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 initializeWebAssemblyDAGToDAGISelLegacyPass(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(Behavior: Module::ModFlagBehavior::Error, Key: MDKey,
319 Val: 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::WasmEnableExnref;
389using WebAssembly::WasmEnableSjLj;
390
391static void basicCheckForEHAndSjLj(TargetMachine *TM) {
392
393 // You can't enable two modes of EH at the same time
394 if (WasmEnableEmEH && WasmEnableEH)
395 report_fatal_error(
396 reason: "-enable-emscripten-cxx-exceptions not allowed with -wasm-enable-eh");
397 // You can't enable two modes of SjLj at the same time
398 if (WasmEnableEmSjLj && WasmEnableSjLj)
399 report_fatal_error(
400 reason: "-enable-emscripten-sjlj not allowed with -wasm-enable-sjlj");
401 // You can't mix Emscripten EH with Wasm SjLj.
402 if (WasmEnableEmEH && WasmEnableSjLj)
403 report_fatal_error(
404 reason: "-enable-emscripten-cxx-exceptions not allowed with -wasm-enable-sjlj");
405 if (WasmEnableExnref && !WasmEnableEH)
406 report_fatal_error(
407 reason: "-wasm-enable-exnref should be used with -wasm-enable-eh");
408
409 // Here we make sure TargetOptions.ExceptionModel is the same as
410 // MCAsmInfo.ExceptionsType. Normally these have to be the same, because clang
411 // stores the exception model info in LangOptions, which is later transferred
412 // to TargetOptions and MCAsmInfo. But when clang compiles bitcode directly,
413 // clang's LangOptions is not used and thus the exception model info is not
414 // correctly transferred to TargetOptions and MCAsmInfo, so we make sure we
415 // have the correct exception model in WebAssemblyMCAsmInfo constructor. But
416 // in this case TargetOptions is still not updated, so we make sure they are
417 // the same.
418 TM->Options.ExceptionModel = TM->getMCAsmInfo()->getExceptionHandlingType();
419
420 // Basic Correctness checking related to -exception-model
421 if (TM->Options.ExceptionModel != ExceptionHandling::None &&
422 TM->Options.ExceptionModel != ExceptionHandling::Wasm)
423 report_fatal_error(reason: "-exception-model should be either 'none' or 'wasm'");
424 if (WasmEnableEmEH && TM->Options.ExceptionModel == ExceptionHandling::Wasm)
425 report_fatal_error(reason: "-exception-model=wasm not allowed with "
426 "-enable-emscripten-cxx-exceptions");
427 if (WasmEnableEH && TM->Options.ExceptionModel != ExceptionHandling::Wasm)
428 report_fatal_error(
429 reason: "-wasm-enable-eh only allowed with -exception-model=wasm");
430 if (WasmEnableSjLj && TM->Options.ExceptionModel != ExceptionHandling::Wasm)
431 report_fatal_error(
432 reason: "-wasm-enable-sjlj only allowed with -exception-model=wasm");
433 if ((!WasmEnableEH && !WasmEnableSjLj) &&
434 TM->Options.ExceptionModel == ExceptionHandling::Wasm)
435 report_fatal_error(
436 reason: "-exception-model=wasm only allowed with at least one of "
437 "-wasm-enable-eh or -wasm-enable-sjlj");
438
439 // Currently it is allowed to mix Wasm EH with Emscripten SjLj as an interim
440 // measure, but some code will error out at compile time in this combination.
441 // See WebAssemblyLowerEmscriptenEHSjLj pass for details.
442}
443
444//===----------------------------------------------------------------------===//
445// The following functions are called from lib/CodeGen/Passes.cpp to modify
446// the CodeGen pass sequence.
447//===----------------------------------------------------------------------===//
448
449void WebAssemblyPassConfig::addIRPasses() {
450 // Add signatures to prototype-less function declarations
451 addPass(P: createWebAssemblyAddMissingPrototypes());
452
453 // Lower .llvm.global_dtors into .llvm.global_ctors with __cxa_atexit calls.
454 addPass(P: createLowerGlobalDtorsLegacyPass());
455
456 // Fix function bitcasts, as WebAssembly requires caller and callee signatures
457 // to match.
458 addPass(P: createWebAssemblyFixFunctionBitcasts());
459
460 // Optimize "returned" function attributes.
461 if (getOptLevel() != CodeGenOptLevel::None)
462 addPass(P: createWebAssemblyOptimizeReturned());
463
464 basicCheckForEHAndSjLj(TM);
465
466 // If exception handling is not enabled and setjmp/longjmp handling is
467 // enabled, we lower invokes into calls and delete unreachable landingpad
468 // blocks. Lowering invokes when there is no EH support is done in
469 // TargetPassConfig::addPassesToHandleExceptions, but that runs after these IR
470 // passes and Emscripten SjLj handling expects all invokes to be lowered
471 // before.
472 if (!WasmEnableEmEH && !WasmEnableEH) {
473 addPass(P: createLowerInvokePass());
474 // The lower invoke pass may create unreachable code. Remove it in order not
475 // to process dead blocks in setjmp/longjmp handling.
476 addPass(P: createUnreachableBlockEliminationPass());
477 }
478
479 // Handle exceptions and setjmp/longjmp if enabled. Unlike Wasm EH preparation
480 // done in WasmEHPrepare pass, Wasm SjLj preparation shares libraries and
481 // transformation algorithms with Emscripten SjLj, so we run
482 // LowerEmscriptenEHSjLj pass also when Wasm SjLj is enabled.
483 if (WasmEnableEmEH || WasmEnableEmSjLj || WasmEnableSjLj)
484 addPass(P: createWebAssemblyLowerEmscriptenEHSjLj());
485
486 // Expand indirectbr instructions to switches.
487 addPass(P: createIndirectBrExpandPass());
488
489 TargetPassConfig::addIRPasses();
490}
491
492void WebAssemblyPassConfig::addISelPrepare() {
493 // We need to move reference type allocas to WASM_ADDRESS_SPACE_VAR so that
494 // loads and stores are promoted to local.gets/local.sets.
495 addPass(P: createWebAssemblyRefTypeMem2Local());
496 // Lower atomics and TLS if necessary
497 addPass(P: new CoalesceFeaturesAndStripAtomics(&getWebAssemblyTargetMachine()));
498
499 // This is a no-op if atomics are not used in the module
500 addPass(P: createAtomicExpandLegacyPass());
501
502 TargetPassConfig::addISelPrepare();
503}
504
505bool WebAssemblyPassConfig::addInstSelector() {
506 (void)TargetPassConfig::addInstSelector();
507 addPass(
508 P: createWebAssemblyISelDag(TM&: getWebAssemblyTargetMachine(), OptLevel: getOptLevel()));
509 // Run the argument-move pass immediately after the ScheduleDAG scheduler
510 // so that we can fix up the ARGUMENT instructions before anything else
511 // sees them in the wrong place.
512 addPass(P: createWebAssemblyArgumentMove());
513 // Set the p2align operands. This information is present during ISel, however
514 // it's inconvenient to collect. Collect it now, and update the immediate
515 // operands.
516 addPass(P: createWebAssemblySetP2AlignOperands());
517
518 // Eliminate range checks and add default targets to br_table instructions.
519 addPass(P: createWebAssemblyFixBrTableDefaults());
520
521 // unreachable is terminator, non-terminator instruction after it is not
522 // allowed.
523 addPass(P: createWebAssemblyCleanCodeAfterTrap());
524
525 return false;
526}
527
528void WebAssemblyPassConfig::addOptimizedRegAlloc() {
529 // Currently RegisterCoalesce degrades wasm debug info quality by a
530 // significant margin. As a quick fix, disable this for -O1, which is often
531 // used for debugging large applications. Disabling this increases code size
532 // of Emscripten core benchmarks by ~5%, which is acceptable for -O1, which is
533 // usually not used for production builds.
534 // TODO Investigate why RegisterCoalesce degrades debug info quality and fix
535 // it properly
536 if (getOptLevel() == CodeGenOptLevel::Less)
537 disablePass(PassID: &RegisterCoalescerID);
538 TargetPassConfig::addOptimizedRegAlloc();
539}
540
541void WebAssemblyPassConfig::addPostRegAlloc() {
542 // TODO: The following CodeGen passes don't currently support code containing
543 // virtual registers. Consider removing their restrictions and re-enabling
544 // them.
545
546 // These functions all require the NoVRegs property.
547 disablePass(PassID: &MachineLateInstrsCleanupID);
548 disablePass(PassID: &MachineCopyPropagationID);
549 disablePass(PassID: &PostRAMachineSinkingID);
550 disablePass(PassID: &PostRASchedulerID);
551 disablePass(PassID: &FuncletLayoutID);
552 disablePass(PassID: &StackMapLivenessID);
553 disablePass(PassID: &PatchableFunctionID);
554 disablePass(PassID: &ShrinkWrapID);
555
556 // This pass hurts code size for wasm because it can generate irreducible
557 // control flow.
558 disablePass(PassID: &MachineBlockPlacementID);
559
560 TargetPassConfig::addPostRegAlloc();
561}
562
563void WebAssemblyPassConfig::addPreEmitPass() {
564 TargetPassConfig::addPreEmitPass();
565
566 // Nullify DBG_VALUE_LISTs that we cannot handle.
567 addPass(P: createWebAssemblyNullifyDebugValueLists());
568
569 // Eliminate multiple-entry loops.
570 if (!WasmDisableFixIrreducibleControlFlowPass)
571 addPass(P: createWebAssemblyFixIrreducibleControlFlow());
572
573 // Do various transformations for exception handling.
574 // Every CFG-changing optimizations should come before this.
575 if (TM->Options.ExceptionModel == ExceptionHandling::Wasm)
576 addPass(P: createWebAssemblyLateEHPrepare());
577
578 // Now that we have a prologue and epilogue and all frame indices are
579 // rewritten, eliminate SP and FP. This allows them to be stackified,
580 // colored, and numbered with the rest of the registers.
581 addPass(P: createWebAssemblyReplacePhysRegs());
582
583 // Preparations and optimizations related to register stackification.
584 if (getOptLevel() != CodeGenOptLevel::None) {
585 // Depend on LiveIntervals and perform some optimizations on it.
586 addPass(P: createWebAssemblyOptimizeLiveIntervals());
587
588 // Prepare memory intrinsic calls for register stackifying.
589 addPass(P: createWebAssemblyMemIntrinsicResults());
590
591 // Mark registers as representing wasm's value stack. This is a key
592 // code-compression technique in WebAssembly. We run this pass (and
593 // MemIntrinsicResults above) very late, so that it sees as much code as
594 // possible, including code emitted by PEI and expanded by late tail
595 // duplication.
596 addPass(P: createWebAssemblyRegStackify());
597
598 // Run the register coloring pass to reduce the total number of registers.
599 // This runs after stackification so that it doesn't consider registers
600 // that become stackified.
601 addPass(P: createWebAssemblyRegColoring());
602 }
603
604 // Sort the blocks of the CFG into topological order, a prerequisite for
605 // BLOCK and LOOP markers.
606 addPass(P: createWebAssemblyCFGSort());
607
608 // Insert BLOCK and LOOP markers.
609 addPass(P: createWebAssemblyCFGStackify());
610
611 // Insert explicit local.get and local.set operators.
612 if (!WasmDisableExplicitLocals)
613 addPass(P: createWebAssemblyExplicitLocals());
614
615 // Lower br_unless into br_if.
616 addPass(P: createWebAssemblyLowerBrUnless());
617
618 // Perform the very last peephole optimizations on the code.
619 if (getOptLevel() != CodeGenOptLevel::None)
620 addPass(P: createWebAssemblyPeephole());
621
622 // Create a mapping from LLVM CodeGen virtual registers to wasm registers.
623 addPass(P: createWebAssemblyRegNumbering());
624
625 // Fix debug_values whose defs have been stackified.
626 if (!WasmDisableExplicitLocals)
627 addPass(P: createWebAssemblyDebugFixup());
628
629 // Collect information to prepare for MC lowering / asm printing.
630 addPass(P: createWebAssemblyMCLowerPrePass());
631}
632
633bool WebAssemblyPassConfig::addPreISel() {
634 TargetPassConfig::addPreISel();
635 addPass(P: createWebAssemblyLowerRefTypesIntPtrConv());
636 return false;
637}
638
639yaml::MachineFunctionInfo *
640WebAssemblyTargetMachine::createDefaultFuncInfoYAML() const {
641 return new yaml::WebAssemblyFunctionInfo();
642}
643
644yaml::MachineFunctionInfo *WebAssemblyTargetMachine::convertFuncInfoToYAML(
645 const MachineFunction &MF) const {
646 const auto *MFI = MF.getInfo<WebAssemblyFunctionInfo>();
647 return new yaml::WebAssemblyFunctionInfo(MF, *MFI);
648}
649
650bool WebAssemblyTargetMachine::parseMachineFunctionInfo(
651 const yaml::MachineFunctionInfo &MFI, PerFunctionMIParsingState &PFS,
652 SMDiagnostic &Error, SMRange &SourceRange) const {
653 const auto &YamlMFI = static_cast<const yaml::WebAssemblyFunctionInfo &>(MFI);
654 MachineFunction &MF = PFS.MF;
655 MF.getInfo<WebAssemblyFunctionInfo>()->initializeBaseYamlFields(MF, YamlMFI);
656 return false;
657}
658