LLVM 24.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"
33#include "llvm/MC/MCAsmInfo.h"
34#include "llvm/MC/MCContext.h"
35#include "llvm/MC/MCExpr.h"
36#include "llvm/MC/MCInst.h"
40#include <optional>
41
42using namespace llvm;
43
44// This disables the removal of registers when lowering into MC, as required
45// by some current tests.
46static cl::opt<bool>
47 WasmKeepRegisters("wasm-keep-registers", cl::Hidden,
48 cl::desc("WebAssembly: output stack registers in"
49 " instruction output for test purposes only."),
50 cl::init(false));
51
52static std::optional<bool> getWasmGlobalMutable(const GlobalValue *Global,
53 const Function &CurrentFunc,
54 const DiagnosticLocation &DL) {
55 const auto *BaseObject = Global->getAliaseeObject();
56 const auto *GV = dyn_cast_or_null<GlobalVariable>(BaseObject);
57 if (!GV) {
59 CurrentFunc,
60 "wasm_var address space symbol must resolve to a "
61 "GlobalVariable",
62 DL));
63 return std::nullopt;
64 }
65 return !GV->isConstant();
66}
67
68static void removeRegisterOperands(const MachineInstr *MI, MCInst &OutMI);
69
71WebAssemblyMCInstLower::GetGlobalAddressSymbol(const GlobalValue &Global,
72 const DebugLoc &DL) const {
73 const TargetMachine &TM = Printer.TM;
74 const Function &CurrentFunc = Printer.MF->getFunction();
75 if (!isa<Function>(Global)) {
76 auto *WasmSym = static_cast<MCSymbolWasm *>(Printer.getSymbol(&Global));
77 // If the symbol doesn't have an explicit WasmSymbolType yet and the
78 // GlobalValue is actually a WebAssembly global, then ensure the symbol is a
79 // WASM_SYMBOL_TYPE_GLOBAL.
80 if (WebAssembly::isWasmVarAddressSpace(Global.getAddressSpace()) &&
81 !WasmSym->getType()) {
82 std::optional<bool> Mutable =
83 getWasmGlobalMutable(&Global, CurrentFunc, DL);
84 if (!Mutable.has_value())
85 return WasmSym;
86
87 Type *GlobalVT = Global.getValueType();
89 computeLegalValueVTs(CurrentFunc, TM, GlobalVT, VTs);
90
91 WebAssembly::wasmSymbolSetType(WasmSym, GlobalVT, VTs, *Mutable);
92 }
93 return WasmSym;
94 }
95
96 const auto *FuncTy = cast<FunctionType>(Global.getValueType());
97
98 SmallVector<MVT, 1> ResultMVTs;
99 SmallVector<MVT, 4> ParamMVTs;
100 const auto *const F = dyn_cast<Function>(&Global);
101 computeSignatureVTs(FuncTy, F, CurrentFunc, TM, ParamMVTs, ResultMVTs);
102 auto Signature = signatureFromMVTs(Ctx, ResultMVTs, ParamMVTs);
103
104 bool InvokeDetected = false;
105 auto *WasmSym = Printer.getMCSymbolForFunction(F, Signature, InvokeDetected);
106 WasmSym->setSignature(Signature);
107 WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
108 return WasmSym;
109}
110
111MCSymbol *WebAssemblyMCInstLower::GetExternalSymbolSymbol(
112 const MachineOperand &MO) const {
113 return Printer.getOrCreateWasmSymbol(MO.getSymbolName());
114}
115
116MCOperand WebAssemblyMCInstLower::lowerSymbolOperand(const MachineOperand &MO,
117 MCSymbol *Sym) const {
118 auto Spec = WebAssembly::S_None;
119 unsigned TargetFlags = MO.getTargetFlags();
120
121 switch (TargetFlags) {
123 break;
126 break;
128 Spec = WebAssembly::S_GOT;
129 break;
132 break;
135 break;
138 break;
139 default:
140 llvm_unreachable("Unknown target flag on GV operand");
141 }
142
143 const MCExpr *Expr = MCSymbolRefExpr::create(Sym, Spec, Ctx);
144
145 if (MO.getOffset() != 0) {
146 const auto *WasmSym = static_cast<const MCSymbolWasm *>(Sym);
147 if (TargetFlags == WebAssemblyII::MO_GOT)
148 report_fatal_error("GOT symbol references do not support offsets");
149 if (WasmSym->isFunction())
150 report_fatal_error("Function addresses with offsets not supported");
151 if (WasmSym->isGlobal())
152 report_fatal_error("Global indexes with offsets not supported");
153 if (WasmSym->isTag())
154 report_fatal_error("Tag indexes with offsets not supported");
155 if (WasmSym->isTable())
156 report_fatal_error("Table indexes with offsets not supported");
157
159 Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
160 }
161
162 return MCOperand::createExpr(Expr);
163}
164
165MCOperand WebAssemblyMCInstLower::lowerTypeIndexOperand(
167 SmallVectorImpl<wasm::ValType> &&Params) const {
168 auto Signature = Ctx.createWasmSignature();
169 Signature->Returns = std::move(Returns);
170 Signature->Params = std::move(Params);
171 auto *Sym =
172 static_cast<MCSymbolWasm *>(Printer.createTempSymbol("typeindex"));
173 Sym->setSignature(Signature);
175 const MCExpr *Expr =
177 return MCOperand::createExpr(Expr);
178}
179
181WebAssemblyMCInstLower::lowerEncodedFunctionSignature(const APInt &Sig) const {
182 // For APInt a word is 64 bits on all architectures, see definition in APInt.h
183 auto NumWords = Sig.getNumWords();
186
187 int Idx = NumWords;
188 auto GetWord = [&Idx, &Sig]() {
189 Idx--;
190 return Sig.extractBitsAsZExtValue(64, 64 * Idx);
191 };
192 // Annoying special case: if getSignificantBits() <= 64 then InstrEmitter will
193 // emit an Imm instead of a CImm. It simplifies WebAssemblyMCInstLower if we
194 // always emit a CImm. So xor NParams with 0x7ffffff to ensure
195 // getSignificantBits() > 64
196 // See encodeFunctionSignature in WebAssemblyISelDAGtoDAG.cpp
197 int NReturns = GetWord() ^ 0x7ffffff;
198 for (int I = 0; I < NReturns; I++) {
199 Returns.push_back(static_cast<wasm::ValType>(GetWord()));
200 }
201 int NParams = GetWord();
202 for (int I = 0; I < NParams; I++) {
203 Params.push_back(static_cast<wasm::ValType>(GetWord()));
204 }
205 return lowerTypeIndexOperand(std::move(Returns), std::move(Params));
206}
207
210 const Function &F = MI->getMF()->getFunction();
211 const TargetMachine &TM = MI->getMF()->getTarget();
212 Type *RetTy = F.getReturnType();
213 SmallVector<MVT, 4> CallerRetTys;
214 computeLegalValueVTs(F, TM, RetTy, CallerRetTys);
215 valTypesFromMVTs(CallerRetTys, Returns);
216}
217
219 MCInst &OutMI) const {
220 OutMI.setOpcode(MI->getOpcode());
221
222 const MCInstrDesc &Desc = MI->getDesc();
223 unsigned NumVariadicDefs = MI->getNumExplicitDefs() - Desc.getNumDefs();
224 const MachineFunction *MF = MI->getMF();
225 const auto &TLI =
226 *MF->getSubtarget<WebAssemblySubtarget>().getTargetLowering();
227 wasm::ValType PtrTy = TLI.getPointerTy(MF->getDataLayout()) == MVT::i32
230
231 for (unsigned I = 0, E = MI->getNumOperands(); I != E; ++I) {
232 const MachineOperand &MO = MI->getOperand(I);
233
234 MCOperand MCOp;
235 switch (MO.getType()) {
236 default:
237 MI->print(errs());
238 llvm_unreachable("unknown operand type");
240 MI->print(errs());
241 llvm_unreachable("MachineBasicBlock operand should have been rewritten");
243 // Ignore all implicit register operands.
244 if (MO.isImplicit())
245 continue;
246 const WebAssemblyFunctionInfo &MFI =
247 *MI->getParent()->getParent()->getInfo<WebAssemblyFunctionInfo>();
248 unsigned WAReg = MFI.getWAReg(MO.getReg());
249 MCOp = MCOperand::createReg(WAReg);
250 break;
251 }
253 // Lower type index placeholder for ref.test
254 // Currently this is the only way that CImmediates show up so panic if we
255 // get confused.
256 unsigned DescIndex = I - NumVariadicDefs;
257 assert(DescIndex < Desc.NumOperands && "unexpected CImmediate operand");
258 auto Operands = Desc.operands();
259 const MCOperandInfo &Info = Operands[DescIndex];
260 assert(Info.OperandType == WebAssembly::OPERAND_TYPEINDEX &&
261 "unexpected CImmediate operand");
262 (void)Info;
263 MCOp = lowerEncodedFunctionSignature(MO.getCImm()->getValue());
264 break;
265 }
267 unsigned DescIndex = I - NumVariadicDefs;
268 if (DescIndex < Desc.NumOperands) {
269 auto Operands = Desc.operands();
270 const MCOperandInfo &Info = Operands[DescIndex];
271 // Replace type index placeholder with actual type index. The type index
272 // placeholders are Immediates and have an operand type of
273 // OPERAND_TYPEINDEX or OPERAND_SIGNATURE.
274 if (Info.OperandType == WebAssembly::OPERAND_TYPEINDEX) {
275 // Lower type index placeholder for a CALL_INDIRECT instruction
278
279 const MachineRegisterInfo &MRI =
280 MI->getParent()->getParent()->getRegInfo();
281 for (const MachineOperand &MO : MI->defs())
283 MRI.getRegClass(MO.getReg())->getID()));
284 for (const MachineOperand &MO : MI->explicit_uses())
285 if (MO.isReg())
287 MRI.getRegClass(MO.getReg())->getID()));
288
289 // call_indirect instructions have a callee operand at the end which
290 // doesn't count as a param.
291 if (WebAssembly::isCallIndirect(MI->getOpcode()))
292 Params.pop_back();
293
294 // return_call_indirect instructions have the return type of the
295 // caller
296 if (MI->getOpcode() == WebAssembly::RET_CALL_INDIRECT)
297 getFunctionReturns(MI, Returns);
298
299 MCOp = lowerTypeIndexOperand(std::move(Returns), std::move(Params));
300 break;
301 }
302 if (Info.OperandType == WebAssembly::OPERAND_SIGNATURE) {
303 // Lower type index placeholder for blocks
304 auto BT = static_cast<WebAssembly::BlockType>(MO.getImm());
308 // Multivalue blocks are emitted in two cases:
309 // 1. When the blocks will never be exited and are at the ends of
310 // functions (see
311 // WebAssemblyCFGStackify::fixEndsAtEndOfFunction). In this case
312 // the exact multivalue signature can always be inferred from the
313 // return type of the parent function.
314 // 2. (catch_ref ...) clause in try_table instruction. Currently all
315 // tags we support (cpp_exception and c_longjmp) throws a single
316 // pointer, so the multivalue signature for this case will be
317 // (ptr, exnref). Having MO_CATCH_BLOCK_SIG target flags means
318 // this is a destination of a catch_ref.
320 Returns = {PtrTy, wasm::ValType::EXNREF};
321 } else
322 getFunctionReturns(MI, Returns);
323 MCOp = lowerTypeIndexOperand(std::move(Returns),
325 break;
326 }
327 }
328 }
329 MCOp = MCOperand::createImm(MO.getImm());
330 break;
331 }
333 const ConstantFP *Imm = MO.getFPImm();
334 const uint64_t BitPattern =
335 Imm->getValueAPF().bitcastToAPInt().getZExtValue();
336 if (Imm->getType()->isFloatTy())
337 MCOp = MCOperand::createSFPImm(static_cast<uint32_t>(BitPattern));
338 else if (Imm->getType()->isDoubleTy())
339 MCOp = MCOperand::createDFPImm(BitPattern);
340 else
341 llvm_unreachable("unknown floating point immediate type");
342 break;
343 }
345 MCOp = lowerSymbolOperand(
346 MO, GetGlobalAddressSymbol(*MO.getGlobal(), MI->getDebugLoc()));
347 break;
349 MCOp = lowerSymbolOperand(MO, GetExternalSymbolSymbol(MO));
350 break;
352 assert(MO.getTargetFlags() == 0 &&
353 "WebAssembly does not use target flags on MCSymbol");
354 MCOp = lowerSymbolOperand(MO, MO.getMCSymbol());
355 break;
356 }
357
358 OutMI.addOperand(MCOp);
359 }
360
363 else if (Desc.variadicOpsAreDefs())
364 OutMI.insert(OutMI.begin(), MCOperand::createImm(MI->getNumExplicitDefs()));
365}
366
367static void removeRegisterOperands(const MachineInstr *MI, MCInst &OutMI) {
368 // Remove all uses of stackified registers to bring the instruction format
369 // into its final stack form used throughout MC, and transition opcodes to
370 // their _S variant.
371 // We do this separate from the above code that still may need these
372 // registers for e.g. call_indirect signatures.
373 // See comments in lib/Target/WebAssembly/WebAssemblyInstrFormats.td for
374 // details.
375 // TODO: the code above creates new registers which are then removed here.
376 // That code could be slightly simplified by not doing that, though maybe
377 // it is simpler conceptually to keep the code above in "register mode"
378 // until this transition point.
379 // FIXME: we are not processing inline assembly, which contains register
380 // operands, because it is used by later target generic code.
381 if (MI->isDebugInstr() || MI->isLabel() || MI->isInlineAsm())
382 return;
383
384 // Transform to _S instruction.
385 auto RegOpcode = OutMI.getOpcode();
386 auto StackOpcode = WebAssembly::getStackOpcode(RegOpcode);
387 assert(StackOpcode != -1 && "Failed to stackify instruction");
388 OutMI.setOpcode(StackOpcode);
389
390 // Remove register operands.
391 for (auto I = OutMI.getNumOperands(); I; --I) {
392 auto &MO = OutMI.getOperand(I - 1);
393 if (MO.isReg()) {
394 OutMI.erase(&MO);
395 }
396 }
397}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
uint64_t Imm
This file implements a class to represent arbitrary precision integral constant values and operations...
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
BitTracker BT
This file contains the declarations for the subclasses of Constant, which represent the different fla...
IRTranslator LLVM IR MI
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
MachineRegisterInfo & MRI
SI Fold 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 std::optional< bool > getWasmGlobalMutable(const GlobalValue *Global, const Function &CurrentFunc, const DiagnosticLocation &DL)
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:517
unsigned getNumWords() const
Get the number of words.
Definition APInt.h:1515
ConstantFP - Floating Point Values [float, double].
Definition Constants.h:420
const APInt & getValue() const
Return the constant as an APInt value reference.
Definition Constants.h:159
A debug info location.
Definition DebugLoc.h:126
Diagnostic information for unsupported feature in backend.
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition Function.cpp:352
LLVM_ABI void diagnose(const DiagnosticInfo &DI)
Report a message to the currently installed diagnostic handler.
static const MCBinaryExpr * createAdd(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx, SMLoc Loc=SMLoc())
Definition MCExpr.h:342
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:88
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:213
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
Definition MCSymbol.h:42
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.
Representation of each machine instruction.
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.
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:46
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)
int32_t getStackOpcode(uint32_t Opcode)
BlockType
Used as immediate MachineOperands for block signatures.
void wasmSymbolSetType(MCSymbolWasm *Sym, const Type *GlobalVT, ArrayRef< MVT > VTs, bool Mutable)
Sets a Wasm Symbol Type.
@ OPERAND_TYPEINDEX
type signature immediate for call_indirect.
@ OPERAND_SIGNATURE
signature immediate for block/loop.
bool isWasmVarAddressSpace(unsigned AS)
initializer< Ty > init(const Ty &Val)
@ WASM_SYMBOL_TYPE_FUNCTION
Definition Wasm.h:231
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:643
Op::Description Desc
auto dyn_cast_or_null(const Y &Val)
Definition Casting.h:753
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
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:547
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:559
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)