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 {
99 unsigned TargetFlags = MO.getTargetFlags();
100
101 switch (TargetFlags) {
103 break;
106 break;
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];
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...
Analysis containing CSE Info
Definition: CSEInfo.cpp:27
This file contains the declarations for the subclasses of Constant, which represent the different fla...
return RetTy
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
Symbol * Sym
Definition: ELF_riscv.cpp:479
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
MCSymbol * getSymbol(const GlobalValue *GV) const
Definition: AsmPrinter.cpp:706
MCSymbol * createTempSymbol(const Twine &Name) const
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
LLVM_ABI wasm::WasmSignature * createWasmSignature()
Allocates and returns a new WasmSignature instance (with empty parameter and return type lists).
Definition: MCContext.cpp:473
Base class for the full range of assembler expressions which are needed for parsing.
Definition: MCExpr.h:34
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.
Definition: MCInstrDesc.h:199
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
void setSignature(wasm::WasmSignature *Sig)
Definition: MCSymbolWasm.h:133
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.
Definition: MachineInstr.h:72
const MachineBasicBlock * getParent() const
Definition: MachineInstr.h:359
MachineOperand class - Representation of each machine instruction operand.
const GlobalValue * getGlobal() const
const ConstantInt * getCImm() const
int64_t getImm() const
bool isImplicit() 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,...
virtual void print(raw_ostream &OS, const Module *M) const
print - Print out the internal state of the pass.
Definition: Pass.cpp:140
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Definition: SmallVector.h:574
void push_back(const T &Elt)
Definition: SmallVector.h:414
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1197
Primary interface to the complete machine description for the target machine.
Definition: TargetMachine.h:83
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
MCSymbol * getOrCreateWasmSymbol(StringRef Name)
MCSymbolWasm * getMCSymbolForFunction(const Function *F, wasm::WasmSignature *Sig, bool &InvokeDetected)
This class is derived from MachineFunctionInfo and contains private WebAssembly-specific information ...
unsigned getWAReg(Register VReg) const
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)
Definition: CommandLine.h:444
@ WASM_SYMBOL_TYPE_FUNCTION
Definition: Wasm.h:220
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
void computeSignatureVTs(const FunctionType *Ty, const Function *TargetFunc, const Function &ContextFunc, const TargetMachine &TM, SmallVectorImpl< MVT > &Params, SmallVectorImpl< MVT > &Results)
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition: Error.cpp:167
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)
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)
Description of the encoding of one expression Op.
SmallVector< ValType, 1 > Returns
Definition: Wasm.h:507