xref: /freebsd/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
1*0b57cec5SDimitry Andric //===- WebAssemblyTargetMachine.cpp - Define TargetMachine for WebAssembly -==//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric ///
9*0b57cec5SDimitry Andric /// \file
10*0b57cec5SDimitry Andric /// This file defines the WebAssembly-specific subclass of TargetMachine.
11*0b57cec5SDimitry Andric ///
12*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
13*0b57cec5SDimitry Andric 
14*0b57cec5SDimitry Andric #include "WebAssemblyTargetMachine.h"
15*0b57cec5SDimitry Andric #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
16*0b57cec5SDimitry Andric #include "TargetInfo/WebAssemblyTargetInfo.h"
17*0b57cec5SDimitry Andric #include "WebAssembly.h"
18*0b57cec5SDimitry Andric #include "WebAssemblyMachineFunctionInfo.h"
19*0b57cec5SDimitry Andric #include "WebAssemblyTargetObjectFile.h"
20*0b57cec5SDimitry Andric #include "WebAssemblyTargetTransformInfo.h"
21*0b57cec5SDimitry Andric #include "llvm/CodeGen/MIRParser/MIParser.h"
22*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
23*0b57cec5SDimitry Andric #include "llvm/CodeGen/Passes.h"
24*0b57cec5SDimitry Andric #include "llvm/CodeGen/RegAllocRegistry.h"
25*0b57cec5SDimitry Andric #include "llvm/CodeGen/TargetPassConfig.h"
26*0b57cec5SDimitry Andric #include "llvm/IR/Function.h"
27*0b57cec5SDimitry Andric #include "llvm/Support/TargetRegistry.h"
28*0b57cec5SDimitry Andric #include "llvm/Target/TargetOptions.h"
29*0b57cec5SDimitry Andric #include "llvm/Transforms/Scalar.h"
30*0b57cec5SDimitry Andric #include "llvm/Transforms/Scalar/LowerAtomic.h"
31*0b57cec5SDimitry Andric #include "llvm/Transforms/Utils.h"
32*0b57cec5SDimitry Andric using namespace llvm;
33*0b57cec5SDimitry Andric 
34*0b57cec5SDimitry Andric #define DEBUG_TYPE "wasm"
35*0b57cec5SDimitry Andric 
36*0b57cec5SDimitry Andric // Emscripten's asm.js-style exception handling
37*0b57cec5SDimitry Andric static cl::opt<bool> EnableEmException(
38*0b57cec5SDimitry Andric     "enable-emscripten-cxx-exceptions",
39*0b57cec5SDimitry Andric     cl::desc("WebAssembly Emscripten-style exception handling"),
40*0b57cec5SDimitry Andric     cl::init(false));
41*0b57cec5SDimitry Andric 
42*0b57cec5SDimitry Andric // Emscripten's asm.js-style setjmp/longjmp handling
43*0b57cec5SDimitry Andric static cl::opt<bool> EnableEmSjLj(
44*0b57cec5SDimitry Andric     "enable-emscripten-sjlj",
45*0b57cec5SDimitry Andric     cl::desc("WebAssembly Emscripten-style setjmp/longjmp handling"),
46*0b57cec5SDimitry Andric     cl::init(false));
47*0b57cec5SDimitry Andric 
48*0b57cec5SDimitry Andric extern "C" void LLVMInitializeWebAssemblyTarget() {
49*0b57cec5SDimitry Andric   // Register the target.
50*0b57cec5SDimitry Andric   RegisterTargetMachine<WebAssemblyTargetMachine> X(
51*0b57cec5SDimitry Andric       getTheWebAssemblyTarget32());
52*0b57cec5SDimitry Andric   RegisterTargetMachine<WebAssemblyTargetMachine> Y(
53*0b57cec5SDimitry Andric       getTheWebAssemblyTarget64());
54*0b57cec5SDimitry Andric 
55*0b57cec5SDimitry Andric   // Register backend passes
56*0b57cec5SDimitry Andric   auto &PR = *PassRegistry::getPassRegistry();
57*0b57cec5SDimitry Andric   initializeWebAssemblyAddMissingPrototypesPass(PR);
58*0b57cec5SDimitry Andric   initializeWebAssemblyLowerEmscriptenEHSjLjPass(PR);
59*0b57cec5SDimitry Andric   initializeLowerGlobalDtorsPass(PR);
60*0b57cec5SDimitry Andric   initializeFixFunctionBitcastsPass(PR);
61*0b57cec5SDimitry Andric   initializeOptimizeReturnedPass(PR);
62*0b57cec5SDimitry Andric   initializeWebAssemblyArgumentMovePass(PR);
63*0b57cec5SDimitry Andric   initializeWebAssemblySetP2AlignOperandsPass(PR);
64*0b57cec5SDimitry Andric   initializeWebAssemblyReplacePhysRegsPass(PR);
65*0b57cec5SDimitry Andric   initializeWebAssemblyPrepareForLiveIntervalsPass(PR);
66*0b57cec5SDimitry Andric   initializeWebAssemblyOptimizeLiveIntervalsPass(PR);
67*0b57cec5SDimitry Andric   initializeWebAssemblyMemIntrinsicResultsPass(PR);
68*0b57cec5SDimitry Andric   initializeWebAssemblyRegStackifyPass(PR);
69*0b57cec5SDimitry Andric   initializeWebAssemblyRegColoringPass(PR);
70*0b57cec5SDimitry Andric   initializeWebAssemblyFixIrreducibleControlFlowPass(PR);
71*0b57cec5SDimitry Andric   initializeWebAssemblyLateEHPreparePass(PR);
72*0b57cec5SDimitry Andric   initializeWebAssemblyExceptionInfoPass(PR);
73*0b57cec5SDimitry Andric   initializeWebAssemblyCFGSortPass(PR);
74*0b57cec5SDimitry Andric   initializeWebAssemblyCFGStackifyPass(PR);
75*0b57cec5SDimitry Andric   initializeWebAssemblyExplicitLocalsPass(PR);
76*0b57cec5SDimitry Andric   initializeWebAssemblyLowerBrUnlessPass(PR);
77*0b57cec5SDimitry Andric   initializeWebAssemblyRegNumberingPass(PR);
78*0b57cec5SDimitry Andric   initializeWebAssemblyPeepholePass(PR);
79*0b57cec5SDimitry Andric   initializeWebAssemblyCallIndirectFixupPass(PR);
80*0b57cec5SDimitry Andric }
81*0b57cec5SDimitry Andric 
82*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
83*0b57cec5SDimitry Andric // WebAssembly Lowering public interface.
84*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
85*0b57cec5SDimitry Andric 
86*0b57cec5SDimitry Andric static Reloc::Model getEffectiveRelocModel(Optional<Reloc::Model> RM,
87*0b57cec5SDimitry Andric                                            const Triple &TT) {
88*0b57cec5SDimitry Andric   if (!RM.hasValue()) {
89*0b57cec5SDimitry Andric     // Default to static relocation model.  This should always be more optimial
90*0b57cec5SDimitry Andric     // than PIC since the static linker can determine all global addresses and
91*0b57cec5SDimitry Andric     // assume direct function calls.
92*0b57cec5SDimitry Andric     return Reloc::Static;
93*0b57cec5SDimitry Andric   }
94*0b57cec5SDimitry Andric 
95*0b57cec5SDimitry Andric   if (!TT.isOSEmscripten()) {
96*0b57cec5SDimitry Andric     // Relocation modes other than static are currently implemented in a way
97*0b57cec5SDimitry Andric     // that only works for Emscripten, so disable them if we aren't targeting
98*0b57cec5SDimitry Andric     // Emscripten.
99*0b57cec5SDimitry Andric     return Reloc::Static;
100*0b57cec5SDimitry Andric   }
101*0b57cec5SDimitry Andric 
102*0b57cec5SDimitry Andric   return *RM;
103*0b57cec5SDimitry Andric }
104*0b57cec5SDimitry Andric 
105*0b57cec5SDimitry Andric /// Create an WebAssembly architecture model.
106*0b57cec5SDimitry Andric ///
107*0b57cec5SDimitry Andric WebAssemblyTargetMachine::WebAssemblyTargetMachine(
108*0b57cec5SDimitry Andric     const Target &T, const Triple &TT, StringRef CPU, StringRef FS,
109*0b57cec5SDimitry Andric     const TargetOptions &Options, Optional<Reloc::Model> RM,
110*0b57cec5SDimitry Andric     Optional<CodeModel::Model> CM, CodeGenOpt::Level OL, bool JIT)
111*0b57cec5SDimitry Andric     : LLVMTargetMachine(T,
112*0b57cec5SDimitry Andric                         TT.isArch64Bit() ? "e-m:e-p:64:64-i64:64-n32:64-S128"
113*0b57cec5SDimitry Andric                                          : "e-m:e-p:32:32-i64:64-n32:64-S128",
114*0b57cec5SDimitry Andric                         TT, CPU, FS, Options, getEffectiveRelocModel(RM, TT),
115*0b57cec5SDimitry Andric                         getEffectiveCodeModel(CM, CodeModel::Large), OL),
116*0b57cec5SDimitry Andric       TLOF(new WebAssemblyTargetObjectFile()) {
117*0b57cec5SDimitry Andric   // WebAssembly type-checks instructions, but a noreturn function with a return
118*0b57cec5SDimitry Andric   // type that doesn't match the context will cause a check failure. So we lower
119*0b57cec5SDimitry Andric   // LLVM 'unreachable' to ISD::TRAP and then lower that to WebAssembly's
120*0b57cec5SDimitry Andric   // 'unreachable' instructions which is meant for that case.
121*0b57cec5SDimitry Andric   this->Options.TrapUnreachable = true;
122*0b57cec5SDimitry Andric 
123*0b57cec5SDimitry Andric   // WebAssembly treats each function as an independent unit. Force
124*0b57cec5SDimitry Andric   // -ffunction-sections, effectively, so that we can emit them independently.
125*0b57cec5SDimitry Andric   this->Options.FunctionSections = true;
126*0b57cec5SDimitry Andric   this->Options.DataSections = true;
127*0b57cec5SDimitry Andric   this->Options.UniqueSectionNames = true;
128*0b57cec5SDimitry Andric 
129*0b57cec5SDimitry Andric   initAsmInfo();
130*0b57cec5SDimitry Andric 
131*0b57cec5SDimitry Andric   // Note that we don't use setRequiresStructuredCFG(true). It disables
132*0b57cec5SDimitry Andric   // optimizations than we're ok with, and want, such as critical edge
133*0b57cec5SDimitry Andric   // splitting and tail merging.
134*0b57cec5SDimitry Andric }
135*0b57cec5SDimitry Andric 
136*0b57cec5SDimitry Andric WebAssemblyTargetMachine::~WebAssemblyTargetMachine() = default; // anchor.
137*0b57cec5SDimitry Andric 
138*0b57cec5SDimitry Andric const WebAssemblySubtarget *
139*0b57cec5SDimitry Andric WebAssemblyTargetMachine::getSubtargetImpl(std::string CPU,
140*0b57cec5SDimitry Andric                                            std::string FS) const {
141*0b57cec5SDimitry Andric   auto &I = SubtargetMap[CPU + FS];
142*0b57cec5SDimitry Andric   if (!I) {
143*0b57cec5SDimitry Andric     I = llvm::make_unique<WebAssemblySubtarget>(TargetTriple, CPU, FS, *this);
144*0b57cec5SDimitry Andric   }
145*0b57cec5SDimitry Andric   return I.get();
146*0b57cec5SDimitry Andric }
147*0b57cec5SDimitry Andric 
148*0b57cec5SDimitry Andric const WebAssemblySubtarget *
149*0b57cec5SDimitry Andric WebAssemblyTargetMachine::getSubtargetImpl(const Function &F) const {
150*0b57cec5SDimitry Andric   Attribute CPUAttr = F.getFnAttribute("target-cpu");
151*0b57cec5SDimitry Andric   Attribute FSAttr = F.getFnAttribute("target-features");
152*0b57cec5SDimitry Andric 
153*0b57cec5SDimitry Andric   std::string CPU = !CPUAttr.hasAttribute(Attribute::None)
154*0b57cec5SDimitry Andric                         ? CPUAttr.getValueAsString().str()
155*0b57cec5SDimitry Andric                         : TargetCPU;
156*0b57cec5SDimitry Andric   std::string FS = !FSAttr.hasAttribute(Attribute::None)
157*0b57cec5SDimitry Andric                        ? FSAttr.getValueAsString().str()
158*0b57cec5SDimitry Andric                        : TargetFS;
159*0b57cec5SDimitry Andric 
160*0b57cec5SDimitry Andric   // This needs to be done before we create a new subtarget since any
161*0b57cec5SDimitry Andric   // creation will depend on the TM and the code generation flags on the
162*0b57cec5SDimitry Andric   // function that reside in TargetOptions.
163*0b57cec5SDimitry Andric   resetTargetOptions(F);
164*0b57cec5SDimitry Andric 
165*0b57cec5SDimitry Andric   return getSubtargetImpl(CPU, FS);
166*0b57cec5SDimitry Andric }
167*0b57cec5SDimitry Andric 
168*0b57cec5SDimitry Andric namespace {
169*0b57cec5SDimitry Andric 
170*0b57cec5SDimitry Andric class CoalesceFeaturesAndStripAtomics final : public ModulePass {
171*0b57cec5SDimitry Andric   // Take the union of all features used in the module and use it for each
172*0b57cec5SDimitry Andric   // function individually, since having multiple feature sets in one module
173*0b57cec5SDimitry Andric   // currently does not make sense for WebAssembly. If atomics are not enabled,
174*0b57cec5SDimitry Andric   // also strip atomic operations and thread local storage.
175*0b57cec5SDimitry Andric   static char ID;
176*0b57cec5SDimitry Andric   WebAssemblyTargetMachine *WasmTM;
177*0b57cec5SDimitry Andric 
178*0b57cec5SDimitry Andric public:
179*0b57cec5SDimitry Andric   CoalesceFeaturesAndStripAtomics(WebAssemblyTargetMachine *WasmTM)
180*0b57cec5SDimitry Andric       : ModulePass(ID), WasmTM(WasmTM) {}
181*0b57cec5SDimitry Andric 
182*0b57cec5SDimitry Andric   bool runOnModule(Module &M) override {
183*0b57cec5SDimitry Andric     FeatureBitset Features = coalesceFeatures(M);
184*0b57cec5SDimitry Andric 
185*0b57cec5SDimitry Andric     std::string FeatureStr = getFeatureString(Features);
186*0b57cec5SDimitry Andric     for (auto &F : M)
187*0b57cec5SDimitry Andric       replaceFeatures(F, FeatureStr);
188*0b57cec5SDimitry Andric 
189*0b57cec5SDimitry Andric     bool StrippedAtomics = false;
190*0b57cec5SDimitry Andric     bool StrippedTLS = false;
191*0b57cec5SDimitry Andric 
192*0b57cec5SDimitry Andric     if (!Features[WebAssembly::FeatureAtomics])
193*0b57cec5SDimitry Andric       StrippedAtomics = stripAtomics(M);
194*0b57cec5SDimitry Andric 
195*0b57cec5SDimitry Andric     if (!Features[WebAssembly::FeatureBulkMemory])
196*0b57cec5SDimitry Andric       StrippedTLS = stripThreadLocals(M);
197*0b57cec5SDimitry Andric 
198*0b57cec5SDimitry Andric     if (StrippedAtomics && !StrippedTLS)
199*0b57cec5SDimitry Andric       stripThreadLocals(M);
200*0b57cec5SDimitry Andric     else if (StrippedTLS && !StrippedAtomics)
201*0b57cec5SDimitry Andric       stripAtomics(M);
202*0b57cec5SDimitry Andric 
203*0b57cec5SDimitry Andric     recordFeatures(M, Features, StrippedAtomics || StrippedTLS);
204*0b57cec5SDimitry Andric 
205*0b57cec5SDimitry Andric     // Conservatively assume we have made some change
206*0b57cec5SDimitry Andric     return true;
207*0b57cec5SDimitry Andric   }
208*0b57cec5SDimitry Andric 
209*0b57cec5SDimitry Andric private:
210*0b57cec5SDimitry Andric   FeatureBitset coalesceFeatures(const Module &M) {
211*0b57cec5SDimitry Andric     FeatureBitset Features =
212*0b57cec5SDimitry Andric         WasmTM
213*0b57cec5SDimitry Andric             ->getSubtargetImpl(WasmTM->getTargetCPU(),
214*0b57cec5SDimitry Andric                                WasmTM->getTargetFeatureString())
215*0b57cec5SDimitry Andric             ->getFeatureBits();
216*0b57cec5SDimitry Andric     for (auto &F : M)
217*0b57cec5SDimitry Andric       Features |= WasmTM->getSubtargetImpl(F)->getFeatureBits();
218*0b57cec5SDimitry Andric     return Features;
219*0b57cec5SDimitry Andric   }
220*0b57cec5SDimitry Andric 
221*0b57cec5SDimitry Andric   std::string getFeatureString(const FeatureBitset &Features) {
222*0b57cec5SDimitry Andric     std::string Ret;
223*0b57cec5SDimitry Andric     for (const SubtargetFeatureKV &KV : WebAssemblyFeatureKV) {
224*0b57cec5SDimitry Andric       if (Features[KV.Value])
225*0b57cec5SDimitry Andric         Ret += (StringRef("+") + KV.Key + ",").str();
226*0b57cec5SDimitry Andric     }
227*0b57cec5SDimitry Andric     return Ret;
228*0b57cec5SDimitry Andric   }
229*0b57cec5SDimitry Andric 
230*0b57cec5SDimitry Andric   void replaceFeatures(Function &F, const std::string &Features) {
231*0b57cec5SDimitry Andric     F.removeFnAttr("target-features");
232*0b57cec5SDimitry Andric     F.removeFnAttr("target-cpu");
233*0b57cec5SDimitry Andric     F.addFnAttr("target-features", Features);
234*0b57cec5SDimitry Andric   }
235*0b57cec5SDimitry Andric 
236*0b57cec5SDimitry Andric   bool stripAtomics(Module &M) {
237*0b57cec5SDimitry Andric     // Detect whether any atomics will be lowered, since there is no way to tell
238*0b57cec5SDimitry Andric     // whether the LowerAtomic pass lowers e.g. stores.
239*0b57cec5SDimitry Andric     bool Stripped = false;
240*0b57cec5SDimitry Andric     for (auto &F : M) {
241*0b57cec5SDimitry Andric       for (auto &B : F) {
242*0b57cec5SDimitry Andric         for (auto &I : B) {
243*0b57cec5SDimitry Andric           if (I.isAtomic()) {
244*0b57cec5SDimitry Andric             Stripped = true;
245*0b57cec5SDimitry Andric             goto done;
246*0b57cec5SDimitry Andric           }
247*0b57cec5SDimitry Andric         }
248*0b57cec5SDimitry Andric       }
249*0b57cec5SDimitry Andric     }
250*0b57cec5SDimitry Andric 
251*0b57cec5SDimitry Andric   done:
252*0b57cec5SDimitry Andric     if (!Stripped)
253*0b57cec5SDimitry Andric       return false;
254*0b57cec5SDimitry Andric 
255*0b57cec5SDimitry Andric     LowerAtomicPass Lowerer;
256*0b57cec5SDimitry Andric     FunctionAnalysisManager FAM;
257*0b57cec5SDimitry Andric     for (auto &F : M)
258*0b57cec5SDimitry Andric       Lowerer.run(F, FAM);
259*0b57cec5SDimitry Andric 
260*0b57cec5SDimitry Andric     return true;
261*0b57cec5SDimitry Andric   }
262*0b57cec5SDimitry Andric 
263*0b57cec5SDimitry Andric   bool stripThreadLocals(Module &M) {
264*0b57cec5SDimitry Andric     bool Stripped = false;
265*0b57cec5SDimitry Andric     for (auto &GV : M.globals()) {
266*0b57cec5SDimitry Andric       if (GV.getThreadLocalMode() !=
267*0b57cec5SDimitry Andric           GlobalValue::ThreadLocalMode::NotThreadLocal) {
268*0b57cec5SDimitry Andric         Stripped = true;
269*0b57cec5SDimitry Andric         GV.setThreadLocalMode(GlobalValue::ThreadLocalMode::NotThreadLocal);
270*0b57cec5SDimitry Andric       }
271*0b57cec5SDimitry Andric     }
272*0b57cec5SDimitry Andric     return Stripped;
273*0b57cec5SDimitry Andric   }
274*0b57cec5SDimitry Andric 
275*0b57cec5SDimitry Andric   void recordFeatures(Module &M, const FeatureBitset &Features, bool Stripped) {
276*0b57cec5SDimitry Andric     for (const SubtargetFeatureKV &KV : WebAssemblyFeatureKV) {
277*0b57cec5SDimitry Andric       std::string MDKey = (StringRef("wasm-feature-") + KV.Key).str();
278*0b57cec5SDimitry Andric       if (KV.Value == WebAssembly::FeatureAtomics && Stripped) {
279*0b57cec5SDimitry Andric         // "atomics" is special: code compiled without atomics may have had its
280*0b57cec5SDimitry Andric         // atomics lowered to nonatomic operations. In that case, atomics is
281*0b57cec5SDimitry Andric         // disallowed to prevent unsafe linking with atomics-enabled objects.
282*0b57cec5SDimitry Andric         assert(!Features[WebAssembly::FeatureAtomics] ||
283*0b57cec5SDimitry Andric                !Features[WebAssembly::FeatureBulkMemory]);
284*0b57cec5SDimitry Andric         M.addModuleFlag(Module::ModFlagBehavior::Error, MDKey,
285*0b57cec5SDimitry Andric                         wasm::WASM_FEATURE_PREFIX_DISALLOWED);
286*0b57cec5SDimitry Andric       } else if (Features[KV.Value]) {
287*0b57cec5SDimitry Andric         // Otherwise features are marked Used or not mentioned
288*0b57cec5SDimitry Andric         M.addModuleFlag(Module::ModFlagBehavior::Error, MDKey,
289*0b57cec5SDimitry Andric                         wasm::WASM_FEATURE_PREFIX_USED);
290*0b57cec5SDimitry Andric       }
291*0b57cec5SDimitry Andric     }
292*0b57cec5SDimitry Andric   }
293*0b57cec5SDimitry Andric };
294*0b57cec5SDimitry Andric char CoalesceFeaturesAndStripAtomics::ID = 0;
295*0b57cec5SDimitry Andric 
296*0b57cec5SDimitry Andric /// WebAssembly Code Generator Pass Configuration Options.
297*0b57cec5SDimitry Andric class WebAssemblyPassConfig final : public TargetPassConfig {
298*0b57cec5SDimitry Andric public:
299*0b57cec5SDimitry Andric   WebAssemblyPassConfig(WebAssemblyTargetMachine &TM, PassManagerBase &PM)
300*0b57cec5SDimitry Andric       : TargetPassConfig(TM, PM) {}
301*0b57cec5SDimitry Andric 
302*0b57cec5SDimitry Andric   WebAssemblyTargetMachine &getWebAssemblyTargetMachine() const {
303*0b57cec5SDimitry Andric     return getTM<WebAssemblyTargetMachine>();
304*0b57cec5SDimitry Andric   }
305*0b57cec5SDimitry Andric 
306*0b57cec5SDimitry Andric   FunctionPass *createTargetRegisterAllocator(bool) override;
307*0b57cec5SDimitry Andric 
308*0b57cec5SDimitry Andric   void addIRPasses() override;
309*0b57cec5SDimitry Andric   bool addInstSelector() override;
310*0b57cec5SDimitry Andric   void addPostRegAlloc() override;
311*0b57cec5SDimitry Andric   bool addGCPasses() override { return false; }
312*0b57cec5SDimitry Andric   void addPreEmitPass() override;
313*0b57cec5SDimitry Andric 
314*0b57cec5SDimitry Andric   // No reg alloc
315*0b57cec5SDimitry Andric   bool addRegAssignmentFast() override { return false; }
316*0b57cec5SDimitry Andric 
317*0b57cec5SDimitry Andric   // No reg alloc
318*0b57cec5SDimitry Andric   bool addRegAssignmentOptimized() override { return false; }
319*0b57cec5SDimitry Andric };
320*0b57cec5SDimitry Andric } // end anonymous namespace
321*0b57cec5SDimitry Andric 
322*0b57cec5SDimitry Andric TargetTransformInfo
323*0b57cec5SDimitry Andric WebAssemblyTargetMachine::getTargetTransformInfo(const Function &F) {
324*0b57cec5SDimitry Andric   return TargetTransformInfo(WebAssemblyTTIImpl(this, F));
325*0b57cec5SDimitry Andric }
326*0b57cec5SDimitry Andric 
327*0b57cec5SDimitry Andric TargetPassConfig *
328*0b57cec5SDimitry Andric WebAssemblyTargetMachine::createPassConfig(PassManagerBase &PM) {
329*0b57cec5SDimitry Andric   return new WebAssemblyPassConfig(*this, PM);
330*0b57cec5SDimitry Andric }
331*0b57cec5SDimitry Andric 
332*0b57cec5SDimitry Andric FunctionPass *WebAssemblyPassConfig::createTargetRegisterAllocator(bool) {
333*0b57cec5SDimitry Andric   return nullptr; // No reg alloc
334*0b57cec5SDimitry Andric }
335*0b57cec5SDimitry Andric 
336*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
337*0b57cec5SDimitry Andric // The following functions are called from lib/CodeGen/Passes.cpp to modify
338*0b57cec5SDimitry Andric // the CodeGen pass sequence.
339*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
340*0b57cec5SDimitry Andric 
341*0b57cec5SDimitry Andric void WebAssemblyPassConfig::addIRPasses() {
342*0b57cec5SDimitry Andric   // Runs LowerAtomicPass if necessary
343*0b57cec5SDimitry Andric   addPass(new CoalesceFeaturesAndStripAtomics(&getWebAssemblyTargetMachine()));
344*0b57cec5SDimitry Andric 
345*0b57cec5SDimitry Andric   // This is a no-op if atomics are not used in the module
346*0b57cec5SDimitry Andric   addPass(createAtomicExpandPass());
347*0b57cec5SDimitry Andric 
348*0b57cec5SDimitry Andric   // Add signatures to prototype-less function declarations
349*0b57cec5SDimitry Andric   addPass(createWebAssemblyAddMissingPrototypes());
350*0b57cec5SDimitry Andric 
351*0b57cec5SDimitry Andric   // Lower .llvm.global_dtors into .llvm_global_ctors with __cxa_atexit calls.
352*0b57cec5SDimitry Andric   addPass(createWebAssemblyLowerGlobalDtors());
353*0b57cec5SDimitry Andric 
354*0b57cec5SDimitry Andric   // Fix function bitcasts, as WebAssembly requires caller and callee signatures
355*0b57cec5SDimitry Andric   // to match.
356*0b57cec5SDimitry Andric   addPass(createWebAssemblyFixFunctionBitcasts());
357*0b57cec5SDimitry Andric 
358*0b57cec5SDimitry Andric   // Optimize "returned" function attributes.
359*0b57cec5SDimitry Andric   if (getOptLevel() != CodeGenOpt::None)
360*0b57cec5SDimitry Andric     addPass(createWebAssemblyOptimizeReturned());
361*0b57cec5SDimitry Andric 
362*0b57cec5SDimitry Andric   // If exception handling is not enabled and setjmp/longjmp handling is
363*0b57cec5SDimitry Andric   // enabled, we lower invokes into calls and delete unreachable landingpad
364*0b57cec5SDimitry Andric   // blocks. Lowering invokes when there is no EH support is done in
365*0b57cec5SDimitry Andric   // TargetPassConfig::addPassesToHandleExceptions, but this runs after this
366*0b57cec5SDimitry Andric   // function and SjLj handling expects all invokes to be lowered before.
367*0b57cec5SDimitry Andric   if (!EnableEmException &&
368*0b57cec5SDimitry Andric       TM->Options.ExceptionModel == ExceptionHandling::None) {
369*0b57cec5SDimitry Andric     addPass(createLowerInvokePass());
370*0b57cec5SDimitry Andric     // The lower invoke pass may create unreachable code. Remove it in order not
371*0b57cec5SDimitry Andric     // to process dead blocks in setjmp/longjmp handling.
372*0b57cec5SDimitry Andric     addPass(createUnreachableBlockEliminationPass());
373*0b57cec5SDimitry Andric   }
374*0b57cec5SDimitry Andric 
375*0b57cec5SDimitry Andric   // Handle exceptions and setjmp/longjmp if enabled.
376*0b57cec5SDimitry Andric   if (EnableEmException || EnableEmSjLj)
377*0b57cec5SDimitry Andric     addPass(createWebAssemblyLowerEmscriptenEHSjLj(EnableEmException,
378*0b57cec5SDimitry Andric                                                    EnableEmSjLj));
379*0b57cec5SDimitry Andric 
380*0b57cec5SDimitry Andric   // Expand indirectbr instructions to switches.
381*0b57cec5SDimitry Andric   addPass(createIndirectBrExpandPass());
382*0b57cec5SDimitry Andric 
383*0b57cec5SDimitry Andric   TargetPassConfig::addIRPasses();
384*0b57cec5SDimitry Andric }
385*0b57cec5SDimitry Andric 
386*0b57cec5SDimitry Andric bool WebAssemblyPassConfig::addInstSelector() {
387*0b57cec5SDimitry Andric   (void)TargetPassConfig::addInstSelector();
388*0b57cec5SDimitry Andric   addPass(
389*0b57cec5SDimitry Andric       createWebAssemblyISelDag(getWebAssemblyTargetMachine(), getOptLevel()));
390*0b57cec5SDimitry Andric   // Run the argument-move pass immediately after the ScheduleDAG scheduler
391*0b57cec5SDimitry Andric   // so that we can fix up the ARGUMENT instructions before anything else
392*0b57cec5SDimitry Andric   // sees them in the wrong place.
393*0b57cec5SDimitry Andric   addPass(createWebAssemblyArgumentMove());
394*0b57cec5SDimitry Andric   // Set the p2align operands. This information is present during ISel, however
395*0b57cec5SDimitry Andric   // it's inconvenient to collect. Collect it now, and update the immediate
396*0b57cec5SDimitry Andric   // operands.
397*0b57cec5SDimitry Andric   addPass(createWebAssemblySetP2AlignOperands());
398*0b57cec5SDimitry Andric   return false;
399*0b57cec5SDimitry Andric }
400*0b57cec5SDimitry Andric 
401*0b57cec5SDimitry Andric void WebAssemblyPassConfig::addPostRegAlloc() {
402*0b57cec5SDimitry Andric   // TODO: The following CodeGen passes don't currently support code containing
403*0b57cec5SDimitry Andric   // virtual registers. Consider removing their restrictions and re-enabling
404*0b57cec5SDimitry Andric   // them.
405*0b57cec5SDimitry Andric 
406*0b57cec5SDimitry Andric   // These functions all require the NoVRegs property.
407*0b57cec5SDimitry Andric   disablePass(&MachineCopyPropagationID);
408*0b57cec5SDimitry Andric   disablePass(&PostRAMachineSinkingID);
409*0b57cec5SDimitry Andric   disablePass(&PostRASchedulerID);
410*0b57cec5SDimitry Andric   disablePass(&FuncletLayoutID);
411*0b57cec5SDimitry Andric   disablePass(&StackMapLivenessID);
412*0b57cec5SDimitry Andric   disablePass(&LiveDebugValuesID);
413*0b57cec5SDimitry Andric   disablePass(&PatchableFunctionID);
414*0b57cec5SDimitry Andric   disablePass(&ShrinkWrapID);
415*0b57cec5SDimitry Andric 
416*0b57cec5SDimitry Andric   // This pass hurts code size for wasm because it can generate irreducible
417*0b57cec5SDimitry Andric   // control flow.
418*0b57cec5SDimitry Andric   disablePass(&MachineBlockPlacementID);
419*0b57cec5SDimitry Andric 
420*0b57cec5SDimitry Andric   TargetPassConfig::addPostRegAlloc();
421*0b57cec5SDimitry Andric }
422*0b57cec5SDimitry Andric 
423*0b57cec5SDimitry Andric void WebAssemblyPassConfig::addPreEmitPass() {
424*0b57cec5SDimitry Andric   TargetPassConfig::addPreEmitPass();
425*0b57cec5SDimitry Andric 
426*0b57cec5SDimitry Andric   // Rewrite pseudo call_indirect instructions as real instructions.
427*0b57cec5SDimitry Andric   // This needs to run before register stackification, because we change the
428*0b57cec5SDimitry Andric   // order of the arguments.
429*0b57cec5SDimitry Andric   addPass(createWebAssemblyCallIndirectFixup());
430*0b57cec5SDimitry Andric 
431*0b57cec5SDimitry Andric   // Eliminate multiple-entry loops.
432*0b57cec5SDimitry Andric   addPass(createWebAssemblyFixIrreducibleControlFlow());
433*0b57cec5SDimitry Andric 
434*0b57cec5SDimitry Andric   // Do various transformations for exception handling.
435*0b57cec5SDimitry Andric   // Every CFG-changing optimizations should come before this.
436*0b57cec5SDimitry Andric   addPass(createWebAssemblyLateEHPrepare());
437*0b57cec5SDimitry Andric 
438*0b57cec5SDimitry Andric   // Now that we have a prologue and epilogue and all frame indices are
439*0b57cec5SDimitry Andric   // rewritten, eliminate SP and FP. This allows them to be stackified,
440*0b57cec5SDimitry Andric   // colored, and numbered with the rest of the registers.
441*0b57cec5SDimitry Andric   addPass(createWebAssemblyReplacePhysRegs());
442*0b57cec5SDimitry Andric 
443*0b57cec5SDimitry Andric   // Preparations and optimizations related to register stackification.
444*0b57cec5SDimitry Andric   if (getOptLevel() != CodeGenOpt::None) {
445*0b57cec5SDimitry Andric     // LiveIntervals isn't commonly run this late. Re-establish preconditions.
446*0b57cec5SDimitry Andric     addPass(createWebAssemblyPrepareForLiveIntervals());
447*0b57cec5SDimitry Andric 
448*0b57cec5SDimitry Andric     // Depend on LiveIntervals and perform some optimizations on it.
449*0b57cec5SDimitry Andric     addPass(createWebAssemblyOptimizeLiveIntervals());
450*0b57cec5SDimitry Andric 
451*0b57cec5SDimitry Andric     // Prepare memory intrinsic calls for register stackifying.
452*0b57cec5SDimitry Andric     addPass(createWebAssemblyMemIntrinsicResults());
453*0b57cec5SDimitry Andric 
454*0b57cec5SDimitry Andric     // Mark registers as representing wasm's value stack. This is a key
455*0b57cec5SDimitry Andric     // code-compression technique in WebAssembly. We run this pass (and
456*0b57cec5SDimitry Andric     // MemIntrinsicResults above) very late, so that it sees as much code as
457*0b57cec5SDimitry Andric     // possible, including code emitted by PEI and expanded by late tail
458*0b57cec5SDimitry Andric     // duplication.
459*0b57cec5SDimitry Andric     addPass(createWebAssemblyRegStackify());
460*0b57cec5SDimitry Andric 
461*0b57cec5SDimitry Andric     // Run the register coloring pass to reduce the total number of registers.
462*0b57cec5SDimitry Andric     // This runs after stackification so that it doesn't consider registers
463*0b57cec5SDimitry Andric     // that become stackified.
464*0b57cec5SDimitry Andric     addPass(createWebAssemblyRegColoring());
465*0b57cec5SDimitry Andric   }
466*0b57cec5SDimitry Andric 
467*0b57cec5SDimitry Andric   // Sort the blocks of the CFG into topological order, a prerequisite for
468*0b57cec5SDimitry Andric   // BLOCK and LOOP markers.
469*0b57cec5SDimitry Andric   addPass(createWebAssemblyCFGSort());
470*0b57cec5SDimitry Andric 
471*0b57cec5SDimitry Andric   // Insert BLOCK and LOOP markers.
472*0b57cec5SDimitry Andric   addPass(createWebAssemblyCFGStackify());
473*0b57cec5SDimitry Andric 
474*0b57cec5SDimitry Andric   // Insert explicit local.get and local.set operators.
475*0b57cec5SDimitry Andric   addPass(createWebAssemblyExplicitLocals());
476*0b57cec5SDimitry Andric 
477*0b57cec5SDimitry Andric   // Lower br_unless into br_if.
478*0b57cec5SDimitry Andric   addPass(createWebAssemblyLowerBrUnless());
479*0b57cec5SDimitry Andric 
480*0b57cec5SDimitry Andric   // Perform the very last peephole optimizations on the code.
481*0b57cec5SDimitry Andric   if (getOptLevel() != CodeGenOpt::None)
482*0b57cec5SDimitry Andric     addPass(createWebAssemblyPeephole());
483*0b57cec5SDimitry Andric 
484*0b57cec5SDimitry Andric   // Create a mapping from LLVM CodeGen virtual registers to wasm registers.
485*0b57cec5SDimitry Andric   addPass(createWebAssemblyRegNumbering());
486*0b57cec5SDimitry Andric }
487*0b57cec5SDimitry Andric 
488*0b57cec5SDimitry Andric yaml::MachineFunctionInfo *
489*0b57cec5SDimitry Andric WebAssemblyTargetMachine::createDefaultFuncInfoYAML() const {
490*0b57cec5SDimitry Andric   return new yaml::WebAssemblyFunctionInfo();
491*0b57cec5SDimitry Andric }
492*0b57cec5SDimitry Andric 
493*0b57cec5SDimitry Andric yaml::MachineFunctionInfo *WebAssemblyTargetMachine::convertFuncInfoToYAML(
494*0b57cec5SDimitry Andric     const MachineFunction &MF) const {
495*0b57cec5SDimitry Andric   const auto *MFI = MF.getInfo<WebAssemblyFunctionInfo>();
496*0b57cec5SDimitry Andric   return new yaml::WebAssemblyFunctionInfo(*MFI);
497*0b57cec5SDimitry Andric }
498*0b57cec5SDimitry Andric 
499*0b57cec5SDimitry Andric bool WebAssemblyTargetMachine::parseMachineFunctionInfo(
500*0b57cec5SDimitry Andric     const yaml::MachineFunctionInfo &MFI, PerFunctionMIParsingState &PFS,
501*0b57cec5SDimitry Andric     SMDiagnostic &Error, SMRange &SourceRange) const {
502*0b57cec5SDimitry Andric   const auto &YamlMFI =
503*0b57cec5SDimitry Andric       reinterpret_cast<const yaml::WebAssemblyFunctionInfo &>(MFI);
504*0b57cec5SDimitry Andric   MachineFunction &MF = PFS.MF;
505*0b57cec5SDimitry Andric   MF.getInfo<WebAssemblyFunctionInfo>()->initializeBaseYamlFields(YamlMFI);
506*0b57cec5SDimitry Andric   return false;
507*0b57cec5SDimitry Andric }
508