LLVM 23.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 MachineOperand &MO) const {
72 const GlobalValue *Global = MO.getGlobal();
73 if (!isa<Function>(Global)) {
74 auto *WasmSym = static_cast<MCSymbolWasm *>(Printer.getSymbol(Global));
75 // If the symbol doesn't have an explicit WasmSymbolType yet and the
76 // GlobalValue is actually a WebAssembly global, then ensure the symbol is a
77 // WASM_SYMBOL_TYPE_GLOBAL.
78 if (WebAssembly::isWasmVarAddressSpace(Global->getAddressSpace()) &&
79 !WasmSym->getType()) {
80 const MachineInstr &MI = *MO.getParent();
81 const MachineFunction &MF = *MO.getParent()->getParent()->getParent();
82 const TargetMachine &TM = MF.getTarget();
83 const Function &CurrentFunc = MF.getFunction();
84
85 std::optional<bool> Mutable =
86 getWasmGlobalMutable(Global, CurrentFunc, MI.getDebugLoc());
87 if (!Mutable.has_value())
88 return WasmSym;
89
90 Type *GlobalVT = Global->getValueType();
92 computeLegalValueVTs(CurrentFunc, TM, GlobalVT, VTs);
93
94 WebAssembly::wasmSymbolSetType(WasmSym, GlobalVT, VTs, *Mutable);
95 }
96 return WasmSym;
97 }
98
99 const auto *FuncTy = cast<FunctionType>(Global->getValueType());
100 const MachineFunction &MF = *MO.getParent()->getParent()->getParent();
101 const TargetMachine &TM = MF.getTarget();
102 const Function &CurrentFunc = MF.getFunction();
103
104 SmallVector<MVT, 1> ResultMVTs;
105 SmallVector<MVT, 4> ParamMVTs;
106 const auto *const F = dyn_cast<Function>(Global);
107 computeSignatureVTs(FuncTy, F, CurrentFunc, TM, ParamMVTs, ResultMVTs);
108 auto Signature = signatureFromMVTs(Ctx, ResultMVTs, ParamMVTs);
109
110 bool InvokeDetected = false;
111 auto *WasmSym = Printer.getMCSymbolForFunction(F, Signature, InvokeDetected);
112 WasmSym->setSignature(Signature);
113 WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
114 return WasmSym;
115}
116
117MCSymbol *WebAssemblyMCInstLower::GetExternalSymbolSymbol(
118 const MachineOperand &MO) const {
119 return Printer.getOrCreateWasmSymbol(MO.getSymbolName());
120}
121
122MCOperand WebAssemblyMCInstLower::lowerSymbolOperand(const MachineOperand &MO,
123 MCSymbol *Sym) const {
124 auto Spec = WebAssembly::S_None;
125 unsigned TargetFlags = MO.getTargetFlags();
126
127 switch (TargetFlags) {
129 break;
132 break;
134 Spec = WebAssembly::S_GOT;
135 break;
138 break;
141 break;
144 break;
145 default:
146 llvm_unreachable("Unknown target flag on GV operand");
147 }
148
149 const MCExpr *Expr = MCSymbolRefExpr::create(Sym, Spec, Ctx);
150
151 if (MO.getOffset() != 0) {
152 const auto *WasmSym = static_cast<const MCSymbolWasm *>(Sym);
153 if (TargetFlags == WebAssemblyII::MO_GOT)
154 report_fatal_error("GOT symbol references do not support offsets");
155 if (WasmSym->isFunction())
156 report_fatal_error("Function addresses with offsets not supported");
157 if (WasmSym->isGlobal())
158 report_fatal_error("Global indexes with offsets not supported");
159 if (WasmSym->isTag())
160 report_fatal_error("Tag indexes with offsets not supported");
161 if (WasmSym->isTable())
162 report_fatal_error("Table indexes with offsets not supported");
163
165 Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
166 }
167
168 return MCOperand::createExpr(Expr);
169}
170
171MCOperand WebAssemblyMCInstLower::lowerTypeIndexOperand(
173 SmallVectorImpl<wasm::ValType> &&Params) const {
174 auto Signature = Ctx.createWasmSignature();
175 Signature->Returns = std::move(Returns);
176 Signature->Params = std::move(Params);
177 auto *Sym =
178 static_cast<MCSymbolWasm *>(Printer.createTempSymbol("typeindex"));
179 Sym->setSignature(Signature);
181 const MCExpr *Expr =
183 return MCOperand::createExpr(Expr);
184}
185
187WebAssemblyMCInstLower::lowerEncodedFunctionSignature(const APInt &Sig) const {
188 // For APInt a word is 64 bits on all architectures, see definition in APInt.h
189 auto NumWords = Sig.getNumWords();
192
193 int Idx = NumWords;
194 auto GetWord = [&Idx, &Sig]() {
195 Idx--;
196 return Sig.extractBitsAsZExtValue(64, 64 * Idx);
197 };
198 // Annoying special case: if getSignificantBits() <= 64 then InstrEmitter will
199 // emit an Imm instead of a CImm. It simplifies WebAssemblyMCInstLower if we
200 // always emit a CImm. So xor NParams with 0x7ffffff to ensure
201 // getSignificantBits() > 64
202 // See encodeFunctionSignature in WebAssemblyISelDAGtoDAG.cpp
203 int NReturns = GetWord() ^ 0x7ffffff;
204 for (int I = 0; I < NReturns; I++) {
205 Returns.push_back(static_cast<wasm::ValType>(GetWord()));
206 }
207 int NParams = GetWord();
208 for (int I = 0; I < NParams; I++) {
209 Params.push_back(static_cast<wasm::ValType>(GetWord()));
210 }
211 return lowerTypeIndexOperand(std::move(Returns), std::move(Params));
212}
213
216 const Function &F = MI->getMF()->getFunction();
217 const TargetMachine &TM = MI->getMF()->getTarget();
218 Type *RetTy = F.getReturnType();
219 SmallVector<MVT, 4> CallerRetTys;
220 computeLegalValueVTs(F, TM, RetTy, CallerRetTys);
221 valTypesFromMVTs(CallerRetTys, Returns);
222}
223
225 MCInst &OutMI) const {
226 OutMI.setOpcode(MI->getOpcode());
227
228 const MCInstrDesc &Desc = MI->getDesc();
229 unsigned NumVariadicDefs = MI->getNumExplicitDefs() - Desc.getNumDefs();
230 const MachineFunction *MF = MI->getMF();
231 const auto &TLI =
232 *MF->getSubtarget<WebAssemblySubtarget>().getTargetLowering();
233 wasm::ValType PtrTy = TLI.getPointerTy(MF->getDataLayout()) == MVT::i32
236
237 for (unsigned I = 0, E = MI->getNumOperands(); I != E; ++I) {
238 const MachineOperand &MO = MI->getOperand(I);
239
240 MCOperand MCOp;
241 switch (MO.getType()) {
242 default:
243 MI->print(errs());
244 llvm_unreachable("unknown operand type");
246 MI->print(errs());
247 llvm_unreachable("MachineBasicBlock operand should have been rewritten");
249 // Ignore all implicit register operands.
250 if (MO.isImplicit())
251 continue;
252 const WebAssemblyFunctionInfo &MFI =
253 *MI->getParent()->getParent()->getInfo<WebAssemblyFunctionInfo>();
254 unsigned WAReg = MFI.getWAReg(MO.getReg());
255 MCOp = MCOperand::createReg(WAReg);
256 break;
257 }
259 // Lower type index placeholder for ref.test
260 // Currently this is the only way that CImmediates show up so panic if we
261 // get confused.
262 unsigned DescIndex = I - NumVariadicDefs;
263 assert(DescIndex < Desc.NumOperands && "unexpected CImmediate operand");
264 auto Operands = Desc.operands();
265 const MCOperandInfo &Info = Operands[DescIndex];
266 assert(Info.OperandType == WebAssembly::OPERAND_TYPEINDEX &&
267 "unexpected CImmediate operand");
268 (void)Info;
269 MCOp = lowerEncodedFunctionSignature(MO.getCImm()->getValue());
270 break;
271 }
273 unsigned DescIndex = I - NumVariadicDefs;
274 if (DescIndex < Desc.NumOperands) {
275 auto Operands = Desc.operands();
276 const MCOperandInfo &Info = Operands[DescIndex];
277 // Replace type index placeholder with actual type index. The type index
278 // placeholders are Immediates and have an operand type of
279 // OPERAND_TYPEINDEX or OPERAND_SIGNATURE.
280 if (Info.OperandType == WebAssembly::OPERAND_TYPEINDEX) {
281 // Lower type index placeholder for a CALL_INDIRECT instruction
284
285 const MachineRegisterInfo &MRI =
286 MI->getParent()->getParent()->getRegInfo();
287 for (const MachineOperand &MO : MI->defs())
289 MRI.getRegClass(MO.getReg())->getID()));
290 for (const MachineOperand &MO : MI->explicit_uses())
291 if (MO.isReg())
293 MRI.getRegClass(MO.getReg())->getID()));
294
295 // call_indirect instructions have a callee operand at the end which
296 // doesn't count as a param.
297 if (WebAssembly::isCallIndirect(MI->getOpcode()))
298 Params.pop_back();
299
300 // return_call_indirect instructions have the return type of the
301 // caller
302 if (MI->getOpcode() == WebAssembly::RET_CALL_INDIRECT)
303 getFunctionReturns(MI, Returns);
304
305 MCOp = lowerTypeIndexOperand(std::move(Returns), std::move(Params));
306 break;
307 }
308 if (Info.OperandType == WebAssembly::OPERAND_SIGNATURE) {
309 // Lower type index placeholder for blocks
310 auto BT = static_cast<WebAssembly::BlockType>(MO.getImm());
314 // Multivalue blocks are emitted in two cases:
315 // 1. When the blocks will never be exited and are at the ends of
316 // functions (see
317 // WebAssemblyCFGStackify::fixEndsAtEndOfFunction). In this case
318 // the exact multivalue signature can always be inferred from the
319 // return type of the parent function.
320 // 2. (catch_ref ...) clause in try_table instruction. Currently all
321 // tags we support (cpp_exception and c_longjmp) throws a single
322 // pointer, so the multivalue signature for this case will be
323 // (ptr, exnref). Having MO_CATCH_BLOCK_SIG target flags means
324 // this is a destination of a catch_ref.
326 Returns = {PtrTy, wasm::ValType::EXNREF};
327 } else
328 getFunctionReturns(MI, Returns);
329 MCOp = lowerTypeIndexOperand(std::move(Returns),
331 break;
332 }
333 }
334 }
335 MCOp = MCOperand::createImm(MO.getImm());
336 break;
337 }
339 const ConstantFP *Imm = MO.getFPImm();
340 const uint64_t BitPattern =
341 Imm->getValueAPF().bitcastToAPInt().getZExtValue();
342 if (Imm->getType()->isFloatTy())
343 MCOp = MCOperand::createSFPImm(static_cast<uint32_t>(BitPattern));
344 else if (Imm->getType()->isDoubleTy())
345 MCOp = MCOperand::createDFPImm(BitPattern);
346 else
347 llvm_unreachable("unknown floating point immediate type");
348 break;
349 }
351 MCOp = lowerSymbolOperand(MO, GetGlobalAddressSymbol(MO));
352 break;
354 MCOp = lowerSymbolOperand(MO, GetExternalSymbolSymbol(MO));
355 break;
357 assert(MO.getTargetFlags() == 0 &&
358 "WebAssembly does not use target flags on MCSymbol");
359 MCOp = lowerSymbolOperand(MO, MO.getMCSymbol());
360 break;
361 }
362
363 OutMI.addOperand(MCOp);
364 }
365
368 else if (Desc.variadicOpsAreDefs())
369 OutMI.insert(OutMI.begin(), MCOperand::createImm(MI->getNumExplicitDefs()));
370}
371
372static void removeRegisterOperands(const MachineInstr *MI, MCInst &OutMI) {
373 // Remove all uses of stackified registers to bring the instruction format
374 // into its final stack form used thruout MC, and transition opcodes to
375 // their _S variant.
376 // We do this separate from the above code that still may need these
377 // registers for e.g. call_indirect signatures.
378 // See comments in lib/Target/WebAssembly/WebAssemblyInstrFormats.td for
379 // details.
380 // TODO: the code above creates new registers which are then removed here.
381 // That code could be slightly simplified by not doing that, though maybe
382 // it is simpler conceptually to keep the code above in "register mode"
383 // until this transition point.
384 // FIXME: we are not processing inline assembly, which contains register
385 // operands, because it is used by later target generic code.
386 if (MI->isDebugInstr() || MI->isLabel() || MI->isInlineAsm())
387 return;
388
389 // Transform to _S instruction.
390 auto RegOpcode = OutMI.getOpcode();
391 auto StackOpcode = WebAssembly::getStackOpcode(RegOpcode);
392 assert(StackOpcode != -1 && "Failed to stackify instruction");
393 OutMI.setOpcode(StackOpcode);
394
395 // Remove register operands.
396 for (auto I = OutMI.getNumOperands(); I; --I) {
397 auto &MO = OutMI.getOperand(I - 1);
398 if (MO.isReg()) {
399 OutMI.erase(&MO);
400 }
401 }
402}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
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
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:521
unsigned getNumWords() const
Get the number of words.
Definition APInt.h:1518
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
Diagnostic information for unsupported feature in backend.
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition Function.cpp:354
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: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,...
const TargetRegisterClass * getRegClass(Register Reg) const
Return the register class of the specified virtual register.
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.
unsigned getID() const
Return the register class ID number.
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:229
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)