1//===- WebAssemblyTargetMachine.cpp - Define TargetMachine for WebAssembly -==//
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 defines the WebAssembly-specific subclass of TargetMachine.
11///
12//===----------------------------------------------------------------------===//
13
14#include "WebAssemblyTargetMachine.h"
15#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
16#include "TargetInfo/WebAssemblyTargetInfo.h"
17#include "WebAssembly.h"
18#include "WebAssemblyISelLowering.h"
19#include "WebAssemblyMachineFunctionInfo.h"
20#include "WebAssemblyTargetObjectFile.h"
21#include "WebAssemblyTargetTransformInfo.h"
22#include "WebAssemblyUtilities.h"
23#include "llvm/CodeGen/MIRParser/MIParser.h"
24#include "llvm/CodeGen/MachineFunctionPass.h"
25#include "llvm/CodeGen/Passes.h"
26#include "llvm/CodeGen/RegAllocRegistry.h"
27#include "llvm/CodeGen/TargetPassConfig.h"
28#include "llvm/IR/Function.h"
29#include "llvm/InitializePasses.h"
30#include "llvm/MC/MCAsmInfo.h"
31#include "llvm/MC/TargetRegistry.h"
32#include "llvm/Target/TargetOptions.h"
33#include "llvm/Transforms/Scalar.h"
34#include "llvm/Transforms/Scalar/LowerAtomicPass.h"
35#include "llvm/Transforms/Utils.h"
36#include <optional>
37using namespace llvm;
38
39#define DEBUG_TYPE "wasm"
40
41// A command-line option to keep implicit locals
42// for the purpose of testing with lit/llc ONLY.
43// This produces output which is not valid WebAssembly, and is not supported
44// by assemblers/disassemblers and other MC based tools.
45static cl::opt<bool> WasmDisableExplicitLocals(
46 "wasm-disable-explicit-locals", cl::Hidden,
47 cl::desc("WebAssembly: output implicit locals in"
48 " instruction output for test purposes only."),
49 cl::init(Val: false));
50
51static cl::opt<bool> WasmDisableFixIrreducibleControlFlowPass(
52 "wasm-disable-fix-irreducible-control-flow-pass", cl::Hidden,
53 cl::desc("webassembly: disables the fix "
54 " irreducible control flow optimization pass"),
55 cl::init(Val: false));
56
57extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeWebAssemblyTarget() {
58 // Register the target.
59 RegisterTargetMachine<WebAssemblyTargetMachine> X(
60 getTheWebAssemblyTarget32());
61 RegisterTargetMachine<WebAssemblyTargetMachine> Y(
62 getTheWebAssemblyTarget64());
63
64 // Register backend passes
65 auto &PR = *PassRegistry::getPassRegistry();
66 initializeWebAssemblyAddMissingPrototypesPass(PR);
67 initializeWebAssemblyLowerEmscriptenEHSjLjPass(PR);
68 initializeLowerGlobalDtorsLegacyPassPass(PR);
69 initializeFixFunctionBitcastsPass(PR);
70 initializeOptimizeReturnedPass(PR);
71 initializeWebAssemblyRefTypeMem2LocalPass(PR);
72 initializeWebAssemblyArgumentMovePass(PR);
73 initializeWebAssemblySetP2AlignOperandsPass(PR);
74 initializeWebAssemblyReplacePhysRegsPass(PR);
75 initializeWebAssemblyOptimizeLiveIntervalsPass(PR);
76 initializeWebAssemblyMemIntrinsicResultsPass(PR);
77 initializeWebAssemblyRegStackifyPass(PR);
78 initializeWebAssemblyRegColoringPass(PR);
79 initializeWebAssemblyNullifyDebugValueListsPass(PR);
80 initializeWebAssemblyFixIrreducibleControlFlowPass(PR);
81 initializeWebAssemblyLateEHPreparePass(PR);
82 initializeWebAssemblyExceptionInfoPass(PR);
83 initializeWebAssemblyCFGSortPass(PR);
84 initializeWebAssemblyCFGStackifyPass(PR);
85 initializeWebAssemblyExplicitLocalsPass(PR);
86 initializeWebAssemblyLowerBrUnlessPass(PR);
87 initializeWebAssemblyRegNumberingPass(PR);
88 initializeWebAssemblyDebugFixupPass(PR);
89 initializeWebAssemblyPeepholePass(PR);
90 initializeWebAssemblyMCLowerPrePassPass(PR);
91 initializeWebAssemblyLowerRefTypesIntPtrConvPass(PR);
92 initializeWebAssemblyFixBrTableDefaultsPass(PR);
93 initializeWebAssemblyDAGToDAGISelPass(PR);
94}
95
96//===----------------------------------------------------------------------===//
97// WebAssembly Lowering public interface.
98//===----------------------------------------------------------------------===//
99
100static Reloc::Model getEffectiveRelocModel(std::optional<Reloc::Model> RM,
101 const Triple &TT) {
102 if (!RM) {
103 // Default to static relocation model. This should always be more optimial
104 // than PIC since the static linker can determine all global addresses and
105 // assume direct function calls.
106 return Reloc::Static;
107 }
108
109 return *RM;
110}
111
112/// Create an WebAssembly architecture model.
113///
114WebAssemblyTargetMachine::WebAssemblyTargetMachine(
115 const Target &T, const Triple &TT, StringRef CPU, StringRef FS,
116 const TargetOptions &Options, std::optional<Reloc::Model> RM,
117 std::optional<CodeModel::Model> CM, CodeGenOptLevel OL, bool JIT)
118 : LLVMTargetMachine(
119 T,
120 TT.isArch64Bit()
121 ? (TT.isOSEmscripten() ? "e-m:e-p:64:64-p10:8:8-p20:8:8-i64:64-"
122 "f128:64-n32:64-S128-ni:1:10:20"
123 : "e-m:e-p:64:64-p10:8:8-p20:8:8-i64:64-"
124 "n32:64-S128-ni:1:10:20")
125 : (TT.isOSEmscripten() ? "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-"
126 "f128:64-n32:64-S128-ni:1:10:20"
127 : "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-"
128 "n32:64-S128-ni:1:10:20"),
129 TT, CPU, FS, Options, getEffectiveRelocModel(RM, TT),
130 getEffectiveCodeModel(CM, Default: CodeModel::Large), OL),
131 TLOF(new WebAssemblyTargetObjectFile()),
132 UsesMultivalueABI(Options.MCOptions.getABIName() == "experimental-mv") {
133 // WebAssembly type-checks instructions, but a noreturn function with a return
134 // type that doesn't match the context will cause a check failure. So we lower
135 // LLVM 'unreachable' to ISD::TRAP and then lower that to WebAssembly's
136 // 'unreachable' instructions which is meant for that case.
137 this->Options.TrapUnreachable = true;
138 this->Options.NoTrapAfterNoreturn = false;
139
140 // WebAssembly treats each function as an independent unit. Force
141 // -ffunction-sections, effectively, so that we can emit them independently.
142 this->Options.FunctionSections = true;
143 this->Options.DataSections = true;
144 this->Options.UniqueSectionNames = true;
145
146 initAsmInfo();
147
148 // Note that we don't use setRequiresStructuredCFG(true). It disables
149 // optimizations than we're ok with, and want, such as critical edge
150 // splitting and tail merging.
151}
152
153WebAssemblyTargetMachine::~WebAssemblyTargetMachine() = default; // anchor.
154
155const WebAssemblySubtarget *WebAssemblyTargetMachine::getSubtargetImpl() const {
156 return getSubtargetImpl(CPU: std::string(getTargetCPU()),
157 FS: std::string(getTargetFeatureString()));
158}
159
160const WebAssemblySubtarget *
161WebAssemblyTargetMachine::getSubtargetImpl(std::string CPU,
162 std::string FS) const {
163 auto &I = SubtargetMap[CPU + FS];
164 if (!I) {
165 I = std::make_unique<WebAssemblySubtarget>(args: TargetTriple, args&: CPU, args&: FS, args: *this);
166 }
167 return I.get();
168}
169
170const WebAssemblySubtarget *
171WebAssemblyTargetMachine::getSubtargetImpl(const Function &F) const {
172 Attribute CPUAttr = F.getFnAttribute(Kind: "target-cpu");
173 Attribute FSAttr = F.getFnAttribute(Kind: "target-features");
174
175 std::string CPU =
176 CPUAttr.isValid() ? CPUAttr.getValueAsString().str() : TargetCPU;
177 std::string FS =
178 FSAttr.isValid() ? FSAttr.getValueAsString().str() : TargetFS;
179
180 // This needs to be done before we create a new subtarget since any
181 // creation will depend on the TM and the code generation flags on the
182 // function that reside in TargetOptions.
183 resetTargetOptions(F);
184
185 return getSubtargetImpl(CPU, FS);
186}
187
188namespace {
189
190class CoalesceFeaturesAndStripAtomics final : public ModulePass {
191 // Take the union of all features used in the module and use it for each
192 // function individually, since having multiple feature sets in one module
193 // currently does not make sense for WebAssembly. If atomics are not enabled,
194 // also strip atomic operations and thread local storage.
195 static char ID;
196 WebAssemblyTargetMachine *WasmTM;
197
198public:
199 CoalesceFeaturesAndStripAtomics(WebAssemblyTargetMachine *WasmTM)
200 : ModulePass(ID), WasmTM(WasmTM) {}
201
202 bool runOnModule(Module &M) override {
203 FeatureBitset Features = coalesceFeatures(M);
204
205 std::string FeatureStr =
206 getFeatureString(Features, TargetFS: WasmTM->getTargetFeatureString());
207 WasmTM->setTargetFeatureString(FeatureStr);
208 for (auto &F : M)
209 replaceFeatures(F, Features: FeatureStr);
210
211 bool StrippedAtomics = false;
212 bool StrippedTLS = false;
213
214 if (!Features[WebAssembly::FeatureAtomics]) {
215 StrippedAtomics = stripAtomics(M);
216 StrippedTLS = stripThreadLocals(M);
217 } else if (!Features[WebAssembly::FeatureBulkMemory]) {
218 StrippedTLS |= stripThreadLocals(M);
219 }
220
221 if (StrippedAtomics && !StrippedTLS)
222 stripThreadLocals(M);
223 else if (StrippedTLS && !StrippedAtomics)
224 stripAtomics(M);
225
226 recordFeatures(M, Features, Stripped: StrippedAtomics || StrippedTLS);
227
228 // Conservatively assume we have made some change
229 return true;
230 }
231
232private:
233 FeatureBitset coalesceFeatures(const Module &M) {
234 FeatureBitset Features =
235 WasmTM
236 ->getSubtargetImpl(CPU: std::string(WasmTM->getTargetCPU()),
237 FS: std::string(WasmTM->getTargetFeatureString()))
238 ->getFeatureBits();
239 for (auto &F : M)
240 Features |= WasmTM->getSubtargetImpl(F)->getFeatureBits();
241 return Features;
242 }
243
244 static std::string getFeatureString(const FeatureBitset &Features,
245 StringRef TargetFS) {
246 std::string Ret;
247 for (const SubtargetFeatureKV &KV : WebAssemblyFeatureKV) {
248 if (Features[KV.Value])
249 Ret += (StringRef("+") + KV.Key + ",").str();
250 }
251 SubtargetFeatures TF{TargetFS};
252 for (std::string const &F : TF.getFeatures())
253 if (!SubtargetFeatures::isEnabled(Feature: F))
254 Ret += F + ",";
255 return Ret;
256 }
257
258 void replaceFeatures(Function &F, const std::string &Features) {
259 F.removeFnAttr(Kind: "target-features");
260 F.removeFnAttr(Kind: "target-cpu");
261 F.addFnAttr(Kind: "target-features", Val: Features);
262 }
263
264 bool stripAtomics(Module &M) {
265 // Detect whether any atomics will be lowered, since there is no way to tell
266 // whether the LowerAtomic pass lowers e.g. stores.
267 bool Stripped = false;
268 for (auto &F : M) {
269 for (auto &B : F) {
270 for (auto &I : B) {
271 if (I.isAtomic()) {
272 Stripped = true;
273 goto done;
274 }
275 }
276 }
277 }
278
279 done:
280 if (!Stripped)
281 return false;
282
283 LowerAtomicPass Lowerer;
284 FunctionAnalysisManager FAM;
285 for (auto &F : M)
286 Lowerer.run(F, FAM);
287
288 return true;
289 }
290
291 bool stripThreadLocals(Module &M) {
292 bool Stripped = false;
293 for (auto &GV : M.globals()) {
294 if (GV.isThreadLocal()) {
295 // replace `@llvm.threadlocal.address.pX(GV)` with `GV`.
296 for (Use &U : make_early_inc_range(Range: GV.uses())) {
297 if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(Val: U.getUser())) {
298 if (II->getIntrinsicID() == Intrinsic::threadlocal_address &&
299 II->getArgOperand(i: 0) == &GV) {
300 II->replaceAllUsesWith(V: &GV);
301 II->eraseFromParent();
302 }
303 }
304 }
305
306 Stripped = true;
307 GV.setThreadLocal(false);
308 }
309 }
310 return Stripped;
311 }
312
313 void recordFeatures(Module &M, const FeatureBitset &Features, bool Stripped) {
314 for (const SubtargetFeatureKV &KV : WebAssemblyFeatureKV) {
315 if (Features[KV.Value]) {
316 // Mark features as used
317 std::string MDKey = (StringRef("wasm-feature-") + KV.Key).str();
318 M.addModuleFlag(Module::ModFlagBehavior::Error, MDKey,
319 wasm::WASM_FEATURE_PREFIX_USED);
320 }
321 }
322 // Code compiled without atomics or bulk-memory may have had its atomics or
323 // thread-local data lowered to nonatomic operations or non-thread-local
324 // data. In that case, we mark the pseudo-feature "shared-mem" as disallowed
325 // to tell the linker that it would be unsafe to allow this code ot be used
326 // in a module with shared memory.
327 if (Stripped) {
328 M.addModuleFlag(Behavior: Module::ModFlagBehavior::Error, Key: "wasm-feature-shared-mem",
329 Val: wasm::WASM_FEATURE_PREFIX_DISALLOWED);
330 }
331 }
332};
333char CoalesceFeaturesAndStripAtomics::ID = 0;
334
335/// WebAssembly Code Generator Pass Configuration Options.
336class WebAssemblyPassConfig final : public TargetPassConfig {
337public:
338 WebAssemblyPassConfig(WebAssemblyTargetMachine &TM, PassManagerBase &PM)
339 : TargetPassConfig(TM, PM) {}
340
341 WebAssemblyTargetMachine &getWebAssemblyTargetMachine() const {
342 return getTM<WebAssemblyTargetMachine>();
343 }
344
345 FunctionPass *createTargetRegisterAllocator(bool) override;
346
347 void addIRPasses() override;
348 void addISelPrepare() override;
349 bool addInstSelector() override;
350 void addOptimizedRegAlloc() override;
351 void addPostRegAlloc() override;
352 bool addGCPasses() override { return false; }
353 void addPreEmitPass() override;
354 bool addPreISel() override;
355
356 // No reg alloc
357 bool addRegAssignAndRewriteFast() override { return false; }
358
359 // No reg alloc
360 bool addRegAssignAndRewriteOptimized() override { return false; }
361};
362} // end anonymous namespace
363
364MachineFunctionInfo *WebAssemblyTargetMachine::createMachineFunctionInfo(
365 BumpPtrAllocator &Allocator, const Function &F,
366 const TargetSubtargetInfo *STI) const {
367 return WebAssemblyFunctionInfo::create<WebAssemblyFunctionInfo>(Allocator, F,
368 STI);
369}
370
371TargetTransformInfo
372WebAssemblyTargetMachine::getTargetTransformInfo(const Function &F) const {
373 return TargetTransformInfo(WebAssemblyTTIImpl(this, F));
374}
375
376TargetPassConfig *
377WebAssemblyTargetMachine::createPassConfig(PassManagerBase &PM) {
378 return new WebAssemblyPassConfig(*this, PM);
379}
380
381FunctionPass *WebAssemblyPassConfig::createTargetRegisterAllocator(bool) {
382 return nullptr; // No reg alloc
383}
384
385using WebAssembly::WasmEnableEH;
386using WebAssembly::WasmEnableEmEH;
387using WebAssembly::WasmEnableEmSjLj;
388using WebAssembly::WasmEnableSjLj;
389
390static void basicCheckForEHAndSjLj(TargetMachine *TM) {
391 // Before checking, we make sure TargetOptions.ExceptionModel is the same as
392 // MCAsmInfo.ExceptionsType. Normally these have to be the same, because clang
393 // stores the exception model info in LangOptions, which is later transferred
394 // to TargetOptions and MCAsmInfo. But when clang compiles bitcode directly,
395 // clang's LangOptions is not used and thus the exception model info is not
396 // correctly transferred to TargetOptions and MCAsmInfo, so we make sure we
397 // have the correct exception model in WebAssemblyMCAsmInfo constructor.
398 // But in this case TargetOptions is still not updated, so we make sure they
399 // are the same.
400 TM->Options.ExceptionModel = TM->getMCAsmInfo()->getExceptionHandlingType();
401
402 // Basic Correctness checking related to -exception-model
403 if (TM->Options.ExceptionModel != ExceptionHandling::None &&
404 TM->Options.ExceptionModel != ExceptionHandling::Wasm)
405 report_fatal_error(reason: "-exception-model should be either 'none' or 'wasm'");
406 if (WasmEnableEmEH && TM->Options.ExceptionModel == ExceptionHandling::Wasm)
407 report_fatal_error(reason: "-exception-model=wasm not allowed with "
408 "-enable-emscripten-cxx-exceptions");
409 if (WasmEnableEH && TM->Options.ExceptionModel != ExceptionHandling::Wasm)
410 report_fatal_error(
411 reason: "-wasm-enable-eh only allowed with -exception-model=wasm");
412 if (WasmEnableSjLj && TM->Options.ExceptionModel != ExceptionHandling::Wasm)
413 report_fatal_error(
414 reason: "-wasm-enable-sjlj only allowed with -exception-model=wasm");
415 if ((!WasmEnableEH && !WasmEnableSjLj) &&
416 TM->Options.ExceptionModel == ExceptionHandling::Wasm)
417 report_fatal_error(
418 reason: "-exception-model=wasm only allowed with at least one of "
419 "-wasm-enable-eh or -wasm-enable-sjlj");
420
421 // You can't enable two modes of EH at the same time
422 if (WasmEnableEmEH && WasmEnableEH)
423 report_fatal_error(
424 reason: "-enable-emscripten-cxx-exceptions not allowed with -wasm-enable-eh");
425 // You can't enable two modes of SjLj at the same time
426 if (WasmEnableEmSjLj && WasmEnableSjLj)
427 report_fatal_error(
428 reason: "-enable-emscripten-sjlj not allowed with -wasm-enable-sjlj");
429 // You can't mix Emscripten EH with Wasm SjLj.
430 if (WasmEnableEmEH && WasmEnableSjLj)
431 report_fatal_error(
432 reason: "-enable-emscripten-cxx-exceptions not allowed with -wasm-enable-sjlj");
433 // Currently it is allowed to mix Wasm EH with Emscripten SjLj as an interim
434 // measure, but some code will error out at compile time in this combination.
435 // See WebAssemblyLowerEmscriptenEHSjLj pass for details.
436}
437
438//===----------------------------------------------------------------------===//
439// The following functions are called from lib/CodeGen/Passes.cpp to modify
440// the CodeGen pass sequence.
441//===----------------------------------------------------------------------===//
442
443void WebAssemblyPassConfig::addIRPasses() {
444 // Add signatures to prototype-less function declarations
445 addPass(P: createWebAssemblyAddMissingPrototypes());
446
447 // Lower .llvm.global_dtors into .llvm.global_ctors with __cxa_atexit calls.
448 addPass(P: createLowerGlobalDtorsLegacyPass());
449
450 // Fix function bitcasts, as WebAssembly requires caller and callee signatures
451 // to match.
452 addPass(P: createWebAssemblyFixFunctionBitcasts());
453
454 // Optimize "returned" function attributes.
455 if (getOptLevel() != CodeGenOptLevel::None)
456 addPass(P: createWebAssemblyOptimizeReturned());
457
458 basicCheckForEHAndSjLj(TM);
459
460 // If exception handling is not enabled and setjmp/longjmp handling is
461 // enabled, we lower invokes into calls and delete unreachable landingpad
462 // blocks. Lowering invokes when there is no EH support is done in
463 // TargetPassConfig::addPassesToHandleExceptions, but that runs after these IR
464 // passes and Emscripten SjLj handling expects all invokes to be lowered
465 // before.
466 if (!WasmEnableEmEH && !WasmEnableEH) {
467 addPass(P: createLowerInvokePass());
468 // The lower invoke pass may create unreachable code. Remove it in order not
469 // to process dead blocks in setjmp/longjmp handling.
470 addPass(P: createUnreachableBlockEliminationPass());
471 }
472
473 // Handle exceptions and setjmp/longjmp if enabled. Unlike Wasm EH preparation
474 // done in WasmEHPrepare pass, Wasm SjLj preparation shares libraries and
475 // transformation algorithms with Emscripten SjLj, so we run
476 // LowerEmscriptenEHSjLj pass also when Wasm SjLj is enabled.
477 if (WasmEnableEmEH || WasmEnableEmSjLj || WasmEnableSjLj)
478 addPass(P: createWebAssemblyLowerEmscriptenEHSjLj());
479
480 // Expand indirectbr instructions to switches.
481 addPass(P: createIndirectBrExpandPass());
482
483 TargetPassConfig::addIRPasses();
484}
485
486void WebAssemblyPassConfig::addISelPrepare() {
487 // We need to move reference type allocas to WASM_ADDRESS_SPACE_VAR so that
488 // loads and stores are promoted to local.gets/local.sets.
489 addPass(P: createWebAssemblyRefTypeMem2Local());
490 // Lower atomics and TLS if necessary
491 addPass(P: new CoalesceFeaturesAndStripAtomics(&getWebAssemblyTargetMachine()));
492
493 // This is a no-op if atomics are not used in the module
494 addPass(P: createAtomicExpandLegacyPass());
495
496 TargetPassConfig::addISelPrepare();
497}
498
499bool WebAssemblyPassConfig::addInstSelector() {
500 (void)TargetPassConfig::addInstSelector();
501 addPass(
502 P: createWebAssemblyISelDag(TM&: getWebAssemblyTargetMachine(), OptLevel: getOptLevel()));
503 // Run the argument-move pass immediately after the ScheduleDAG scheduler
504 // so that we can fix up the ARGUMENT instructions before anything else
505 // sees them in the wrong place.
506 addPass(P: createWebAssemblyArgumentMove());
507 // Set the p2align operands. This information is present during ISel, however
508 // it's inconvenient to collect. Collect it now, and update the immediate
509 // operands.
510 addPass(P: createWebAssemblySetP2AlignOperands());
511
512 // Eliminate range checks and add default targets to br_table instructions.
513 addPass(P: createWebAssemblyFixBrTableDefaults());
514
515 return false;
516}
517
518void WebAssemblyPassConfig::addOptimizedRegAlloc() {
519 // Currently RegisterCoalesce degrades wasm debug info quality by a
520 // significant margin. As a quick fix, disable this for -O1, which is often
521 // used for debugging large applications. Disabling this increases code size
522 // of Emscripten core benchmarks by ~5%, which is acceptable for -O1, which is
523 // usually not used for production builds.
524 // TODO Investigate why RegisterCoalesce degrades debug info quality and fix
525 // it properly
526 if (getOptLevel() == CodeGenOptLevel::Less)
527 disablePass(PassID: &RegisterCoalescerID);
528 TargetPassConfig::addOptimizedRegAlloc();
529}
530
531void WebAssemblyPassConfig::addPostRegAlloc() {
532 // TODO: The following CodeGen passes don't currently support code containing
533 // virtual registers. Consider removing their restrictions and re-enabling
534 // them.
535
536 // These functions all require the NoVRegs property.
537 disablePass(PassID: &MachineLateInstrsCleanupID);
538 disablePass(PassID: &MachineCopyPropagationID);
539 disablePass(PassID: &PostRAMachineSinkingID);
540 disablePass(PassID: &PostRASchedulerID);
541 disablePass(PassID: &FuncletLayoutID);
542 disablePass(PassID: &StackMapLivenessID);
543 disablePass(PassID: &PatchableFunctionID);
544 disablePass(PassID: &ShrinkWrapID);
545
546 // This pass hurts code size for wasm because it can generate irreducible
547 // control flow.
548 disablePass(PassID: &MachineBlockPlacementID);
549
550 TargetPassConfig::addPostRegAlloc();
551}
552
553void WebAssemblyPassConfig::addPreEmitPass() {
554 TargetPassConfig::addPreEmitPass();
555
556 // Nullify DBG_VALUE_LISTs that we cannot handle.
557 addPass(P: createWebAssemblyNullifyDebugValueLists());
558
559 // Eliminate multiple-entry loops.
560 if (!WasmDisableFixIrreducibleControlFlowPass)
561 addPass(P: createWebAssemblyFixIrreducibleControlFlow());
562
563 // Do various transformations for exception handling.
564 // Every CFG-changing optimizations should come before this.
565 if (TM->Options.ExceptionModel == ExceptionHandling::Wasm)
566 addPass(P: createWebAssemblyLateEHPrepare());
567
568 // Now that we have a prologue and epilogue and all frame indices are
569 // rewritten, eliminate SP and FP. This allows them to be stackified,
570 // colored, and numbered with the rest of the registers.
571 addPass(P: createWebAssemblyReplacePhysRegs());
572
573 // Preparations and optimizations related to register stackification.
574 if (getOptLevel() != CodeGenOptLevel::None) {
575 // Depend on LiveIntervals and perform some optimizations on it.
576 addPass(P: createWebAssemblyOptimizeLiveIntervals());
577
578 // Prepare memory intrinsic calls for register stackifying.
579 addPass(P: createWebAssemblyMemIntrinsicResults());
580
581 // Mark registers as representing wasm's value stack. This is a key
582 // code-compression technique in WebAssembly. We run this pass (and
583 // MemIntrinsicResults above) very late, so that it sees as much code as
584 // possible, including code emitted by PEI and expanded by late tail
585 // duplication.
586 addPass(P: createWebAssemblyRegStackify());
587
588 // Run the register coloring pass to reduce the total number of registers.
589 // This runs after stackification so that it doesn't consider registers
590 // that become stackified.
591 addPass(P: createWebAssemblyRegColoring());
592 }
593
594 // Sort the blocks of the CFG into topological order, a prerequisite for
595 // BLOCK and LOOP markers.
596 addPass(P: createWebAssemblyCFGSort());
597
598 // Insert BLOCK and LOOP markers.
599 addPass(P: createWebAssemblyCFGStackify());
600
601 // Insert explicit local.get and local.set operators.
602 if (!WasmDisableExplicitLocals)
603 addPass(P: createWebAssemblyExplicitLocals());
604
605 // Lower br_unless into br_if.
606 addPass(P: createWebAssemblyLowerBrUnless());
607
608 // Perform the very last peephole optimizations on the code.
609 if (getOptLevel() != CodeGenOptLevel::None)
610 addPass(P: createWebAssemblyPeephole());
611
612 // Create a mapping from LLVM CodeGen virtual registers to wasm registers.
613 addPass(P: createWebAssemblyRegNumbering());
614
615 // Fix debug_values whose defs have been stackified.
616 if (!WasmDisableExplicitLocals)
617 addPass(P: createWebAssemblyDebugFixup());
618
619 // Collect information to prepare for MC lowering / asm printing.
620 addPass(P: createWebAssemblyMCLowerPrePass());
621}
622
623bool WebAssemblyPassConfig::addPreISel() {
624 TargetPassConfig::addPreISel();
625 addPass(P: createWebAssemblyLowerRefTypesIntPtrConv());
626 return false;
627}
628
629yaml::MachineFunctionInfo *
630WebAssemblyTargetMachine::createDefaultFuncInfoYAML() const {
631 return new yaml::WebAssemblyFunctionInfo();
632}
633
634yaml::MachineFunctionInfo *WebAssemblyTargetMachine::convertFuncInfoToYAML(
635 const MachineFunction &MF) const {
636 const auto *MFI = MF.getInfo<WebAssemblyFunctionInfo>();
637 return new yaml::WebAssemblyFunctionInfo(MF, *MFI);
638}
639
640bool WebAssemblyTargetMachine::parseMachineFunctionInfo(
641 const yaml::MachineFunctionInfo &MFI, PerFunctionMIParsingState &PFS,
642 SMDiagnostic &Error, SMRange &SourceRange) const {
643 const auto &YamlMFI = static_cast<const yaml::WebAssemblyFunctionInfo &>(MFI);
644 MachineFunction &MF = PFS.MF;
645 MF.getInfo<WebAssemblyFunctionInfo>()->initializeBaseYamlFields(MF, YamlMFI);
646 return false;
647}
648

source code of llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp