LLVM 20.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/IR/Constants.h"
25#include "llvm/MC/MCAsmInfo.h"
26#include "llvm/MC/MCContext.h"
27#include "llvm/MC/MCExpr.h"
28#include "llvm/MC/MCInst.h"
32
33using namespace llvm;
34
35// This disables the removal of registers when lowering into MC, as required
36// by some current tests.
38 WasmKeepRegisters("wasm-keep-registers", cl::Hidden,
39 cl::desc("WebAssembly: output stack registers in"
40 " instruction output for test purposes only."),
41 cl::init(false));
42
43static void removeRegisterOperands(const MachineInstr *MI, MCInst &OutMI);
44
46WebAssemblyMCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const {
47 const GlobalValue *Global = MO.getGlobal();
48 if (!isa<Function>(Global)) {
49 auto *WasmSym = cast<MCSymbolWasm>(Printer.getSymbol(Global));
50 // If the symbol doesn't have an explicit WasmSymbolType yet and the
51 // GlobalValue is actually a WebAssembly global, then ensure the symbol is a
52 // WASM_SYMBOL_TYPE_GLOBAL.
53 if (WebAssembly::isWasmVarAddressSpace(Global->getAddressSpace()) &&
54 !WasmSym->getType()) {
55 const MachineFunction &MF = *MO.getParent()->getParent()->getParent();
56 const TargetMachine &TM = MF.getTarget();
57 const Function &CurrentFunc = MF.getFunction();
58 Type *GlobalVT = Global->getValueType();
60 computeLegalValueVTs(CurrentFunc, TM, GlobalVT, VTs);
61
62 WebAssembly::wasmSymbolSetType(WasmSym, GlobalVT, VTs);
63 }
64 return WasmSym;
65 }
66
67 const auto *FuncTy = cast<FunctionType>(Global->getValueType());
68 const MachineFunction &MF = *MO.getParent()->getParent()->getParent();
69 const TargetMachine &TM = MF.getTarget();
70 const Function &CurrentFunc = MF.getFunction();
71
72 SmallVector<MVT, 1> ResultMVTs;
73 SmallVector<MVT, 4> ParamMVTs;
74 const auto *const F = dyn_cast<Function>(Global);
75 computeSignatureVTs(FuncTy, F, CurrentFunc, TM, ParamMVTs, ResultMVTs);
76 auto Signature = signatureFromMVTs(Ctx, ResultMVTs, ParamMVTs);
77
78 bool InvokeDetected = false;
79 auto *WasmSym = Printer.getMCSymbolForFunction(
81 Signature, InvokeDetected);
82 WasmSym->setSignature(Signature);
83 WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
84 return WasmSym;
85}
86
87MCSymbol *WebAssemblyMCInstLower::GetExternalSymbolSymbol(
88 const MachineOperand &MO) const {
89 return Printer.getOrCreateWasmSymbol(MO.getSymbolName());
90}
91
92MCOperand WebAssemblyMCInstLower::lowerSymbolOperand(const MachineOperand &MO,
93 MCSymbol *Sym) const {
95 unsigned TargetFlags = MO.getTargetFlags();
96
97 switch (TargetFlags) {
99 break;
102 break;
105 break;
108 break;
111 break;
114 break;
115 default:
116 llvm_unreachable("Unknown target flag on GV operand");
117 }
118
119 const MCExpr *Expr = MCSymbolRefExpr::create(Sym, Kind, Ctx);
120
121 if (MO.getOffset() != 0) {
122 const auto *WasmSym = cast<MCSymbolWasm>(Sym);
123 if (TargetFlags == WebAssemblyII::MO_GOT)
124 report_fatal_error("GOT symbol references do not support offsets");
125 if (WasmSym->isFunction())
126 report_fatal_error("Function addresses with offsets not supported");
127 if (WasmSym->isGlobal())
128 report_fatal_error("Global indexes with offsets not supported");
129 if (WasmSym->isTag())
130 report_fatal_error("Tag indexes with offsets not supported");
131 if (WasmSym->isTable())
132 report_fatal_error("Table indexes with offsets not supported");
133
135 Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
136 }
137
138 return MCOperand::createExpr(Expr);
139}
140
141MCOperand WebAssemblyMCInstLower::lowerTypeIndexOperand(
143 SmallVectorImpl<wasm::ValType> &&Params) const {
144 auto Signature = Ctx.createWasmSignature();
145 Signature->Returns = std::move(Returns);
146 Signature->Params = std::move(Params);
147 MCSymbol *Sym = Printer.createTempSymbol("typeindex");
148 auto *WasmSym = cast<MCSymbolWasm>(Sym);
149 WasmSym->setSignature(Signature);
150 WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
151 const MCExpr *Expr =
153 return MCOperand::createExpr(Expr);
154}
155
158 const Function &F = MI->getMF()->getFunction();
159 const TargetMachine &TM = MI->getMF()->getTarget();
160 Type *RetTy = F.getReturnType();
161 SmallVector<MVT, 4> CallerRetTys;
162 computeLegalValueVTs(F, TM, RetTy, CallerRetTys);
163 valTypesFromMVTs(CallerRetTys, Returns);
164}
165
167 MCInst &OutMI) const {
168 OutMI.setOpcode(MI->getOpcode());
169
170 const MCInstrDesc &Desc = MI->getDesc();
171 unsigned NumVariadicDefs = MI->getNumExplicitDefs() - Desc.getNumDefs();
172 for (unsigned I = 0, E = MI->getNumOperands(); I != E; ++I) {
173 const MachineOperand &MO = MI->getOperand(I);
174
175 MCOperand MCOp;
176 switch (MO.getType()) {
177 default:
178 MI->print(errs());
179 llvm_unreachable("unknown operand type");
181 MI->print(errs());
182 llvm_unreachable("MachineBasicBlock operand should have been rewritten");
184 // Ignore all implicit register operands.
185 if (MO.isImplicit())
186 continue;
187 const WebAssemblyFunctionInfo &MFI =
188 *MI->getParent()->getParent()->getInfo<WebAssemblyFunctionInfo>();
189 unsigned WAReg = MFI.getWAReg(MO.getReg());
190 MCOp = MCOperand::createReg(WAReg);
191 break;
192 }
194 unsigned DescIndex = I - NumVariadicDefs;
195 if (DescIndex < Desc.NumOperands) {
196 const MCOperandInfo &Info = Desc.operands()[DescIndex];
197 if (Info.OperandType == WebAssembly::OPERAND_TYPEINDEX) {
200
201 const MachineRegisterInfo &MRI =
202 MI->getParent()->getParent()->getRegInfo();
203 for (const MachineOperand &MO : MI->defs())
205 MRI.getRegClass(MO.getReg())->getID()));
206 for (const MachineOperand &MO : MI->explicit_uses())
207 if (MO.isReg())
209 MRI.getRegClass(MO.getReg())->getID()));
210
211 // call_indirect instructions have a callee operand at the end which
212 // doesn't count as a param.
213 if (WebAssembly::isCallIndirect(MI->getOpcode()))
214 Params.pop_back();
215
216 // return_call_indirect instructions have the return type of the
217 // caller
218 if (MI->getOpcode() == WebAssembly::RET_CALL_INDIRECT)
219 getFunctionReturns(MI, Returns);
220
221 MCOp = lowerTypeIndexOperand(std::move(Returns), std::move(Params));
222 break;
223 }
224 if (Info.OperandType == WebAssembly::OPERAND_SIGNATURE) {
225 auto BT = static_cast<WebAssembly::BlockType>(MO.getImm());
229 // Multivalue blocks are emitted in two cases:
230 // 1. When the blocks will never be exited and are at the ends of
231 // functions (see
232 // WebAssemblyCFGStackify::fixEndsAtEndOfFunction). In this case
233 // the exact multivalue signature can always be inferred from the
234 // return type of the parent function.
235 // 2. (catch_ref ...) clause in try_table instruction. Currently all
236 // tags we support (cpp_exception and c_longjmp) throws a single
237 // i32, so the multivalue signature for this case will be (i32,
238 // exnref). Having MO_CATCH_BLOCK_SIG target flags means this is
239 // a destination of a catch_ref.
242 else
243 getFunctionReturns(MI, Returns);
244 MCOp = lowerTypeIndexOperand(std::move(Returns),
246 break;
247 }
248 }
249 }
250 MCOp = MCOperand::createImm(MO.getImm());
251 break;
252 }
254 const ConstantFP *Imm = MO.getFPImm();
255 const uint64_t BitPattern =
256 Imm->getValueAPF().bitcastToAPInt().getZExtValue();
257 if (Imm->getType()->isFloatTy())
258 MCOp = MCOperand::createSFPImm(static_cast<uint32_t>(BitPattern));
259 else if (Imm->getType()->isDoubleTy())
260 MCOp = MCOperand::createDFPImm(BitPattern);
261 else
262 llvm_unreachable("unknown floating point immediate type");
263 break;
264 }
266 MCOp = lowerSymbolOperand(MO, GetGlobalAddressSymbol(MO));
267 break;
269 MCOp = lowerSymbolOperand(MO, GetExternalSymbolSymbol(MO));
270 break;
272 assert(MO.getTargetFlags() == 0 &&
273 "WebAssembly does not use target flags on MCSymbol");
274 MCOp = lowerSymbolOperand(MO, MO.getMCSymbol());
275 break;
276 }
277
278 OutMI.addOperand(MCOp);
279 }
280
283 else if (Desc.variadicOpsAreDefs())
284 OutMI.insert(OutMI.begin(), MCOperand::createImm(MI->getNumExplicitDefs()));
285}
286
287static void removeRegisterOperands(const MachineInstr *MI, MCInst &OutMI) {
288 // Remove all uses of stackified registers to bring the instruction format
289 // into its final stack form used thruout MC, and transition opcodes to
290 // their _S variant.
291 // We do this separate from the above code that still may need these
292 // registers for e.g. call_indirect signatures.
293 // See comments in lib/Target/WebAssembly/WebAssemblyInstrFormats.td for
294 // details.
295 // TODO: the code above creates new registers which are then removed here.
296 // That code could be slightly simplified by not doing that, though maybe
297 // it is simpler conceptually to keep the code above in "register mode"
298 // until this transition point.
299 // FIXME: we are not processing inline assembly, which contains register
300 // operands, because it is used by later target generic code.
301 if (MI->isDebugInstr() || MI->isLabel() || MI->isInlineAsm())
302 return;
303
304 // Transform to _S instruction.
305 auto RegOpcode = OutMI.getOpcode();
306 auto StackOpcode = WebAssembly::getStackOpcode(RegOpcode);
307 assert(StackOpcode != -1 && "Failed to stackify instruction");
308 OutMI.setOpcode(StackOpcode);
309
310 // Remove register operands.
311 for (auto I = OutMI.getNumOperands(); I; --I) {
312 auto &MO = OutMI.getOperand(I - 1);
313 if (MO.isReg()) {
314 OutMI.erase(&MO);
315 }
316 }
317}
unsigned const MachineRegisterInfo * MRI
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
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
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
cl::opt< bool > WasmKeepRegisters
static void removeRegisterOperands(const MachineInstr *MI, MCInst &OutMI)
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 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.
MCSymbol * getSymbol(const GlobalValue *GV) const
Definition: AsmPrinter.cpp:701
MCSymbol * createTempSymbol(const Twine &Name) const
ConstantFP - Floating Point Values [float, double].
Definition: Constants.h:271
static const MCBinaryExpr * createAdd(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx)
Definition: MCExpr.h:537
static const MCConstantExpr * create(int64_t Value, MCContext &Ctx, bool PrintInHex=false, unsigned SizeInBytes=0)
Definition: MCExpr.cpp:222
wasm::WasmSignature * createWasmSignature()
Allocates and returns a new WasmSignature instance (with empty parameter and return type lists).
Definition: MCContext.cpp:428
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:185
void erase(iterator I)
Definition: MCInst.h:217
unsigned getNumOperands() const
Definition: MCInst.h:209
unsigned getOpcode() const
Definition: MCInst.h:199
iterator insert(iterator I, const MCOperand &Op)
Definition: MCInst.h:225
void addOperand(const MCOperand Op)
Definition: MCInst.h:211
iterator begin()
Definition: MCInst.h:220
void setOpcode(unsigned Op)
Definition: MCInst.h:198
const MCOperand & getOperand(unsigned i) const
Definition: MCInst.h:207
Describe properties that are true of each instruction in the target description file.
Definition: MCInstrDesc.h:198
This holds information about one operand of a machine instruction, indicating the register class for ...
Definition: MCInstrDesc.h:85
Instances of this class represent operands of the MCInst class.
Definition: MCInst.h:37
static MCOperand createExpr(const MCExpr *Val)
Definition: MCInst.h:163
static MCOperand createSFPImm(uint32_t Val)
Definition: MCInst.h:149
static MCOperand createReg(MCRegister Reg)
Definition: MCInst.h:135
static MCOperand createImm(int64_t Val)
Definition: MCInst.h:142
static MCOperand createDFPImm(uint64_t Val)
Definition: MCInst.h:156
static const MCSymbolRefExpr * create(const MCSymbol *Symbol, MCContext &Ctx)
Definition: MCExpr.h:398
void setSignature(wasm::WasmSignature *Sig)
Definition: MCSymbolWasm.h:132
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
Definition: MCSymbol.h:41
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
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:69
const MachineBasicBlock * getParent() const
Definition: MachineInstr.h:347
MachineOperand class - Representation of each machine instruction operand.
const GlobalValue * getGlobal() 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_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:130
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Definition: SmallVector.h:573
void push_back(const T &Elt)
Definition: SmallVector.h:413
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1196
Primary interface to the complete machine description for the target machine.
Definition: TargetMachine.h:77
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, bool EnableEmEH, wasm::WasmSignature *Sig, bool &InvokeDetected)
This class is derived from MachineFunctionInfo and contains private WebAssembly-specific information ...
unsigned getWAReg(unsigned 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.
cl::opt< bool > WasmEnableEmEH
BlockType
Used as immediate MachineOperands for block signatures.
@ OPERAND_TYPEINDEX
type signature immediate for call_indirect.
@ OPERAND_SIGNATURE
signature immediate for block/loop.
cl::opt< bool > WasmEnableEmSjLj
int getStackOpcode(unsigned short Opcode)
bool isWasmVarAddressSpace(unsigned AS)
initializer< Ty > init(const Ty &Val)
Definition: CommandLine.h:443
@ WASM_SYMBOL_TYPE_FUNCTION
Definition: Wasm.h:216
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)
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
Definition: Error.cpp:167
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:495