LLVM 22.0.0git
WebAssemblyMCInstLower.cpp
Go to the documentation of this file.
1// WebAssemblyMCInstLower.cpp - Convert WebAssembly MachineInstr to an MCInst //
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 contains code to lower WebAssembly MachineInstrs to their
11/// corresponding MCInst records.
12///
13//===----------------------------------------------------------------------===//
14
24#include "llvm/ADT/APInt.h"
30#include "llvm/IR/Constants.h"
31#include "llvm/MC/MCAsmInfo.h"
32#include "llvm/MC/MCContext.h"
33#include "llvm/MC/MCExpr.h"
34#include "llvm/MC/MCInst.h"
38
39using namespace llvm;
40
41// This disables the removal of registers when lowering into MC, as required
42// by some current tests.
43static cl::opt<bool>
44 WasmKeepRegisters("wasm-keep-registers", cl::Hidden,
45 cl::desc("WebAssembly: output stack registers in"
46 " instruction output for test purposes only."),
47 cl::init(false));
48
49static void removeRegisterOperands(const MachineInstr *MI, MCInst &OutMI);
50
52WebAssemblyMCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const {
53 const GlobalValue *Global = MO.getGlobal();
54 if (!isa<Function>(Global)) {
55 auto *WasmSym = static_cast<MCSymbolWasm *>(Printer.getSymbol(Global));
56 // If the symbol doesn't have an explicit WasmSymbolType yet and the
57 // GlobalValue is actually a WebAssembly global, then ensure the symbol is a
58 // WASM_SYMBOL_TYPE_GLOBAL.
59 if (WebAssembly::isWasmVarAddressSpace(Global->getAddressSpace()) &&
60 !WasmSym->getType()) {
61 const MachineFunction &MF = *MO.getParent()->getParent()->getParent();
62 const TargetMachine &TM = MF.getTarget();
63 const Function &CurrentFunc = MF.getFunction();
64 Type *GlobalVT = Global->getValueType();
66 computeLegalValueVTs(CurrentFunc, TM, GlobalVT, VTs);
67
68 WebAssembly::wasmSymbolSetType(WasmSym, GlobalVT, VTs);
69 }
70 return WasmSym;
71 }
72
73 const auto *FuncTy = cast<FunctionType>(Global->getValueType());
74 const MachineFunction &MF = *MO.getParent()->getParent()->getParent();
75 const TargetMachine &TM = MF.getTarget();
76 const Function &CurrentFunc = MF.getFunction();
77
78 SmallVector<MVT, 1> ResultMVTs;
79 SmallVector<MVT, 4> ParamMVTs;
80 const auto *const F = dyn_cast<Function>(Global);
81 computeSignatureVTs(FuncTy, F, CurrentFunc, TM, ParamMVTs, ResultMVTs);
82 auto Signature = signatureFromMVTs(Ctx, ResultMVTs, ParamMVTs);
83
84 bool InvokeDetected = false;
85 auto *WasmSym = Printer.getMCSymbolForFunction(F, Signature, InvokeDetected);
86 WasmSym->setSignature(Signature);
87 WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
88 return WasmSym;
89}
90
91MCSymbol *WebAssemblyMCInstLower::GetExternalSymbolSymbol(
92 const MachineOperand &MO) const {
93 return Printer.getOrCreateWasmSymbol(MO.getSymbolName());
94}
95
96MCOperand WebAssemblyMCInstLower::lowerSymbolOperand(const MachineOperand &MO,
97 MCSymbol *Sym) const {
98 auto Spec = WebAssembly::S_None;
99 unsigned TargetFlags = MO.getTargetFlags();
100
101 switch (TargetFlags) {
103 break;
106 break;
108 Spec = WebAssembly::S_GOT;
109 break;
112 break;
115 break;
118 break;
119 default:
120 llvm_unreachable("Unknown target flag on GV operand");
121 }
122
123 const MCExpr *Expr = MCSymbolRefExpr::create(Sym, Spec, Ctx);
124
125 if (MO.getOffset() != 0) {
126 const auto *WasmSym = static_cast<const MCSymbolWasm *>(Sym);
127 if (TargetFlags == WebAssemblyII::MO_GOT)
128 report_fatal_error("GOT symbol references do not support offsets");
129 if (WasmSym->isFunction())
130 report_fatal_error("Function addresses with offsets not supported");
131 if (WasmSym->isGlobal())
132 report_fatal_error("Global indexes with offsets not supported");
133 if (WasmSym->isTag())
134 report_fatal_error("Tag indexes with offsets not supported");
135 if (WasmSym->isTable())
136 report_fatal_error("Table indexes with offsets not supported");
137
139 Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
140 }
141
142 return MCOperand::createExpr(Expr);
143}
144
145MCOperand WebAssemblyMCInstLower::lowerTypeIndexOperand(
147 SmallVectorImpl<wasm::ValType> &&Params) const {
148 auto Signature = Ctx.createWasmSignature();
149 Signature->Returns = std::move(Returns);
150 Signature->Params = std::move(Params);
151 auto *Sym =
152 static_cast<MCSymbolWasm *>(Printer.createTempSymbol("typeindex"));
153 Sym->setSignature(Signature);
155 const MCExpr *Expr =
157 return MCOperand::createExpr(Expr);
158}
159
161WebAssemblyMCInstLower::lowerEncodedFunctionSignature(const APInt &Sig) const {
162 // For APInt a word is 64 bits on all architectures, see definition in APInt.h
163 auto NumWords = Sig.getNumWords();
166
167 int Idx = NumWords;
168 auto GetWord = [&Idx, &Sig]() {
169 Idx--;
170 return Sig.extractBitsAsZExtValue(64, 64 * Idx);
171 };
172 // Annoying special case: if getSignificantBits() <= 64 then InstrEmitter will
173 // emit an Imm instead of a CImm. It simplifies WebAssemblyMCInstLower if we
174 // always emit a CImm. So xor NParams with 0x7ffffff to ensure
175 // getSignificantBits() > 64
176 // See encodeFunctionSignature in WebAssemblyISelDAGtoDAG.cpp
177 int NReturns = GetWord() ^ 0x7ffffff;
178 for (int I = 0; I < NReturns; I++) {
179 Returns.push_back(static_cast<wasm::ValType>(GetWord()));
180 }
181 int NParams = GetWord();
182 for (int I = 0; I < NParams; I++) {
183 Params.push_back(static_cast<wasm::ValType>(GetWord()));
184 }
185 return lowerTypeIndexOperand(std::move(Returns), std::move(Params));
186}
187
190 const Function &F = MI->getMF()->getFunction();
191 const TargetMachine &TM = MI->getMF()->getTarget();
192 Type *RetTy = F.getReturnType();
193 SmallVector<MVT, 4> CallerRetTys;
194 computeLegalValueVTs(F, TM, RetTy, CallerRetTys);
195 valTypesFromMVTs(CallerRetTys, Returns);
196}
197
199 MCInst &OutMI) const {
200 OutMI.setOpcode(MI->getOpcode());
201
202 const MCInstrDesc &Desc = MI->getDesc();
203 unsigned NumVariadicDefs = MI->getNumExplicitDefs() - Desc.getNumDefs();
204 const MachineFunction *MF = MI->getMF();
205 const auto &TLI =
206 *MF->getSubtarget<WebAssemblySubtarget>().getTargetLowering();
207 wasm::ValType PtrTy = TLI.getPointerTy(MF->getDataLayout()) == MVT::i32
210
211 for (unsigned I = 0, E = MI->getNumOperands(); I != E; ++I) {
212 const MachineOperand &MO = MI->getOperand(I);
213
214 MCOperand MCOp;
215 switch (MO.getType()) {
216 default:
217 MI->print(errs());
218 llvm_unreachable("unknown operand type");
220 MI->print(errs());
221 llvm_unreachable("MachineBasicBlock operand should have been rewritten");
223 // Ignore all implicit register operands.
224 if (MO.isImplicit())
225 continue;
226 const WebAssemblyFunctionInfo &MFI =
227 *MI->getParent()->getParent()->getInfo<WebAssemblyFunctionInfo>();
228 unsigned WAReg = MFI.getWAReg(MO.getReg());
229 MCOp = MCOperand::createReg(WAReg);
230 break;
231 }
233 // Lower type index placeholder for ref.test
234 // Currently this is the only way that CImmediates show up so panic if we
235 // get confused.
236 unsigned DescIndex = I - NumVariadicDefs;
237 assert(DescIndex < Desc.NumOperands && "unexpected CImmediate operand");
238 auto Operands = Desc.operands();
239 const MCOperandInfo &Info = Operands[DescIndex];
240 assert(Info.OperandType == WebAssembly::OPERAND_TYPEINDEX &&
241 "unexpected CImmediate operand");
242 (void)Info;
243 MCOp = lowerEncodedFunctionSignature(MO.getCImm()->getValue());
244 break;
245 }
247 unsigned DescIndex = I - NumVariadicDefs;
248 if (DescIndex < Desc.NumOperands) {
249 auto Operands = Desc.operands();
250 const MCOperandInfo &Info = Operands[DescIndex];
251 // Replace type index placeholder with actual type index. The type index
252 // placeholders are Immediates and have an operand type of
253 // OPERAND_TYPEINDEX or OPERAND_SIGNATURE.
254 if (Info.OperandType == WebAssembly::OPERAND_TYPEINDEX) {
255 // Lower type index placeholder for a CALL_INDIRECT instruction
258
259 const MachineRegisterInfo &MRI =
260 MI->getParent()->getParent()->getRegInfo();
261 for (const MachineOperand &MO : MI->defs())
263 MRI.getRegClass(MO.getReg())->getID()));
264 for (const MachineOperand &MO : MI->explicit_uses())
265 if (MO.isReg())
267 MRI.getRegClass(MO.getReg())->getID()));
268
269 // call_indirect instructions have a callee operand at the end which
270 // doesn't count as a param.
271 if (WebAssembly::isCallIndirect(MI->getOpcode()))
272 Params.pop_back();
273
274 // return_call_indirect instructions have the return type of the
275 // caller
276 if (MI->getOpcode() == WebAssembly::RET_CALL_INDIRECT)
277 getFunctionReturns(MI, Returns);
278
279 MCOp = lowerTypeIndexOperand(std::move(Returns), std::move(Params));
280 break;
281 }
282 if (Info.OperandType == WebAssembly::OPERAND_SIGNATURE) {
283 // Lower type index placeholder for blocks
284 auto BT = static_cast<WebAssembly::BlockType>(MO.getImm());
288 // Multivalue blocks are emitted in two cases:
289 // 1. When the blocks will never be exited and are at the ends of
290 // functions (see
291 // WebAssemblyCFGStackify::fixEndsAtEndOfFunction). In this case
292 // the exact multivalue signature can always be inferred from the
293 // return type of the parent function.
294 // 2. (catch_ref ...) clause in try_table instruction. Currently all
295 // tags we support (cpp_exception and c_longjmp) throws a single
296 // pointer, so the multivalue signature for this case will be
297 // (ptr, exnref). Having MO_CATCH_BLOCK_SIG target flags means
298 // this is a destination of a catch_ref.
300 Returns = {PtrTy, wasm::ValType::EXNREF};
301 } else
302 getFunctionReturns(MI, Returns);
303 MCOp = lowerTypeIndexOperand(std::move(Returns),
305 break;
306 }
307 }
308 }
309 MCOp = MCOperand::createImm(MO.getImm());
310 break;
311 }
313 const ConstantFP *Imm = MO.getFPImm();
314 const uint64_t BitPattern =
315 Imm->getValueAPF().bitcastToAPInt().getZExtValue();
316 if (Imm->getType()->isFloatTy())
317 MCOp = MCOperand::createSFPImm(static_cast<uint32_t>(BitPattern));
318 else if (Imm->getType()->isDoubleTy())
319 MCOp = MCOperand::createDFPImm(BitPattern);
320 else
321 llvm_unreachable("unknown floating point immediate type");
322 break;
323 }
325 MCOp = lowerSymbolOperand(MO, GetGlobalAddressSymbol(MO));
326 break;
328 MCOp = lowerSymbolOperand(MO, GetExternalSymbolSymbol(MO));
329 break;
331 assert(MO.getTargetFlags() == 0 &&
332 "WebAssembly does not use target flags on MCSymbol");
333 MCOp = lowerSymbolOperand(MO, MO.getMCSymbol());
334 break;
335 }
336
337 OutMI.addOperand(MCOp);
338 }
339
342 else if (Desc.variadicOpsAreDefs())
343 OutMI.insert(OutMI.begin(), MCOperand::createImm(MI->getNumExplicitDefs()));
344}
345
346static void removeRegisterOperands(const MachineInstr *MI, MCInst &OutMI) {
347 // Remove all uses of stackified registers to bring the instruction format
348 // into its final stack form used thruout MC, and transition opcodes to
349 // their _S variant.
350 // We do this separate from the above code that still may need these
351 // registers for e.g. call_indirect signatures.
352 // See comments in lib/Target/WebAssembly/WebAssemblyInstrFormats.td for
353 // details.
354 // TODO: the code above creates new registers which are then removed here.
355 // That code could be slightly simplified by not doing that, though maybe
356 // it is simpler conceptually to keep the code above in "register mode"
357 // until this transition point.
358 // FIXME: we are not processing inline assembly, which contains register
359 // operands, because it is used by later target generic code.
360 if (MI->isDebugInstr() || MI->isLabel() || MI->isInlineAsm())
361 return;
362
363 // Transform to _S instruction.
364 auto RegOpcode = OutMI.getOpcode();
365 auto StackOpcode = WebAssembly::getStackOpcode(RegOpcode);
366 assert(StackOpcode != -1 && "Failed to stackify instruction");
367 OutMI.setOpcode(StackOpcode);
368
369 // Remove register operands.
370 for (auto I = OutMI.getNumOperands(); I; --I) {
371 auto &MO = OutMI.getOperand(I - 1);
372 if (MO.isReg()) {
373 OutMI.erase(&MO);
374 }
375 }
376}
unsigned const MachineRegisterInfo * MRI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file implements a class to represent arbitrary precision integral constant values and operations...
BitTracker BT
This file contains the declarations for the subclasses of Constant, which represent the different fla...
dxil pretty DXIL Metadata Pretty Printer
IRTranslator LLVM IR MI
#define F(x, y, z)
Definition MD5.cpp:55
#define I(x, y, z)
Definition MD5.cpp:58
mir Rename Register Operands
This file defines the SmallVector class.
cl::opt< bool > WasmKeepRegisters
This file contains the declaration of the WebAssemblyMCAsmInfo class.
static void removeRegisterOperands(const MachineInstr *MI, MCInst &OutMI)
static cl::opt< bool > WasmKeepRegisters("wasm-keep-registers", cl::Hidden, cl::desc("WebAssembly: output stack registers in" " instruction output for test purposes only."), cl::init(false))
static void getFunctionReturns(const MachineInstr *MI, SmallVectorImpl< wasm::ValType > &Returns)
This file declares the class to lower WebAssembly MachineInstrs to their corresponding MCInst records...
This file provides WebAssembly-specific target descriptions.
This file contains the declaration of the WebAssembly-specific type parsing utility functions.
This file declares WebAssembly-specific per-machine-function information.
This file registers the WebAssembly target.
This file contains the declaration of the WebAssembly-specific type parsing utility functions.
This file contains the declaration of the WebAssembly-specific utility functions.
Class for arbitrary precision integers.
Definition APInt.h:78
LLVM_ABI uint64_t extractBitsAsZExtValue(unsigned numBits, unsigned bitPosition) const
Definition APInt.cpp:520
unsigned getNumWords() const
Get the number of words.
Definition APInt.h:1495
ConstantFP - Floating Point Values [float, double].
Definition Constants.h:277
const APInt & getValue() const
Return the constant as an APInt value reference.
Definition Constants.h:154
static const MCBinaryExpr * createAdd(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx, SMLoc Loc=SMLoc())
Definition MCExpr.h:343
static LLVM_ABI const MCConstantExpr * create(int64_t Value, MCContext &Ctx, bool PrintInHex=false, unsigned SizeInBytes=0)
Definition MCExpr.cpp:212
Instances of this class represent a single low-level machine instruction.
Definition MCInst.h:188
void erase(iterator I)
Definition MCInst.h:224
unsigned getNumOperands() const
Definition MCInst.h:212
unsigned getOpcode() const
Definition MCInst.h:202
iterator insert(iterator I, const MCOperand &Op)
Definition MCInst.h:232
void addOperand(const MCOperand Op)
Definition MCInst.h:215
iterator begin()
Definition MCInst.h:227
void setOpcode(unsigned Op)
Definition MCInst.h:201
const MCOperand & getOperand(unsigned i) const
Definition MCInst.h:210
Describe properties that are true of each instruction in the target description file.
This holds information about one operand of a machine instruction, indicating the register class for ...
Definition MCInstrDesc.h:86
Instances of this class represent operands of the MCInst class.
Definition MCInst.h:40
static MCOperand createExpr(const MCExpr *Val)
Definition MCInst.h:166
static MCOperand createSFPImm(uint32_t Val)
Definition MCInst.h:152
static MCOperand createReg(MCRegister Reg)
Definition MCInst.h:138
static MCOperand createImm(int64_t Val)
Definition MCInst.h:145
static MCOperand createDFPImm(uint64_t Val)
Definition MCInst.h:159
static const MCSymbolRefExpr * create(const MCSymbol *Symbol, MCContext &Ctx, SMLoc Loc=SMLoc())
Definition MCExpr.h:214
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
Definition MCSymbol.h:42
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
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.
const TargetMachine & getTarget() const
getTarget - Return the target machine this machine code is compiled with
Representation of each machine instruction.
const MachineBasicBlock * getParent() const
MachineOperand class - Representation of each machine instruction operand.
const GlobalValue * getGlobal() const
const ConstantInt * getCImm() const
int64_t getImm() const
bool isReg() const
isReg - Tests if this is a MO_Register operand.
MachineInstr * getParent()
getParent - Return the instruction that this operand belongs to.
unsigned getTargetFlags() const
MachineOperandType getType() const
getType - Returns the MachineOperandType for this operand.
const char * getSymbolName() const
Register getReg() const
getReg - Returns the register number.
const ConstantFP * getFPImm() const
MCSymbol * getMCSymbol() const
@ MO_Immediate
Immediate operand.
@ MO_MCSymbol
MCSymbol reference (for debug/eh info)
@ MO_GlobalAddress
Address of a global value.
@ MO_CImmediate
Immediate >64bit operand.
@ MO_MachineBasicBlock
MachineBasicBlock reference.
@ MO_Register
Register operand.
@ MO_ExternalSymbol
Name of external global symbol.
@ MO_FPImmediate
Floating-point immediate operand.
int64_t getOffset() const
Return the offset from the symbol in this operand.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Primary interface to the complete machine description for the target machine.
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:45
This class is derived from MachineFunctionInfo and contains private WebAssembly-specific information ...
void lower(const MachineInstr *MI, MCInst &OutMI) const
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
bool isCallIndirect(unsigned Opc)
wasm::ValType regClassToValType(unsigned RC)
void wasmSymbolSetType(MCSymbolWasm *Sym, const Type *GlobalVT, ArrayRef< MVT > VTs)
Sets a Wasm Symbol Type.
BlockType
Used as immediate MachineOperands for block signatures.
@ OPERAND_TYPEINDEX
type signature immediate for call_indirect.
@ OPERAND_SIGNATURE
signature immediate for block/loop.
int getStackOpcode(unsigned short Opcode)
bool isWasmVarAddressSpace(unsigned AS)
initializer< Ty > init(const Ty &Val)
@ WASM_SYMBOL_TYPE_FUNCTION
Definition Wasm.h:220
This is an optimization pass for GlobalISel generic memory operations.
void computeSignatureVTs(const FunctionType *Ty, const Function *TargetFunc, const Function &ContextFunc, const TargetMachine &TM, SmallVectorImpl< MVT > &Params, SmallVectorImpl< MVT > &Results)
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:649
Op::Description Desc
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:167
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:548
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
@ Global
Append to llvm.global_dtors.
void valTypesFromMVTs(ArrayRef< MVT > In, SmallVectorImpl< wasm::ValType > &Out)
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:565
wasm::WasmSignature * signatureFromMVTs(MCContext &Ctx, const SmallVectorImpl< MVT > &Results, const SmallVectorImpl< MVT > &Params)
void computeLegalValueVTs(const WebAssemblyTargetLowering &TLI, LLVMContext &Ctx, const DataLayout &DL, Type *Ty, SmallVectorImpl< MVT > &ValueVTs)