LLVM 18.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 "RISCVISelLowering.h"
17#include "RISCVSubtarget.h"
20
21using namespace llvm;
22
23namespace {
24
25struct RISCVOutgoingValueAssigner : public CallLowering::OutgoingValueAssigner {
26private:
27 // The function used internally to assign args - we ignore the AssignFn stored
28 // by OutgoingValueAssigner since RISC-V implements its CC using a custom
29 // function with a different signature.
31
32 // Whether this is assigning args for a return.
33 bool IsRet;
34
35public:
36 RISCVOutgoingValueAssigner(
37 RISCVTargetLowering::RISCVCCAssignFn *RISCVAssignFn_, bool IsRet)
38 : CallLowering::OutgoingValueAssigner(nullptr),
39 RISCVAssignFn(RISCVAssignFn_), IsRet(IsRet) {}
40
41 bool assignArg(unsigned ValNo, EVT OrigVT, MVT ValVT, MVT LocVT,
43 const CallLowering::ArgInfo &Info, ISD::ArgFlagsTy Flags,
44 CCState &State) override {
46 const DataLayout &DL = MF.getDataLayout();
47 const RISCVSubtarget &Subtarget = MF.getSubtarget<RISCVSubtarget>();
48
49 return RISCVAssignFn(DL, Subtarget.getTargetABI(), ValNo, ValVT, LocVT,
50 LocInfo, Flags, State, /*IsFixed=*/true, IsRet,
51 Info.Ty, *Subtarget.getTargetLowering(),
52 /*FirstMaskArgument=*/std::nullopt);
53 }
54};
55
56struct RISCVOutgoingValueHandler : public CallLowering::OutgoingValueHandler {
57 RISCVOutgoingValueHandler(MachineIRBuilder &B, MachineRegisterInfo &MRI,
59 : OutgoingValueHandler(B, MRI), MIB(MIB) {}
60
62
63 Register getStackAddress(uint64_t MemSize, int64_t Offset,
65 ISD::ArgFlagsTy Flags) override {
66 llvm_unreachable("not implemented");
67 }
68
69 void assignValueToAddress(Register ValVReg, Register Addr, LLT MemTy,
70 MachinePointerInfo &MPO, CCValAssign &VA) override {
71 llvm_unreachable("not implemented");
72 }
73
74 void assignValueToReg(Register ValVReg, Register PhysReg,
75 CCValAssign VA) override {
76 Register ExtReg = extendRegister(ValVReg, VA);
77 MIRBuilder.buildCopy(PhysReg, ExtReg);
78 MIB.addUse(PhysReg, RegState::Implicit);
79 }
80};
81
82struct RISCVIncomingValueAssigner : public CallLowering::IncomingValueAssigner {
83private:
84 // The function used internally to assign args - we ignore the AssignFn stored
85 // by IncomingValueAssigner since RISC-V implements its CC using a custom
86 // function with a different signature.
88
89 // Whether this is assigning args from a return.
90 bool IsRet;
91
92public:
93 RISCVIncomingValueAssigner(
94 RISCVTargetLowering::RISCVCCAssignFn *RISCVAssignFn_, bool IsRet)
95 : CallLowering::IncomingValueAssigner(nullptr),
96 RISCVAssignFn(RISCVAssignFn_), IsRet(IsRet) {}
97
98 bool assignArg(unsigned ValNo, EVT OrigVT, MVT ValVT, MVT LocVT,
100 const CallLowering::ArgInfo &Info, ISD::ArgFlagsTy Flags,
101 CCState &State) override {
103 const DataLayout &DL = MF.getDataLayout();
104 const RISCVSubtarget &Subtarget = MF.getSubtarget<RISCVSubtarget>();
105
106 return RISCVAssignFn(DL, Subtarget.getTargetABI(), ValNo, ValVT, LocVT,
107 LocInfo, Flags, State, /*IsFixed=*/true, IsRet,
108 Info.Ty, *Subtarget.getTargetLowering(),
109 /*FirstMaskArgument=*/std::nullopt);
110 }
111};
112
113struct RISCVIncomingValueHandler : public CallLowering::IncomingValueHandler {
114 RISCVIncomingValueHandler(MachineIRBuilder &B, MachineRegisterInfo &MRI)
115 : IncomingValueHandler(B, MRI) {}
116
117 Register getStackAddress(uint64_t MemSize, int64_t Offset,
119 ISD::ArgFlagsTy Flags) override {
120 llvm_unreachable("not implemented");
121 }
122
123 void assignValueToAddress(Register ValVReg, Register Addr, LLT MemTy,
124 MachinePointerInfo &MPO, CCValAssign &VA) override {
125 llvm_unreachable("not implemented");
126 }
127
128 void assignValueToReg(Register ValVReg, Register PhysReg,
129 CCValAssign VA) override {
130 // Copy argument received in physical register to desired VReg.
131 MIRBuilder.getMBB().addLiveIn(PhysReg);
132 MIRBuilder.buildCopy(ValVReg, PhysReg);
133 }
134};
135
136struct RISCVCallReturnHandler : public RISCVIncomingValueHandler {
137 RISCVCallReturnHandler(MachineIRBuilder &B, MachineRegisterInfo &MRI,
139 : RISCVIncomingValueHandler(B, MRI), MIB(MIB) {}
140
142
143 void assignValueToReg(Register ValVReg, Register PhysReg,
144 CCValAssign VA) override {
145 // Copy argument received in physical register to desired VReg.
146 MIB.addDef(PhysReg, RegState::Implicit);
147 MIRBuilder.buildCopy(ValVReg, PhysReg);
148 }
149};
150
151} // namespace
152
154 : CallLowering(&TLI) {}
155
156bool RISCVCallLowering::lowerReturnVal(MachineIRBuilder &MIRBuilder,
157 const Value *Val,
158 ArrayRef<Register> VRegs,
159 MachineInstrBuilder &Ret) const {
160 if (!Val)
161 return true;
162
163 // TODO: Only integer, pointer and aggregate types are supported now.
164 if (!Val->getType()->isIntOrPtrTy() && !Val->getType()->isAggregateType())
165 return false;
166
167 MachineFunction &MF = MIRBuilder.getMF();
168 const DataLayout &DL = MF.getDataLayout();
169 const Function &F = MF.getFunction();
170 CallingConv::ID CC = F.getCallingConv();
171
172 ArgInfo OrigRetInfo(VRegs, Val->getType(), 0);
174
175 SmallVector<ArgInfo, 4> SplitRetInfos;
176 splitToValueTypes(OrigRetInfo, SplitRetInfos, DL, CC);
177
178 RISCVOutgoingValueAssigner Assigner(
180 /*IsRet=*/true);
181 RISCVOutgoingValueHandler Handler(MIRBuilder, MF.getRegInfo(), Ret);
182 return determineAndHandleAssignments(Handler, Assigner, SplitRetInfos,
183 MIRBuilder, CC, F.isVarArg());
184}
185
187 const Value *Val, ArrayRef<Register> VRegs,
188 FunctionLoweringInfo &FLI) const {
189 assert(!Val == VRegs.empty() && "Return value without a vreg");
190 MachineInstrBuilder Ret = MIRBuilder.buildInstrNoInsert(RISCV::PseudoRET);
191
192 if (!lowerReturnVal(MIRBuilder, Val, VRegs, Ret))
193 return false;
194
195 MIRBuilder.insertInstr(Ret);
196 return true;
197}
198
200 const Function &F,
202 FunctionLoweringInfo &FLI) const {
203 // Early exit if there are no arguments.
204 if (F.arg_empty())
205 return true;
206
207 // TODO: Support vararg functions.
208 if (F.isVarArg())
209 return false;
210
211 // TODO: Support all argument types.
212 for (auto &Arg : F.args()) {
213 if (Arg.getType()->isIntegerTy())
214 continue;
215 if (Arg.getType()->isPointerTy())
216 continue;
217 return false;
218 }
219
220 MachineFunction &MF = MIRBuilder.getMF();
221 const DataLayout &DL = MF.getDataLayout();
222 CallingConv::ID CC = F.getCallingConv();
223
224 SmallVector<ArgInfo, 32> SplitArgInfos;
225 unsigned Index = 0;
226 for (auto &Arg : F.args()) {
227 // Construct the ArgInfo object from destination register and argument type.
228 ArgInfo AInfo(VRegs[Index], Arg.getType(), Index);
230
231 // Handle any required merging from split value types from physical
232 // registers into the desired VReg. ArgInfo objects are constructed
233 // correspondingly and appended to SplitArgInfos.
234 splitToValueTypes(AInfo, SplitArgInfos, DL, CC);
235
236 ++Index;
237 }
238
239 RISCVIncomingValueAssigner Assigner(
241 /*IsRet=*/false);
242 RISCVIncomingValueHandler Handler(MIRBuilder, MF.getRegInfo());
243
244 return determineAndHandleAssignments(Handler, Assigner, SplitArgInfos,
245 MIRBuilder, CC, F.isVarArg());
246}
247
249 CallLoweringInfo &Info) const {
250 MachineFunction &MF = MIRBuilder.getMF();
251 const DataLayout &DL = MF.getDataLayout();
252 const Function &F = MF.getFunction();
253 CallingConv::ID CC = F.getCallingConv();
254
255 // TODO: Support vararg functions.
256 if (Info.IsVarArg)
257 return false;
258
259 // TODO: Support all argument types.
260 for (auto &AInfo : Info.OrigArgs) {
261 if (AInfo.Ty->isIntegerTy())
262 continue;
263 if (AInfo.Ty->isPointerTy())
264 continue;
265 if (AInfo.Ty->isFloatingPointTy())
266 continue;
267 return false;
268 }
269
270 SmallVector<ArgInfo, 32> SplitArgInfos;
272 for (auto &AInfo : Info.OrigArgs) {
273 // Handle any required unmerging of split value types from a given VReg into
274 // physical registers. ArgInfo objects are constructed correspondingly and
275 // appended to SplitArgInfos.
276 splitToValueTypes(AInfo, SplitArgInfos, DL, CC);
277 }
278
279 // TODO: Support tail calls.
280 Info.IsTailCall = false;
281
282 if (!Info.Callee.isReg())
283 Info.Callee.setTargetFlags(RISCVII::MO_CALL);
284
286 MIRBuilder
287 .buildInstrNoInsert(Info.Callee.isReg() ? RISCV::PseudoCALLIndirect
288 : RISCV::PseudoCALL)
289 .add(Info.Callee);
290
291 RISCVOutgoingValueAssigner ArgAssigner(
293 /*IsRet=*/false);
294 RISCVOutgoingValueHandler ArgHandler(MIRBuilder, MF.getRegInfo(), Call);
295 if (!determineAndHandleAssignments(ArgHandler, ArgAssigner, SplitArgInfos,
296 MIRBuilder, CC, Info.IsVarArg))
297 return false;
298
299 MIRBuilder.insertInstr(Call);
300
301 if (Info.OrigRet.Ty->isVoidTy())
302 return true;
303
304 // TODO: Only integer, pointer and aggregate types are supported now.
305 if (!Info.OrigRet.Ty->isIntOrPtrTy() && !Info.OrigRet.Ty->isAggregateType())
306 return false;
307
308 SmallVector<ArgInfo, 4> SplitRetInfos;
309 splitToValueTypes(Info.OrigRet, SplitRetInfos, DL, CC);
310
311 // Assignments should be handled *before* the merging of values takes place.
312 // To ensure this, the insert point is temporarily adjusted to just after the
313 // call instruction.
314 MachineBasicBlock::iterator CallInsertPt = Call;
315 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), std::next(CallInsertPt));
316
317 RISCVIncomingValueAssigner RetAssigner(
319 /*IsRet=*/true);
320 RISCVCallReturnHandler RetHandler(MIRBuilder, MF.getRegInfo(), Call);
321 if (!determineAndHandleAssignments(RetHandler, RetAssigner, SplitRetInfos,
322 MIRBuilder, CC, Info.IsVarArg))
323 return false;
324
325 // Readjust insert point to end of basic block.
326 MIRBuilder.setMBB(MIRBuilder.getMBB());
327
328 return true;
329}
unsigned const MachineRegisterInfo * MRI
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
Analysis containing CSE Info
Definition: CSEInfo.cpp:27
uint64_t Addr
#define F(x, y, z)
Definition: MD5.cpp:55
This file declares the MachineIRBuilder class.
This file describes how to lower LLVM calls to machine code calls.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: ArrayRef.h:41
bool empty() const
empty - Check if the array is empty.
Definition: ArrayRef.h:160
CCState - This class holds information needed while lowering arguments and return values.
MachineFunction & getMachineFunction() const
CCValAssign - Represent assignment of one arg/retval to a location.
bool determineAndHandleAssignments(ValueHandler &Handler, ValueAssigner &Assigner, SmallVectorImpl< ArgInfo > &Args, MachineIRBuilder &MIRBuilder, CallingConv::ID CallConv, bool IsVarArg, ArrayRef< Register > ThisReturnRegs=std::nullopt) const
Invoke ValueAssigner::assignArg on each of the given Args and then use Handler to move them to the as...
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 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:110
FunctionLoweringInfo - This contains information that is global to a function that is used when lower...
Machine Value Type.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
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.
Helper class to build MachineInstr.
MachineInstrBuilder insertInstr(MachineInstrBuilder MIB)
Insert an existing instruction at the insertion point.
void setInsertPt(MachineBasicBlock &MBB, MachineBasicBlock::iterator II)
Set the insertion point before the specified position.
MachineFunction & getMF()
Getter for the function we currently build.
const MachineBasicBlock & getMBB() const
Getter for the basic block we currently build.
void setMBB(MachineBasicBlock &MBB)
Set the insertion point to the end of MBB.
MachineInstrBuilder buildInstrNoInsert(unsigned Opcode)
Build but don't insert <empty> = Opcode <empty>.
const MachineInstrBuilder & add(const MachineOperand &MO) const
const MachineInstrBuilder & addUse(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register use operand.
const MachineInstrBuilder & addDef(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register definition operand.
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 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)
RISCVABI::ABI getTargetABI() const
const RISCVTargetLowering * getTargetLowering() const override
bool RISCVCCAssignFn(const DataLayout &DL, RISCVABI::ABI, unsigned ValNo, MVT ValVT, MVT LocVT, CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, CCState &State, bool IsFixed, bool IsRet, Type *OrigTy, const RISCVTargetLowering &TLI, std::optional< unsigned > FirstMaskArgument)
RISCVCCAssignFn - This target-specific function extends the default CCValAssign with additional infor...
Wrapper class representing virtual and physical registers.
Definition: Register.h:19
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1200
bool isAggregateType() const
Return true if the type is an aggregate type.
Definition: Type.h:295
bool isIntOrPtrTy() const
Return true if this is an integer type or a pointer type.
Definition: Type.h:243
LLVM Value Representation.
Definition: Value.h:74
Type * getType() const
All values are typed, get the type of this value.
Definition: Value.h:255
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ Fast
Attempts to make calls as fast as possible (e.g.
Definition: CallingConv.h:41
bool CC_RISCV(const DataLayout &DL, RISCVABI::ABI ABI, unsigned ValNo, MVT ValVT, MVT LocVT, CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, CCState &State, bool IsFixed, bool IsRet, Type *OrigTy, const RISCVTargetLowering &TLI, std::optional< unsigned > FirstMaskArgument)
bool CC_RISCV_FastCC(const DataLayout &DL, RISCVABI::ABI ABI, unsigned ValNo, MVT ValVT, MVT LocVT, CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, CCState &State, bool IsFixed, bool IsRet, Type *OrigTy, const RISCVTargetLowering &TLI, std::optional< unsigned > FirstMaskArgument)
@ Implicit
Not emitted register (e.g. carry, or temporary result).
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
@ Offset
Definition: DWP.cpp:440
Helper struct shared between Function Specialization and SCCP Solver.
Definition: SCCPSolver.h:41
Base class for ValueHandlers used for arguments coming into the current function, or for return value...
Definition: CallLowering.h:320
void assignValueToReg(Register ValVReg, Register PhysReg, 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.
Definition: CallLowering.h:335
virtual bool assignArg(unsigned ValNo, EVT OrigVT, MVT ValVT, MVT LocVT, CCValAssign::LocInfo LocInfo, const ArgInfo &Info, ISD::ArgFlagsTy Flags, CCState &State)
Wrap call to (typically tablegenerated CCAssignFn).
Definition: CallLowering.h:188
Register extendRegister(Register ValReg, CCValAssign &VA, unsigned MaxSizeBits=0)
Extend a register to the location type given in VA, capped at extending to at most MaxSize bits.
virtual Register getStackAddress(uint64_t MemSize, int64_t Offset, MachinePointerInfo &MPO, ISD::ArgFlagsTy Flags)=0
Materialize a VReg containing the address of the specified stack-based object.
virtual void assignValueToAddress(Register ValVReg, Register Addr, LLT MemTy, MachinePointerInfo &MPO, CCValAssign &VA)=0
The specified value has been assigned to a stack location.
virtual void assignValueToReg(Register ValVReg, Register PhysReg, CCValAssign VA)=0
The specified value has been assigned to a physical register, handle the appropriate COPY (either to ...
Extended Value Type.
Definition: ValueTypes.h:34
This class contains a discriminated union of information about pointers in memory operands,...