LLVM 23.0.0git
WebAssemblyAsmPrinter.cpp
Go to the documentation of this file.
1//===-- WebAssemblyAsmPrinter.cpp - WebAssembly LLVM assembly writer ------===//
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 a printer that converts from our internal
11/// representation of machine-dependent LLVM code to the WebAssembly assembly
12/// language.
13///
14//===----------------------------------------------------------------------===//
15
22#include "WebAssembly.h"
29#include "llvm/ADT/MapVector.h"
30#include "llvm/ADT/SmallSet.h"
39#include "llvm/IR/DataLayout.h"
42#include "llvm/IR/Metadata.h"
43#include "llvm/IR/Module.h"
44#include "llvm/MC/MCContext.h"
46#include "llvm/MC/MCStreamer.h"
47#include "llvm/MC/MCSymbol.h"
51#include "llvm/Support/Debug.h"
53
54using namespace llvm;
55
56#define DEBUG_TYPE "asm-printer"
57
59
60//===----------------------------------------------------------------------===//
61// Helpers.
62//===----------------------------------------------------------------------===//
63
65 const TargetRegisterInfo *TRI = Subtarget->getRegisterInfo();
66 const TargetRegisterClass *TRC = MRI->getRegClass(RegNo);
67 for (MVT T : {MVT::i32, MVT::i64, MVT::f32, MVT::f64, MVT::v16i8, MVT::v8i16,
68 MVT::v4i32, MVT::v2i64, MVT::v4f32, MVT::v2f64, MVT::v8f16})
69 if (TRI->isTypeLegalForClass(*TRC, T))
70 return T;
71 LLVM_DEBUG(errs() << "Unknown type for register number: " << RegNo);
72 llvm_unreachable("Unknown register type");
73 return MVT::Other;
74}
75
77 Register RegNo = MO.getReg();
78 assert(RegNo.isVirtual() &&
79 "Unlowered physical register encountered during assembly printing");
80 assert(!MFI->isVRegStackified(RegNo));
81 unsigned WAReg = MFI->getWAReg(RegNo);
83 return '$' + utostr(WAReg);
84}
85
90
91// Emscripten exception handling helpers
92//
93// This converts invoke names generated by LowerEmscriptenEHSjLj to real names
94// that are expected by JavaScript glue code. The invoke names generated by
95// Emscripten JS glue code are based on their argument and return types; for
96// example, for a function that takes an i32 and returns nothing, it is
97// 'invoke_vi'. But the format of invoke generated by LowerEmscriptenEHSjLj pass
98// contains a mangled string generated from their IR types, for example,
99// "__invoke_void_%struct.mystruct*_int", because final wasm types are not
100// available in the IR pass. So we convert those names to the form that
101// Emscripten JS code expects.
102//
103// Refer to LowerEmscriptenEHSjLj pass for more details.
104
105// Returns true if the given function name is an invoke name generated by
106// LowerEmscriptenEHSjLj pass.
108 if (Name.front() == '"' && Name.back() == '"')
109 Name = Name.substr(1, Name.size() - 2);
110 return Name.starts_with("__invoke_");
111}
112
113// Returns a character that represents the given wasm value type in invoke
114// signatures.
116 switch (VT) {
118 return 'i';
120 return 'j';
122 return 'f';
124 return 'd';
126 return 'V';
128 return 'F';
130 return 'X';
132 return 'E';
133 default:
134 llvm_unreachable("Unhandled wasm::ValType enum");
135 }
136}
137
138// Given the wasm signature, generate the invoke name in the format JS glue code
139// expects.
141 assert(Sig->Returns.size() <= 1);
142 std::string Ret = "invoke_";
143 if (!Sig->Returns.empty())
144 for (auto VT : Sig->Returns)
145 Ret += getInvokeSig(VT);
146 else
147 Ret += 'v';
148 // Invokes' first argument is a pointer to the original function, so skip it
149 for (unsigned I = 1, E = Sig->Params.size(); I < E; I++)
150 Ret += getInvokeSig(Sig->Params[I]);
151 return Ret;
152}
153
154//===----------------------------------------------------------------------===//
155// WebAssemblyAsmPrinter Implementation.
156//===----------------------------------------------------------------------===//
157
159 const Function *F, wasm::WasmSignature *Sig, bool &InvokeDetected) {
160 MCSymbolWasm *WasmSym = nullptr;
161
162 const bool EnableEmEH =
164 if (EnableEmEH && isEmscriptenInvokeName(F->getName())) {
165 assert(Sig);
166 InvokeDetected = true;
167 if (Sig->Returns.size() > 1) {
168 std::string Msg =
169 "Emscripten EH/SjLj does not support multivalue returns: " +
170 std::string(F->getName()) + ": " +
173 }
174 WasmSym = static_cast<MCSymbolWasm *>(
176 } else {
177 WasmSym = static_cast<MCSymbolWasm *>(getSymbol(F));
178 }
179 return WasmSym;
180}
181
183 if (GV->hasCommonLinkage()) {
184 OutContext.reportError(SMLoc(),
185 "common symbols are not yet implemented for Wasm: " +
186 getSymbol(GV)->getName());
187 return;
188 }
189
192 return;
193 }
194
195 assert(!GV->isThreadLocal());
196 auto *Sym = static_cast<MCSymbolWasm *>(getSymbol(GV));
197 if (!Sym->getType()) {
199 Type *GlobalVT = GV->getValueType();
200 // Function-specific subtargets are not needed here: WebAssembly
201 // coalesces features before isel, so use the TargetMachine's
202 // module-wide subtarget to compute legal value types.
203 auto &WasmTM = static_cast<const WebAssemblyTargetMachine &>(TM);
204 const WebAssemblySubtarget *ST = WasmTM.getSubtargetImpl();
205 const WebAssemblyTargetLowering &TLI = *ST->getTargetLowering();
207 GV->getDataLayout(), GlobalVT, VTs);
208
209 WebAssembly::wasmSymbolSetType(Sym, GlobalVT, VTs,
210 /*Mutable=*/!GV->isConstant());
211 }
212
213 emitVisibility(Sym, GV->getVisibility(), !GV->isDeclaration());
214 emitSymbolType(Sym);
215 if (GV->hasInitializer()) {
216 assert(getSymbolPreferLocal(*GV) == Sym);
217 emitLinkage(GV, Sym);
218 OutStreamer->emitLabel(Sym);
219 // TODO: Actually emit the initializer value. Otherwise the global has the
220 // default value for its type (0, ref.null, etc).
221 OutStreamer->addBlankLine();
222 }
223}
224
226 auto *WasmSym = static_cast<MCSymbolWasm *>(GetExternalSymbolSymbol(Name));
227 // May be called multiple times, so early out.
228 if (WasmSym->getType())
229 return WasmSym;
230
231 const WebAssemblySubtarget &Subtarget = getSubtarget();
232
233 // Except for certain known symbols, all symbols used by CodeGen are
234 // functions. It's OK to hardcode knowledge of specific symbols here; this
235 // method is precisely there for fetching the signatures of known
236 // Clang-provided symbols.
237 if (Name == "__stack_pointer" || Name == "__tls_base" ||
238 Name == "__memory_base" || Name == "__table_base" ||
239 Name == "__tls_size" || Name == "__tls_align") {
240 bool Mutable = Name == "__stack_pointer" || Name == "__tls_base";
241 WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL);
242 WasmSym->setGlobalType(wasm::WasmGlobalType{
243 uint8_t(Subtarget.hasAddr64() ? wasm::WASM_TYPE_I64
245 Mutable});
246 return WasmSym;
247 }
248
249 if (Name.starts_with("GCC_except_table")) {
250 WasmSym->setType(wasm::WASM_SYMBOL_TYPE_DATA);
251 return WasmSym;
252 }
253
256 if (Name == "__cpp_exception" || Name == "__c_longjmp") {
257 WasmSym->setType(wasm::WASM_SYMBOL_TYPE_TAG);
258 WasmSym->setExternal(true);
259
260 // Currently both C++ exceptions and C longjmps have a single pointer type
261 // param. For C++ exceptions it is a pointer to an exception object, and for
262 // C longjmps it is pointer to a struct that contains a setjmp buffer and a
263 // longjmp return value. We may consider using multiple value parameters for
264 // longjmps later when multivalue support is ready.
265 wasm::ValType AddrType =
266 Subtarget.hasAddr64() ? wasm::ValType::I64 : wasm::ValType::I32;
267 Params.push_back(AddrType);
268 } else if (Name == "__wasm_get_stack_pointer" ||
269 Name == "__wasm_get_tls_base") {
270 WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
272 } else if (Name == "__wasm_set_stack_pointer" ||
273 Name == "__wasm_set_tls_base") {
274 WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
276 } else { // Function symbols
277 WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
278 WebAssembly::getLibcallSignature(Subtarget, Name, Returns, Params);
279 }
280 auto Signature = OutContext.createWasmSignature();
281 Signature->Returns = std::move(Returns);
282 Signature->Params = std::move(Params);
283 WasmSym->setSignature(Signature);
284
285 return WasmSym;
286}
287
289 std::optional<wasm::WasmSymbolType> WasmTy = Sym->getType();
290 if (!WasmTy)
291 return;
292
293 switch (*WasmTy) {
296 break;
299 break;
302 break;
303 default:
304 break; // We only handle globals, tags and tables here
305 }
306}
307
309 if (signaturesEmitted)
310 return;
311 signaturesEmitted = true;
312
313 // Normally symbols for globals get discovered as the MI gets lowered,
314 // but we need to know about them ahead of time. This will however,
315 // only find symbols that have been used. Unused symbols from globals will
316 // not be found here.
317 MachineModuleInfoWasm &MMIW = MMI->getObjFileInfo<MachineModuleInfoWasm>();
318 for (StringRef Name : MMIW.MachineSymbolsUsed) {
319 auto *WasmSym = static_cast<MCSymbolWasm *>(getOrCreateWasmSymbol(Name));
320 if (WasmSym->isFunction()) {
321 // TODO(wvo): is there any case where this overlaps with the call to
322 // emitFunctionType in the loop below?
324 }
325 }
326
327 for (auto &It : OutContext.getSymbols()) {
328 // Emit .globaltype, .tagtype, or .tabletype declarations for extern
329 // declarations, i.e. those that have only been declared (but not defined)
330 // in the current module
331 auto Sym = static_cast<MCSymbolWasm *>(It.getValue().Symbol);
332 if (Sym && !Sym->isDefined())
333 emitSymbolType(Sym);
334 }
335
336 // We handle `__funcref_call_table` specially here.
337 //
338 // Unlike most table symbols, which are attached to a `GlobalVariable`
339 // this one is a directly created, freestanding MCSymbol, much like
340 // `__indirect_function_table`. However, given that the table is always
341 // identical (single element, default initialized), we declare it
342 // weak in each object, and define it here rather than in the linker.
343 //
344 // TODO: consider moving this definition elsewhere, or doing away with
345 // the table entirely (in favor of `call_ref` exclusively).
346 {
347 StringRef Name = "__funcref_call_table";
348 auto *Sym = static_cast<MCSymbolWasm *>(OutContext.lookupSymbol(Name));
349 if (Sym) {
350 if (!Sym->isFunctionTable())
351 OutContext.reportError(SMLoc(), "symbol is not a wasm funcref table");
352
353 // symbol is declared weak in `getOrCreateFuncrefCallTableSymbol`
354 assert(Sym->isWeak());
355 OutStreamer->emitSymbolAttribute(Sym, MCSA_Weak);
356
357 // Make sure we haven't already emitted it for whatever reason.
358 assert(!Sym->isDefined());
359
360 // Actually define the symbol.
361 // Confusingly enough, `emitLabel` is what "defines" a MCSymbol.
362 // Provides it a fragment, so that it `!isUndefined`
363 OutStreamer->emitLabel(Sym);
364 // No initializer needed. Default ref.null is good
365 OutStreamer->addBlankLine();
366 }
367 }
368
369 DenseSet<MCSymbol *> InvokeSymbols;
370 for (const auto &F : M) {
371 if (F.isIntrinsic())
372 continue;
373
374 // Emit function type info for all functions. This will emit duplicate
375 // information for defined functions (which already have function type
376 // info emitted alongside their definition), but this is necessary in
377 // order to enable the single-pass WebAssemblyAsmTypeCheck to succeed.
379 SmallVector<MVT, 4> Params;
380 computeSignatureVTs(F.getFunctionType(), &F, F, TM, Params, Results);
381 // At this point these MCSymbols may or may not have been created already
382 // and thus also contain a signature, but we need to get the signature
383 // anyway here in case it is an invoke that has not yet been created. We
384 // will discard it later if it turns out not to be necessary.
385 auto Signature = signatureFromMVTs(OutContext, Results, Params);
386 bool InvokeDetected = false;
387 auto *Sym = getMCSymbolForFunction(&F, Signature, InvokeDetected);
388
389 // Multiple functions can be mapped to the same invoke symbol. For
390 // example, two IR functions '__invoke_void_i8*' and '__invoke_void_i32'
391 // are both mapped to '__invoke_vi'. We keep them in a set once we emit an
392 // Emscripten EH symbol so we don't emit the same symbol twice.
393 if (InvokeDetected && !InvokeSymbols.insert(Sym).second)
394 continue;
395
397 if (!Sym->getSignature()) {
398 Sym->setSignature(Signature);
399 }
400
402
403 if (F.hasFnAttribute("wasm-import-module")) {
404 StringRef Name =
405 F.getFnAttribute("wasm-import-module").getValueAsString();
406 Sym->setImportModule(OutContext.allocateString(Name));
408 }
409 if (F.hasFnAttribute("wasm-import-name")) {
410 // If this is a converted Emscripten EH/SjLj symbol, we shouldn't use
411 // the original function name but the converted symbol name.
412 StringRef Name =
413 InvokeDetected
414 ? Sym->getName()
415 : F.getFnAttribute("wasm-import-name").getValueAsString();
416 Sym->setImportName(OutContext.allocateString(Name));
417 getTargetStreamer()->emitImportName(Sym, Name);
418 }
419
420 if (F.hasFnAttribute("wasm-export-name")) {
421 auto *Sym = static_cast<MCSymbolWasm *>(getSymbol(&F));
422 StringRef Name = F.getFnAttribute("wasm-export-name").getValueAsString();
423 Sym->setExportName(OutContext.allocateString(Name));
424 getTargetStreamer()->emitExportName(Sym, Name);
425 }
426 }
427}
428
430 // This is required to emit external declarations (like .functypes) when
431 // no functions are defined in the compilation unit and therefore,
432 // emitDecls() is not called until now.
433 emitDecls(M);
434
435 // When a function's address is taken, a TABLE_INDEX relocation is emitted
436 // against the function symbol at the use site. However the relocation
437 // doesn't explicitly refer to the table. In the future we may want to
438 // define a new kind of reloc against both the function and the table, so
439 // that the linker can see that the function symbol keeps the table alive,
440 // but for now manually mark the table as live.
441 for (const auto &F : M) {
442 if (!F.isIntrinsic() && F.hasAddressTaken()) {
443 MCSymbolWasm *FunctionTable =
445 OutStreamer->emitSymbolAttribute(FunctionTable, MCSA_NoDeadStrip);
446 break;
447 }
448 }
449
450 for (const auto &G : M.globals()) {
451 if (!G.hasInitializer() && G.hasExternalLinkage() &&
452 !WebAssembly::isWasmVarAddressSpace(G.getAddressSpace()) &&
453 G.getValueType()->isSized()) {
454 uint16_t Size = G.getGlobalSize(M.getDataLayout());
455 OutStreamer->emitELFSize(getSymbol(&G),
457 }
458 }
459
460 if (const NamedMDNode *Named = M.getNamedMetadata("wasm.custom_sections")) {
461 for (const Metadata *MD : Named->operands()) {
462 const auto *Tuple = dyn_cast<MDTuple>(MD);
463 if (!Tuple || Tuple->getNumOperands() != 2)
464 continue;
465 const MDString *Name = dyn_cast<MDString>(Tuple->getOperand(0));
466 const MDString *Contents = dyn_cast<MDString>(Tuple->getOperand(1));
467 if (!Name || !Contents)
468 continue;
469
470 OutStreamer->pushSection();
471 std::string SectionName = (".custom_section." + Name->getString()).str();
472 MCSectionWasm *MySection =
474 OutStreamer->switchSection(MySection);
475 OutStreamer->emitBytes(Contents->getString());
476 OutStreamer->popSection();
477 }
478 }
479
483}
484
487 if (const NamedMDNode *Debug = M.getNamedMetadata("llvm.dbg.cu")) {
488 llvm::SmallSet<StringRef, 4> SeenLanguages;
489 for (size_t I = 0, E = Debug->getNumOperands(); I < E; ++I) {
490 const auto *CU = cast<DICompileUnit>(Debug->getOperand(I));
491 StringRef Language =
492 dwarf::LanguageString(CU->getSourceLanguage().getUnversionedName());
493
494 Language.consume_front("DW_LANG_");
495 if (SeenLanguages.insert(Language).second)
496 Languages.emplace_back(Language.str(), "");
497 }
498 }
499
501 if (const NamedMDNode *Ident = M.getNamedMetadata("llvm.ident")) {
503 for (size_t I = 0, E = Ident->getNumOperands(); I < E; ++I) {
504 const auto *S = cast<MDString>(Ident->getOperand(I)->getOperand(0));
505 std::pair<StringRef, StringRef> Field = S->getString().split("version");
506 StringRef Name = Field.first.trim();
507 StringRef Version = Field.second.trim();
508 if (SeenTools.insert(Name).second)
509 Tools.emplace_back(Name.str(), Version.str());
510 }
511 }
512
513 int FieldCount = int(!Languages.empty()) + int(!Tools.empty());
514 if (FieldCount != 0) {
515 MCSectionWasm *Producers = OutContext.getWasmSection(
516 ".custom_section.producers", SectionKind::getMetadata());
517 OutStreamer->pushSection();
518 OutStreamer->switchSection(Producers);
519 OutStreamer->emitULEB128IntValue(FieldCount);
520 for (auto &Producers : {std::make_pair("language", &Languages),
521 std::make_pair("processed-by", &Tools)}) {
522 if (Producers.second->empty())
523 continue;
524 OutStreamer->emitULEB128IntValue(strlen(Producers.first));
525 OutStreamer->emitBytes(Producers.first);
526 OutStreamer->emitULEB128IntValue(Producers.second->size());
527 for (auto &Producer : *Producers.second) {
528 OutStreamer->emitULEB128IntValue(Producer.first.size());
529 OutStreamer->emitBytes(Producer.first);
530 OutStreamer->emitULEB128IntValue(Producer.second.size());
531 OutStreamer->emitBytes(Producer.second);
532 }
533 }
534 OutStreamer->popSection();
535 }
536}
537
539 struct FeatureEntry {
540 uint8_t Prefix;
541 std::string Name;
542 };
543
544 // Read target features and linkage policies from module metadata
545 SmallVector<FeatureEntry, 4> EmittedFeatures;
546 auto EmitFeature = [&](std::string Feature) {
547 std::string MDKey = (StringRef("wasm-feature-") + Feature).str();
548 Metadata *Policy = M.getModuleFlag(MDKey);
549 if (Policy == nullptr)
550 return;
551
552 FeatureEntry Entry;
553 Entry.Prefix = 0;
554 Entry.Name = Feature;
555
556 if (auto *MD = cast<ConstantAsMetadata>(Policy))
557 if (auto *I = cast<ConstantInt>(MD->getValue()))
558 Entry.Prefix = I->getZExtValue();
559
560 // Silently ignore invalid metadata
561 if (Entry.Prefix != wasm::WASM_FEATURE_PREFIX_USED &&
563 return;
564
565 EmittedFeatures.push_back(Entry);
566 };
567
568 // If we never compiled a single function, Subtarget is null.
569 if (!Subtarget) {
570 Subtarget = static_cast<WebAssemblyTargetMachine &>(TM).getSubtargetImpl(
571 std::string(TM.getTargetCPU()),
572 std::string(TM.getTargetFeatureString()));
573 }
574 for (const SubtargetFeatureKV &KV : Subtarget->getAllProcessorFeatures()) {
575 EmitFeature(KV.key());
576 }
577 // This pseudo-feature tells the linker whether shared memory would be safe
578 EmitFeature("shared-mem");
579
580 // This is an "architecture", not a "feature", but we emit it as such for
581 // the benefit of tools like Binaryen and consistency with other producers.
582 if (Subtarget->hasAddr64()) {
583 // Can't use EmitFeature since "wasm-feature-memory64" is not a module
584 // flag.
585 EmittedFeatures.push_back({wasm::WASM_FEATURE_PREFIX_USED, "memory64"});
586 }
587
588 if (EmittedFeatures.size() == 0)
589 return;
590
591 // Emit features and linkage policies into the "target_features" section
592 MCSectionWasm *FeaturesSection = OutContext.getWasmSection(
593 ".custom_section.target_features", SectionKind::getMetadata());
594 OutStreamer->pushSection();
595 OutStreamer->switchSection(FeaturesSection);
596
597 OutStreamer->emitULEB128IntValue(EmittedFeatures.size());
598 for (auto &F : EmittedFeatures) {
599 OutStreamer->emitIntValue(F.Prefix, 1);
600 OutStreamer->emitULEB128IntValue(F.Name.size());
601 OutStreamer->emitBytes(F.Name);
602 }
603
604 OutStreamer->popSection();
605}
606
608 auto V = M.getNamedGlobal("llvm.global.annotations");
609 if (!V)
610 return;
611
612 // Group all the custom attributes by name.
614 const ConstantArray *CA = cast<ConstantArray>(V->getOperand(0));
615 for (Value *Op : CA->operands()) {
616 auto *CS = cast<ConstantStruct>(Op);
617 // The first field is a pointer to the annotated variable.
618 Value *AnnotatedVar = CS->getOperand(0)->stripPointerCasts();
619 // Only annotated functions are supported for now.
620 if (!isa<Function>(AnnotatedVar))
621 continue;
622 auto *F = cast<Function>(AnnotatedVar);
623
624 // The second field is a pointer to a global annotation string.
625 auto *GV = cast<GlobalVariable>(CS->getOperand(1)->stripPointerCasts());
626 StringRef AnnotationString;
627 getConstantStringInfo(GV, AnnotationString);
628 auto *Sym = static_cast<MCSymbolWasm *>(getSymbol(F));
629 CustomSections[AnnotationString].push_back(Sym);
630 }
631
632 // Emit a custom section for each unique attribute.
633 for (const auto &[Name, Symbols] : CustomSections) {
634 MCSectionWasm *CustomSection = OutContext.getWasmSection(
635 ".custom_section.llvm.func_attr.annotate." + Name, SectionKind::getMetadata());
636 OutStreamer->pushSection();
637 OutStreamer->switchSection(CustomSection);
638
639 for (auto &Sym : Symbols) {
640 OutStreamer->emitValue(
642 4);
643 }
644 OutStreamer->popSection();
645 }
646}
647
649 emitDecls(*MMI->getModule());
650 assert(MF->getConstantPool()->getConstants().empty() &&
651 "WebAssembly disables constant pools");
652}
653
655 // Nothing to do; jump tables are incorporated into the instruction stream.
656}
657
659 const Function &F = MF->getFunction();
660 SmallVector<MVT, 1> ResultVTs;
661 SmallVector<MVT, 4> ParamVTs;
662 computeSignatureVTs(F.getFunctionType(), &F, F, TM, ParamVTs, ResultVTs);
663
664 auto Signature = signatureFromMVTs(OutContext, ResultVTs, ParamVTs);
665 auto *WasmSym = static_cast<MCSymbolWasm *>(CurrentFnSym);
666 WasmSym->setSignature(Signature);
667 WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
668
670
671 // Emit the function index.
672 if (MDNode *Idx = F.getMetadata("wasm.index")) {
673 assert(Idx->getNumOperands() == 1);
674
676 cast<ConstantAsMetadata>(Idx->getOperand(0))->getValue()));
677 }
678
680 valTypesFromMVTs(MFI->getLocals(), Locals);
681 getTargetStreamer()->emitLocal(Locals);
682
684}
685
687 LLVM_DEBUG(dbgs() << "EmitInstruction: " << *MI << '\n');
688 WebAssembly_MC::verifyInstructionPredicates(MI->getOpcode(),
689 Subtarget->getFeatureBits());
690
691 switch (MI->getOpcode()) {
692 case WebAssembly::ARGUMENT_i32:
693 case WebAssembly::ARGUMENT_i32_S:
694 case WebAssembly::ARGUMENT_i64:
695 case WebAssembly::ARGUMENT_i64_S:
696 case WebAssembly::ARGUMENT_f32:
697 case WebAssembly::ARGUMENT_f32_S:
698 case WebAssembly::ARGUMENT_f64:
699 case WebAssembly::ARGUMENT_f64_S:
700 case WebAssembly::ARGUMENT_v16i8:
701 case WebAssembly::ARGUMENT_v16i8_S:
702 case WebAssembly::ARGUMENT_v8i16:
703 case WebAssembly::ARGUMENT_v8i16_S:
704 case WebAssembly::ARGUMENT_v4i32:
705 case WebAssembly::ARGUMENT_v4i32_S:
706 case WebAssembly::ARGUMENT_v2i64:
707 case WebAssembly::ARGUMENT_v2i64_S:
708 case WebAssembly::ARGUMENT_v4f32:
709 case WebAssembly::ARGUMENT_v4f32_S:
710 case WebAssembly::ARGUMENT_v2f64:
711 case WebAssembly::ARGUMENT_v2f64_S:
712 case WebAssembly::ARGUMENT_v8f16:
713 case WebAssembly::ARGUMENT_v8f16_S:
714 case WebAssembly::ARGUMENT_externref:
715 case WebAssembly::ARGUMENT_externref_S:
716 case WebAssembly::ARGUMENT_funcref:
717 case WebAssembly::ARGUMENT_funcref_S:
718 case WebAssembly::ARGUMENT_exnref:
719 case WebAssembly::ARGUMENT_exnref_S:
720 // These represent values which are live into the function entry, so there's
721 // no instruction to emit.
722 break;
723 case WebAssembly::FALLTHROUGH_RETURN: {
724 // These instructions represent the implicit return at the end of a
725 // function body.
726 if (isVerbose()) {
727 OutStreamer->AddComment("fallthrough-return");
728 OutStreamer->addBlankLine();
729 }
730 break;
731 }
732 case WebAssembly::COMPILER_FENCE:
733 // This is a compiler barrier that prevents instruction reordering during
734 // backend compilation, and should not be emitted.
735 break;
736 case WebAssembly::CATCH:
737 case WebAssembly::CATCH_S:
738 case WebAssembly::CATCH_REF:
739 case WebAssembly::CATCH_REF_S:
740 case WebAssembly::CATCH_ALL:
741 case WebAssembly::CATCH_ALL_S:
742 case WebAssembly::CATCH_ALL_REF:
743 case WebAssembly::CATCH_ALL_REF_S:
744 // These are pseudo instructions to represent catch clauses in try_table
745 // instruction to simulate block return values.
746 break;
747 default: {
748 WebAssemblyMCInstLower MCInstLowering(OutContext, *this);
749 MCInst TmpInst;
750 MCInstLowering.lower(MI, TmpInst);
751 EmitToStreamer(*OutStreamer, TmpInst);
752 break;
753 }
754 }
755}
756
758 unsigned OpNo,
759 const char *ExtraCode,
760 raw_ostream &OS) {
761 // First try the generic code, which knows about modifiers like 'c' and 'n'.
762 if (!AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS))
763 return false;
764
765 if (!ExtraCode) {
766 const MachineOperand &MO = MI->getOperand(OpNo);
767 switch (MO.getType()) {
769 OS << MO.getImm();
770 return false;
772 // FIXME: only opcode that still contains registers, as required by
773 // MachineInstr::getDebugVariable().
774 assert(MI->getOpcode() == WebAssembly::INLINEASM);
775 OS << regToString(MO);
776 return false;
778 PrintSymbolOperand(MO, OS);
779 return false;
782 printOffset(MO.getOffset(), OS);
783 return false;
785 MO.getMBB()->getSymbol()->print(OS, MAI);
786 return false;
787 default:
788 break;
789 }
790 }
791
792 return true;
793}
794
796 unsigned OpNo,
797 const char *ExtraCode,
798 raw_ostream &OS) {
799 // The current approach to inline asm is that "r" constraints are expressed
800 // as local indices, rather than values on the operand stack. This simplifies
801 // using "r" as it eliminates the need to push and pop the values in a
802 // particular order, however it also makes it impossible to have an "m"
803 // constraint. So we don't support it.
804
805 return AsmPrinter::PrintAsmMemoryOperand(MI, OpNo, ExtraCode, OS);
806}
807
809
810INITIALIZE_PASS(WebAssemblyAsmPrinter, "webassembly-asm-printer",
811 "WebAssembly Assmebly Printer", false, false)
812
813// Force static initialization.
815LLVMInitializeWebAssemblyAsmPrinter() {
818}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
Function Alias Analysis Results
#define X(NUM, ENUM, NAME)
Definition ELF.h:856
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define LLVM_ABI
Definition Compiler.h:215
#define LLVM_EXTERNAL_VISIBILITY
Definition Compiler.h:132
IRTranslator LLVM IR MI
Module.h This file contains the declarations for the Module class.
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
#define G(x, y, z)
Definition MD5.cpp:55
This file declares the MachineConstantPool class which is an abstract constant pool to keep track of ...
Register const TargetRegisterInfo * TRI
This file implements a map that provides insertion order iteration.
This file contains the declarations for metadata subclasses.
#define T
OptimizedStructLayoutField Field
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
static StringRef getName(Value *V)
This file defines the SmallSet class.
This file contains some functions that are useful when dealing with strings.
#define LLVM_DEBUG(...)
Definition Debug.h:119
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
static std::string getEmscriptenInvokeSymbolName(wasm::WasmSignature *Sig)
static bool isEmscriptenInvokeName(StringRef Name)
static char getInvokeSig(wasm::ValType VT)
cl::opt< bool > WasmKeepRegisters
This file contains the declaration of the WebAssemblyMCAsmInfo class.
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 contains the WebAssembly implementation of the WebAssemblyRegisterInfo class.
This file provides signature information for runtime libcalls.
This file registers the WebAssembly target.
This file declares the WebAssembly-specific subclass of TargetMachine.
This file declares WebAssembly-specific target streamer classes.
This file contains the declaration of the WebAssembly-specific type parsing utility functions.
This file contains the declaration of the WebAssembly-specific utility functions.
This file contains the entry points for global functions defined in the LLVM WebAssembly back-end.
MCSymbol * getSymbol(const GlobalValue *GV) const
void EmitToStreamer(MCStreamer &S, const MCInst &Inst)
virtual void emitGlobalVariable(const GlobalVariable *GV)
Emit the specified global variable to the .s file.
TargetMachine & TM
Target machine description.
Definition AsmPrinter.h:94
virtual void PrintSymbolOperand(const MachineOperand &MO, raw_ostream &OS)
Print the MachineOperand as a symbol.
MachineFunction * MF
The current machine function.
Definition AsmPrinter.h:109
virtual const MCExpr * lowerConstant(const Constant *CV, const Constant *BaseCV=nullptr, uint64_t Offset=0)
Lower the specified LLVM Constant to an MCExpr.
virtual void emitFunctionBodyStart()
Targets can override this to emit stuff before the first basic block in the function.
Definition AsmPrinter.h:622
virtual void emitLinkage(const GlobalValue *GV, MCSymbol *GVSym) const
This emits linkage information about GVSym based on GV, if this is supported by the target.
void printOffset(int64_t Offset, raw_ostream &OS) const
This is just convenient handler for printing offsets.
MCSymbol * getSymbolPreferLocal(const GlobalValue &GV) const
Similar to getSymbol() but preferred for references.
MCSymbol * CurrentFnSym
The symbol for the current function.
Definition AsmPrinter.h:128
MachineModuleInfo * MMI
This is a pointer to the current MachineModuleInfo.
Definition AsmPrinter.h:112
MCContext & OutContext
This is the context for the output file that we are streaming.
Definition AsmPrinter.h:101
void emitVisibility(MCSymbol *Sym, unsigned Visibility, bool IsDefinition=true) const
This emits visibility information about symbol, if this is supported by the target.
std::unique_ptr< MCStreamer > OutStreamer
This is the MCStreamer object for the file we are generating.
Definition AsmPrinter.h:106
const MCAsmInfo & MAI
Target Asm Printer information.
Definition AsmPrinter.h:97
virtual bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, const char *ExtraCode, raw_ostream &OS)
Print the specified operand of MI, an INLINEASM instruction, using the specified assembler variant as...
bool isVerbose() const
Return true if assembly output should contain comments.
Definition AsmPrinter.h:310
MCSymbol * GetExternalSymbolSymbol(const Twine &Sym) const
Return the MCSymbol for the specified ExternalSymbol.
@ Debug
Emit .debug_frame.
Definition AsmPrinter.h:169
virtual bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, const char *ExtraCode, raw_ostream &OS)
Print the specified operand of MI, an INLINEASM instruction, using the specified assembler variant.
ConstantArray - Constant Array Declarations.
Definition Constants.h:590
Implements a dense probed hash-table based set.
Definition DenseSet.h:289
bool isThreadLocal() const
If the value is "Thread Local", its value isn't shared by the threads.
VisibilityTypes getVisibility() const
LLVM_ABI bool isDeclaration() const
Return true if the primary definition of this global value is outside of the current translation unit...
Definition Globals.cpp:346
unsigned getAddressSpace() const
Module * getParent()
Get the module that this global value is contained inside of...
LLVM_ABI const DataLayout & getDataLayout() const
Get the data layout of the module this global belongs to.
Definition Globals.cpp:143
bool hasCommonLinkage() const
Type * getValueType() const
bool hasInitializer() const
Definitions have initializers, declarations don't.
bool isConstant() const
If the value is a global constant, its value is immutable throughout the runtime execution of the pro...
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
This represents a section on wasm.
static const MCSymbolRefExpr * create(const MCSymbol *Symbol, MCContext &Ctx, SMLoc Loc=SMLoc())
Definition MCExpr.h:213
void setSignature(wasm::WasmSignature *Sig)
std::optional< wasm::WasmSymbolType > getType() const
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
Definition MCSymbol.h:42
LLVM_ABI void print(raw_ostream &OS, const MCAsmInfo *MAI) const
print - Print the value to the stream OS.
Definition MCSymbol.cpp:59
Target specific streamer interface.
Definition MCStreamer.h:95
Metadata node.
Definition Metadata.h:1069
A single uniqued string.
Definition Metadata.h:722
LLVM_ABI StringRef getString() const
Definition Metadata.cpp:632
Machine Value Type.
LLVM_ABI MCSymbol * getSymbol() const
Return the MCSymbol for this basic block.
Representation of each machine instruction.
MachineModuleInfoWasm - This is a MachineModuleInfoImpl implementation for Wasm targets.
SetVector< StringRef > MachineSymbolsUsed
MachineOperand class - Representation of each machine instruction operand.
int64_t getImm() const
MachineBasicBlock * getMBB() const
MachineOperandType getType() const
getType - Returns the MachineOperandType for this operand.
const char * getSymbolName() const
Register getReg() const
getReg - Returns the register number.
@ MO_Immediate
Immediate operand.
@ MO_GlobalAddress
Address of a global value.
@ MO_MachineBasicBlock
MachineBasicBlock reference.
@ MO_Register
Register operand.
@ MO_ExternalSymbol
Name of external global symbol.
int64_t getOffset() const
Return the offset from the symbol in this operand.
This class implements a map that also provides access to all stored values in a deterministic order.
Definition MapVector.h:38
Root of the metadata hierarchy.
Definition Metadata.h:64
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:67
LLVMContext & getContext() const
Get the global data context.
Definition Module.h:287
A tuple of MDNodes.
Definition Metadata.h:1742
Wrapper class representing virtual and physical registers.
Definition Register.h:20
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
Definition Register.h:79
Represents a location in source code.
Definition SMLoc.h:22
static SectionKind getMetadata()
SmallSet - This maintains a set of unique values, optimizing for the case when the set is small (less...
Definition SmallSet.h:134
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
Definition SmallSet.h:184
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
op_range operands()
Definition User.h:267
LLVM Value Representation.
Definition Value.h:75
LLVM_ABI const Value * stripPointerCasts() const
Strip off pointer casts, all-zero GEPs and address space casts.
Definition Value.cpp:713
void emitJumpTableInfo() override
Print assembly representations of the jump tables used by the current function to the current output ...
void emitGlobalVariable(const GlobalVariable *GV) override
Emit the specified global variable to the .s file.
bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, const char *ExtraCode, raw_ostream &OS) override
Print the specified operand of MI, an INLINEASM instruction, using the specified assembler variant as...
const WebAssemblySubtarget & getSubtarget() const
WebAssemblyTargetStreamer * getTargetStreamer()
void emitInstruction(const MachineInstr *MI) override
Targets should implement this to emit instructions.
std::string regToString(const MachineOperand &MO)
void emitSymbolType(const MCSymbolWasm *Sym)
MCSymbol * getOrCreateWasmSymbol(StringRef Name)
void emitConstantPool() override
Print to the current output stream assembly representations of the constants in the constant pool MCP...
MVT getRegType(unsigned RegNo) const
void emitFunctionBodyStart() override
Targets can override this to emit stuff before the first basic block in the function.
bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, const char *ExtraCode, raw_ostream &OS) override
Print the specified operand of MI, an INLINEASM instruction, using the specified assembler variant.
void emitEndOfAsmFile(Module &M) override
This virtual method can be overridden by targets that want to emit something at the end of their file...
MCSymbolWasm * getMCSymbolForFunction(const Function *F, wasm::WasmSignature *Sig, bool &InvokeDetected)
This class is used to lower an MachineInstr into an MCInst.
void lower(const MachineInstr *MI, MCInst &OutMI) const
WebAssembly-specific streamer interface, to implement support WebAssembly-specific assembly directive...
virtual void emitFunctionType(const MCSymbolWasm *Sym)=0
.functype
virtual void emitLocal(ArrayRef< wasm::ValType > Types)=0
.local
virtual void emitTagType(const MCSymbolWasm *Sym)=0
.tagtype
virtual void emitExportName(const MCSymbolWasm *Sym, StringRef ExportName)=0
.export_name
virtual void emitGlobalType(const MCSymbolWasm *Sym)=0
.globaltype
virtual void emitImportModule(const MCSymbolWasm *Sym, StringRef ImportModule)=0
.import_module
virtual void emitTableType(const MCSymbolWasm *Sym)=0
.tabletype
virtual void emitImportName(const MCSymbolWasm *Sym, StringRef ImportName)=0
.import_name
virtual void emitIndIdx(const MCExpr *Value)=0
.indidx
std::pair< iterator, bool > insert(const ValueT &V)
Definition DenseSet.h:212
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
LLVM_ABI StringRef LanguageString(unsigned Language)
Definition Dwarf.cpp:412
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
MCSymbolWasm * getOrCreateFunctionTableSymbol(MCContext &Ctx, const WebAssemblySubtarget *Subtarget)
Returns the __indirect_function_table, for use in call_indirect and in function bitcasts.
static const unsigned UnusedReg
cl::opt< bool > WasmEnableEmEH
void wasmSymbolSetType(MCSymbolWasm *Sym, const Type *GlobalVT, ArrayRef< MVT > VTs, bool Mutable)
Sets a Wasm Symbol Type.
cl::opt< bool > WasmEnableEmSjLj
std::string signatureToString(const wasm::WasmSignature *Sig)
void getLibcallSignature(const WebAssemblySubtarget &Subtarget, RTLIB::Libcall LC, SmallVectorImpl< wasm::ValType > &Rets, SmallVectorImpl< wasm::ValType > &Params)
bool isWasmVarAddressSpace(unsigned AS)
@ WASM_TYPE_I64
Definition Wasm.h:57
@ WASM_TYPE_I32
Definition Wasm.h:56
@ WASM_FEATURE_PREFIX_USED
Definition Wasm.h:189
@ WASM_FEATURE_PREFIX_DISALLOWED
Definition Wasm.h:190
@ WASM_SYMBOL_TYPE_GLOBAL
Definition Wasm.h:231
@ WASM_SYMBOL_TYPE_DATA
Definition Wasm.h:230
@ WASM_SYMBOL_TYPE_TAG
Definition Wasm.h:233
@ WASM_SYMBOL_TYPE_TABLE
Definition Wasm.h:234
@ 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
LLVM_ABI bool getConstantStringInfo(const Value *V, StringRef &Str, bool TrimAtNul=true)
This function computes the length of a null-terminated C string pointed to by V.
std::string utostr(uint64_t X, bool isNeg=false)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
Target & getTheWebAssemblyTarget32()
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
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.
Target & getTheWebAssemblyTarget64()
DWARFExpression::Operation Op
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)
@ MCSA_Weak
.weak
@ MCSA_NoDeadStrip
.no_dead_strip (MachO)
RegisterAsmPrinter - Helper template for registering a target specific assembly printer,...
Used to provide key value pairs for feature and CPU bit flags.
SmallVector< ValType, 1 > Returns
Definition Wasm.h:516
SmallVector< ValType, 4 > Params
Definition Wasm.h:517