LLVM 23.0.0git
WebAssemblyCallLowering.cpp
Go to the documentation of this file.
1//===-- WebAssemblyCallLowering.cpp - Call lowering for GlobalISel -*- 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
28#include "llvm/IR/DataLayout.h"
29#include "llvm/IR/DebugLoc.h"
30#include "llvm/IR/Value.h"
31
32#define DEBUG_TYPE "wasm-call-lowering"
33
34using namespace llvm;
35
36// Test whether the given calling convention is supported.
38 // We currently support the language-independent target-independent
39 // conventions. We don't yet have a way to annotate calls with properties like
40 // "cold", and we don't have any call-clobbered registers, so these are mostly
41 // all handled the same.
42 return CallConv == CallingConv::C || CallConv == CallingConv::Fast ||
43 CallConv == CallingConv::Cold ||
44 CallConv == CallingConv::PreserveMost ||
45 CallConv == CallingConv::PreserveAll ||
46 CallConv == CallingConv::CXX_FAST_TLS ||
48 CallConv == CallingConv::Swift;
49}
50
54
62
64 const Value *Val,
67 Register SwiftErrorVReg) const {
68 if (!Val)
69 return true; // allow only void returns for now
70
71 return false;
72}
73
74static unsigned getWASMArgumentOpcode(MVT ArgType) {
75 switch (ArgType.SimpleTy) {
76 case MVT::i32:
77 return WebAssembly::ARGUMENT_i32;
78 case MVT::i64:
79 return WebAssembly::ARGUMENT_i64;
80 case MVT::f32:
81 return WebAssembly::ARGUMENT_f32;
82 case MVT::f64:
83 return WebAssembly::ARGUMENT_f64;
84
85 case MVT::funcref:
86 return WebAssembly::ARGUMENT_funcref;
87 case MVT::externref:
88 return WebAssembly::ARGUMENT_externref;
89 case MVT::exnref:
90 return WebAssembly::ARGUMENT_exnref;
91
92 case MVT::v16i8:
93 return WebAssembly::ARGUMENT_v16i8;
94 case MVT::v8i16:
95 return WebAssembly::ARGUMENT_v8i16;
96 case MVT::v4i32:
97 return WebAssembly::ARGUMENT_v4i32;
98 case MVT::v2i64:
99 return WebAssembly::ARGUMENT_v2i64;
100 case MVT::v8f16:
101 return WebAssembly::ARGUMENT_v8f16;
102 case MVT::v4f32:
103 return WebAssembly::ARGUMENT_v4f32;
104 case MVT::v2f64:
105 return WebAssembly::ARGUMENT_v2f64;
106 default:
107 break;
108 }
109 llvm_unreachable("Found unexpected type for WASM argument");
110}
111
113 if (Ty == MVT::externref) {
114 return LLT::pointer(
116 DL.getPointerSizeInBits(
118 }
119
120 if (Ty == MVT::funcref) {
121 return LLT::pointer(
123 DL.getPointerSizeInBits(
125 }
126
127 return llvm::getLLTForMVT(Ty);
128}
129
131 MachineIRBuilder &MIRBuilder, const Function &F,
133 MachineFunction &MF = MIRBuilder.getMF();
136 const DataLayout &DL = F.getDataLayout();
138 const WebAssemblySubtarget &Subtarget =
140 const WebAssemblyRegisterInfo &TRI = *Subtarget.getRegisterInfo();
141 const WebAssemblyInstrInfo &TII = *Subtarget.getInstrInfo();
142 const RegisterBankInfo &RBI = *Subtarget.getRegBankInfo();
143
144 LLVMContext &Ctx = MIRBuilder.getContext();
145 const CallingConv::ID CallConv = F.getCallingConv();
146
147 if (!callingConvSupported(CallConv)) {
148 return false;
149 }
150
151 MF.getRegInfo().addLiveIn(WebAssembly::ARGUMENTS);
152 MF.front().addLiveIn(WebAssembly::ARGUMENTS);
153
154 SmallVector<ArgInfo, 8> SplitArgs;
155
156 if (!FLI.CanLowerReturn) {
157 insertSRetIncomingArgument(F, SplitArgs, FLI.DemoteRegister, MRI, DL);
158 }
159
160 unsigned ArgIdx = 0;
161 bool HasSwiftErrorArg = false;
162 bool HasSwiftSelfArg = false;
163 for (const Argument &Arg : F.args()) {
164 ArgInfo OrigArg{VRegs[ArgIdx], Arg.getType(), ArgIdx};
165 setArgFlags(OrigArg, ArgIdx + AttributeList::FirstArgIndex, DL, F);
166
167 HasSwiftSelfArg |= Arg.hasSwiftSelfAttr();
168 HasSwiftErrorArg |= Arg.hasSwiftErrorAttr();
169 if (Arg.hasInAllocaAttr()) {
170 return false;
171 }
172 if (Arg.hasNestAttr()) {
173 return false;
174 }
175 splitToValueTypes(OrigArg, SplitArgs, DL, F.getCallingConv());
176 ++ArgIdx;
177 }
178
179 unsigned FinalArgIdx = 0;
180 for (ArgInfo &Arg : SplitArgs) {
181 const EVT OrigVT = TLI.getValueType(DL, Arg.Ty);
182 const MVT NewVT = TLI.getRegisterTypeForCallingConv(Ctx, CallConv, OrigVT);
183 const LLT OrigLLT =
184 getLLTForType(*OrigVT.getTypeForEVT(F.getContext()), DL);
185 const LLT NewLLT = getLLTForWasmMVT(NewVT, DL);
186
187 // If we need to split the type over multiple regs, check it's a scenario
188 // we currently support.
189 const unsigned NumParts =
190 TLI.getNumRegistersForCallingConv(Ctx, CallConv, OrigVT);
191
192 const ISD::ArgFlagsTy OrigFlags = Arg.Flags[0];
193 Arg.Flags.clear();
194
195 for (unsigned Part = 0; Part < NumParts; ++Part) {
196 ISD::ArgFlagsTy Flags = OrigFlags;
197 if (Part == 0) {
198 Flags.setSplit();
199 } else {
200 Flags.setOrigAlign(Align(1));
201 if (Part == NumParts - 1)
202 Flags.setSplitEnd();
203 }
204
205 Arg.Flags.push_back(Flags);
206 }
207
208 Arg.OrigRegs.assign(Arg.Regs.begin(), Arg.Regs.end());
209 if (NumParts != 1 || OrigLLT != NewLLT) {
210 // If we can't directly assign the register, we need one or more
211 // intermediate values.
212 Arg.Regs.resize(NumParts);
213
214 // For each split register, create and assign a vreg that will store
215 // the incoming component of the larger value. These will later be
216 // merged to form the final vreg.
217 for (unsigned Part = 0; Part < NumParts; ++Part) {
218 Arg.Regs[Part] = MRI.createGenericVirtualRegister(NewLLT);
219 }
220 }
221
222 for (unsigned Part = 0; Part < NumParts; ++Part) {
223 MachineInstrBuilder ArgInst =
224 MIRBuilder.buildInstr(getWASMArgumentOpcode(NewVT))
225 .addDef(Arg.Regs[Part])
226 .addImm(FinalArgIdx);
227
228 constrainOperandRegClass(MF, TRI, MRI, TII, RBI, *ArgInst,
229 ArgInst->getDesc(), ArgInst->getOperand(0), 0);
230 MFI->addParam(NewVT);
231 ++FinalArgIdx;
232 }
233
234 if (OrigVT != NewVT) {
235 buildCopyFromRegs(MIRBuilder, Arg.OrigRegs, Arg.Regs, OrigLLT, NewLLT,
236 Arg.Flags[0]);
237 }
238 }
239
240 // For swiftcc, emit additional swiftself and swifterror arguments
241 // if there aren't. These additional arguments are also added for callee
242 // signature They are necessary to match callee and caller signature for
243 // indirect call.
244 if (CallConv == CallingConv::Swift) {
245 const MVT PtrVT = TLI.getPointerTy(DL);
246
247 if (!HasSwiftSelfArg) {
248 MFI->addParam(PtrVT);
249 }
250 if (!HasSwiftErrorArg) {
251 MFI->addParam(PtrVT);
252 }
253 }
254
255 // Varargs are copied into a buffer allocated by the caller, and a pointer to
256 // the buffer is passed as an argument.
257 if (F.isVarArg()) {
258 const MVT PtrVT = TLI.getPointerTy(DL, 0);
259 const LLT PtrLLT = LLT::pointer(0, DL.getPointerSizeInBits(0));
260 Register VarargVreg = MF.getRegInfo().createGenericVirtualRegister(PtrLLT);
261
262 MFI->setVarargBufferVreg(VarargVreg);
263
264 MachineInstrBuilder ArgInst =
265 MIRBuilder.buildInstr(getWASMArgumentOpcode(PtrVT))
266 .addDef(VarargVreg)
267 .addImm(FinalArgIdx);
268
269 constrainOperandRegClass(MF, TRI, MRI, TII, RBI, *ArgInst,
270 ArgInst->getDesc(), ArgInst->getOperand(0), 0);
271
272 MFI->addParam(PtrVT);
273 ++FinalArgIdx;
274 }
275
276 // Record the number and types of arguments and results.
277 SmallVector<MVT, 4> Params;
280 MF.getFunction(), MF.getTarget(), Params, Results);
281 for (MVT VT : Results)
282 MFI->addResult(VT);
283
284 // TODO: Use signatures in WebAssemblyMachineFunctionInfo too and unify
285 // the param logic here with ComputeSignatureVTs
286 assert(MFI->getParams().size() == Params.size() &&
287 std::equal(MFI->getParams().begin(), MFI->getParams().end(),
288 Params.begin()));
289 return true;
290}
291
293 CallLoweringInfo &Info) const {
294 return false;
295}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Function Alias Analysis Results
const HexagonInstrInfo * TII
#define F(x, y, z)
Definition MD5.cpp:54
This file declares the MachineIRBuilder class.
Register const TargetRegisterInfo * TRI
static bool callingConvSupported(CallingConv::ID CallConv)
static unsigned getWASMArgumentOpcode(MVT ArgType)
static LLT getLLTForWasmMVT(MVT Ty, const DataLayout &DL)
This file describes how to lower LLVM calls to machine code calls.
This file defines the interfaces that WebAssembly uses to lower LLVM code into a selection DAG.
This file provides WebAssembly-specific target descriptions.
This file declares WebAssembly-specific per-machine-function information.
This file contains the WebAssembly implementation of the WebAssemblyRegisterInfo class.
This file declares the WebAssembly-specific subclass of TargetSubtarget.
This file contains the declaration of the WebAssembly-specific utility functions.
This class represents an incoming formal argument to a Function.
Definition Argument.h:32
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
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.
static void buildCopyFromRegs(MachineIRBuilder &B, ArrayRef< Register > OrigRegs, ArrayRef< Register > Regs, LLT LLTy, LLT PartLLT, const ISD::ArgFlagsTy Flags)
Create a sequence of instructions to combine pieces split into register typed values to the original ...
CallLowering(const TargetLowering *TLI)
const TargetLowering * getTLI() const
Getter for generic TargetLowering class.
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
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.
FunctionType * getFunctionType() const
Returns the FunctionType for me.
Definition Function.h:211
static constexpr LLT pointer(unsigned AddressSpace, unsigned SizeInBits)
Get a low-level pointer in the given address space.
This is an important class for using LLVM in a threaded context.
Definition LLVMContext.h:68
Machine Value Type.
SimpleValueType SimpleTy
void addLiveIn(MCRegister PhysReg, LaneBitmask LaneMask=LaneBitmask::getAll())
Adds the specified register as a live in.
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.
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...
const MachineBasicBlock & front() const
const TargetMachine & getTarget() const
getTarget - Return the target machine this machine code is compiled with
Helper class to build MachineInstr.
LLVMContext & getContext() const
MachineInstrBuilder buildInstr(unsigned Opcode)
Build and insert <empty> = Opcode <empty>.
MachineFunction & getMF()
Getter for the function we currently build.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addDef(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register definition operand.
const MCInstrDesc & getDesc() const
Returns the target instruction descriptor of this MachineInstr.
const MachineOperand & getOperand(unsigned i) const
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.
void addLiveIn(MCRegister Reg, Register vreg=Register())
addLiveIn - Add the specified register as a live-in.
Holds all the information related to register banks.
Wrapper class representing virtual and physical registers.
Definition Register.h:20
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.
LLVM Value Representation.
Definition Value.h:75
bool lowerReturn(MachineIRBuilder &MIRBuilder, const Value *Val, ArrayRef< Register > VRegs, FunctionLoweringInfo &FLI, Register SwiftErrorVReg) const override
This hook must be implemented to lower outgoing return values, described by Val, into the specified v...
WebAssemblyCallLowering(const WebAssemblyTargetLowering &TLI)
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 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 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,...
This class is derived from MachineFunctionInfo and contains private WebAssembly-specific information ...
const std::vector< MVT > & getParams() const
const WebAssemblyInstrInfo * getInstrInfo() const override
const WebAssemblyRegisterInfo * getRegisterInfo() const override
const RegisterBankInfo * getRegBankInfo() const override
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
@ Swift
Calling convention for Swift.
Definition CallingConv.h:69
@ PreserveMost
Used for runtime calls that preserves most registers.
Definition CallingConv.h:63
@ CXX_FAST_TLS
Used for access functions.
Definition CallingConv.h:72
@ WASM_EmscriptenInvoke
For emscripten __invoke_* functions.
@ Cold
Attempts to make code in the caller as efficient as possible under the assumption that the call is no...
Definition CallingConv.h:47
@ PreserveAll
Used for runtime calls that preserves (almost) all registers.
Definition CallingConv.h:66
@ Fast
Attempts to make calls as fast as possible (e.g.
Definition CallingConv.h:41
@ C
The default llvm calling convention, compatible with C.
Definition CallingConv.h:34
bool canLowerReturn(size_t ResultSize, const WebAssemblySubtarget *Subtarget)
Returns true if the function's return value(s) can be lowered directly, i.e., not indirectly via a po...
This is an optimization pass for GlobalISel generic memory operations.
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
void computeSignatureVTs(const FunctionType *Ty, const Function *TargetFunc, const Function &ContextFunc, const TargetMachine &TM, SmallVectorImpl< MVT > &Params, SmallVectorImpl< MVT > &Results)
LLVM_ABI LLT getLLTForMVT(MVT Ty)
Get a rough equivalent of an LLT for a given MVT.
LLVM_ABI LLT getLLTForType(Type &Ty, const DataLayout &DL)
Construct a low-level type based on an LLVM type.
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39
Extended Value Type.
Definition ValueTypes.h:35
LLVM_ABI Type * getTypeForEVT(LLVMContext &Context) const
This method returns an LLVM type corresponding to the specified EVT.