xref: /llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp (revision 2946cd701067404b99c39fb29dc9c74bd7193eb3)
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 "WebAssembly.h"
17 #include "WebAssemblyTargetObjectFile.h"
18 #include "WebAssemblyTargetTransformInfo.h"
19 #include "llvm/CodeGen/MachineFunctionPass.h"
20 #include "llvm/CodeGen/Passes.h"
21 #include "llvm/CodeGen/RegAllocRegistry.h"
22 #include "llvm/CodeGen/TargetPassConfig.h"
23 #include "llvm/IR/Function.h"
24 #include "llvm/Support/TargetRegistry.h"
25 #include "llvm/Target/TargetOptions.h"
26 #include "llvm/Transforms/Scalar.h"
27 #include "llvm/Transforms/Utils.h"
28 using namespace llvm;
29 
30 #define DEBUG_TYPE "wasm"
31 
32 // Emscripten's asm.js-style exception handling
33 static cl::opt<bool> EnableEmException(
34     "enable-emscripten-cxx-exceptions",
35     cl::desc("WebAssembly Emscripten-style exception handling"),
36     cl::init(false));
37 
38 // Emscripten's asm.js-style setjmp/longjmp handling
39 static cl::opt<bool> EnableEmSjLj(
40     "enable-emscripten-sjlj",
41     cl::desc("WebAssembly Emscripten-style setjmp/longjmp handling"),
42     cl::init(false));
43 
44 extern "C" void LLVMInitializeWebAssemblyTarget() {
45   // Register the target.
46   RegisterTargetMachine<WebAssemblyTargetMachine> X(
47       getTheWebAssemblyTarget32());
48   RegisterTargetMachine<WebAssemblyTargetMachine> Y(
49       getTheWebAssemblyTarget64());
50 
51   // Register backend passes
52   auto &PR = *PassRegistry::getPassRegistry();
53   initializeWebAssemblyAddMissingPrototypesPass(PR);
54   initializeWebAssemblyLowerEmscriptenEHSjLjPass(PR);
55   initializeLowerGlobalDtorsPass(PR);
56   initializeFixFunctionBitcastsPass(PR);
57   initializeOptimizeReturnedPass(PR);
58   initializeWebAssemblyArgumentMovePass(PR);
59   initializeWebAssemblySetP2AlignOperandsPass(PR);
60   initializeWebAssemblyEHRestoreStackPointerPass(PR);
61   initializeWebAssemblyReplacePhysRegsPass(PR);
62   initializeWebAssemblyPrepareForLiveIntervalsPass(PR);
63   initializeWebAssemblyOptimizeLiveIntervalsPass(PR);
64   initializeWebAssemblyMemIntrinsicResultsPass(PR);
65   initializeWebAssemblyRegStackifyPass(PR);
66   initializeWebAssemblyRegColoringPass(PR);
67   initializeWebAssemblyExplicitLocalsPass(PR);
68   initializeWebAssemblyFixIrreducibleControlFlowPass(PR);
69   initializeWebAssemblyLateEHPreparePass(PR);
70   initializeWebAssemblyExceptionInfoPass(PR);
71   initializeWebAssemblyCFGSortPass(PR);
72   initializeWebAssemblyCFGStackifyPass(PR);
73   initializeWebAssemblyLowerBrUnlessPass(PR);
74   initializeWebAssemblyRegNumberingPass(PR);
75   initializeWebAssemblyPeepholePass(PR);
76   initializeWebAssemblyCallIndirectFixupPass(PR);
77 }
78 
79 //===----------------------------------------------------------------------===//
80 // WebAssembly Lowering public interface.
81 //===----------------------------------------------------------------------===//
82 
83 static Reloc::Model getEffectiveRelocModel(Optional<Reloc::Model> RM) {
84   if (!RM.hasValue()) {
85     // Default to static relocation model.  This should always be more optimial
86     // than PIC since the static linker can determine all global addresses and
87     // assume direct function calls.
88     return Reloc::Static;
89   }
90   return *RM;
91 }
92 
93 /// Create an WebAssembly architecture model.
94 ///
95 WebAssemblyTargetMachine::WebAssemblyTargetMachine(
96     const Target &T, const Triple &TT, StringRef CPU, StringRef FS,
97     const TargetOptions &Options, Optional<Reloc::Model> RM,
98     Optional<CodeModel::Model> CM, CodeGenOpt::Level OL, bool JIT)
99     : LLVMTargetMachine(T,
100                         TT.isArch64Bit() ? "e-m:e-p:64:64-i64:64-n32:64-S128"
101                                          : "e-m:e-p:32:32-i64:64-n32:64-S128",
102                         TT, CPU, FS, Options, getEffectiveRelocModel(RM),
103                         getEffectiveCodeModel(CM, CodeModel::Large), OL),
104       TLOF(new WebAssemblyTargetObjectFile()) {
105   // WebAssembly type-checks instructions, but a noreturn function with a return
106   // type that doesn't match the context will cause a check failure. So we lower
107   // LLVM 'unreachable' to ISD::TRAP and then lower that to WebAssembly's
108   // 'unreachable' instructions which is meant for that case.
109   this->Options.TrapUnreachable = true;
110 
111   // WebAssembly treats each function as an independent unit. Force
112   // -ffunction-sections, effectively, so that we can emit them independently.
113   this->Options.FunctionSections = true;
114   this->Options.DataSections = true;
115   this->Options.UniqueSectionNames = true;
116 
117   initAsmInfo();
118 
119   // Note that we don't use setRequiresStructuredCFG(true). It disables
120   // optimizations than we're ok with, and want, such as critical edge
121   // splitting and tail merging.
122 }
123 
124 WebAssemblyTargetMachine::~WebAssemblyTargetMachine() {}
125 
126 const WebAssemblySubtarget *
127 WebAssemblyTargetMachine::getSubtargetImpl(const Function &F) const {
128   Attribute CPUAttr = F.getFnAttribute("target-cpu");
129   Attribute FSAttr = F.getFnAttribute("target-features");
130 
131   std::string CPU = !CPUAttr.hasAttribute(Attribute::None)
132                         ? CPUAttr.getValueAsString().str()
133                         : TargetCPU;
134   std::string FS = !FSAttr.hasAttribute(Attribute::None)
135                        ? FSAttr.getValueAsString().str()
136                        : TargetFS;
137 
138   auto &I = SubtargetMap[CPU + FS];
139   if (!I) {
140     // This needs to be done before we create a new subtarget since any
141     // creation will depend on the TM and the code generation flags on the
142     // function that reside in TargetOptions.
143     resetTargetOptions(F);
144     I = llvm::make_unique<WebAssemblySubtarget>(TargetTriple, CPU, FS, *this);
145   }
146   return I.get();
147 }
148 
149 namespace {
150 class StripThreadLocal final : public ModulePass {
151   // The default thread model for wasm is single, where thread-local variables
152   // are identical to regular globals and should be treated the same. So this
153   // pass just converts all GlobalVariables to NotThreadLocal
154   static char ID;
155 
156 public:
157   StripThreadLocal() : ModulePass(ID) {}
158   bool runOnModule(Module &M) override {
159     for (auto &GV : M.globals())
160       GV.setThreadLocalMode(GlobalValue::ThreadLocalMode::NotThreadLocal);
161     return true;
162   }
163 };
164 char StripThreadLocal::ID = 0;
165 
166 /// WebAssembly Code Generator Pass Configuration Options.
167 class WebAssemblyPassConfig final : public TargetPassConfig {
168 public:
169   WebAssemblyPassConfig(WebAssemblyTargetMachine &TM, PassManagerBase &PM)
170       : TargetPassConfig(TM, PM) {}
171 
172   WebAssemblyTargetMachine &getWebAssemblyTargetMachine() const {
173     return getTM<WebAssemblyTargetMachine>();
174   }
175 
176   FunctionPass *createTargetRegisterAllocator(bool) override;
177 
178   void addIRPasses() override;
179   bool addInstSelector() override;
180   void addPostRegAlloc() override;
181   bool addGCPasses() override { return false; }
182   void addPreEmitPass() override;
183 };
184 } // end anonymous namespace
185 
186 TargetTransformInfo
187 WebAssemblyTargetMachine::getTargetTransformInfo(const Function &F) {
188   return TargetTransformInfo(WebAssemblyTTIImpl(this, F));
189 }
190 
191 TargetPassConfig *
192 WebAssemblyTargetMachine::createPassConfig(PassManagerBase &PM) {
193   return new WebAssemblyPassConfig(*this, PM);
194 }
195 
196 FunctionPass *WebAssemblyPassConfig::createTargetRegisterAllocator(bool) {
197   return nullptr; // No reg alloc
198 }
199 
200 //===----------------------------------------------------------------------===//
201 // The following functions are called from lib/CodeGen/Passes.cpp to modify
202 // the CodeGen pass sequence.
203 //===----------------------------------------------------------------------===//
204 
205 void WebAssemblyPassConfig::addIRPasses() {
206   if (TM->Options.ThreadModel == ThreadModel::Single) {
207     // In "single" mode, atomics get lowered to non-atomics.
208     addPass(createLowerAtomicPass());
209     addPass(new StripThreadLocal());
210   } else {
211     // Expand some atomic operations. WebAssemblyTargetLowering has hooks which
212     // control specifically what gets lowered.
213     addPass(createAtomicExpandPass());
214   }
215 
216   // Add signatures to prototype-less function declarations
217   addPass(createWebAssemblyAddMissingPrototypes());
218 
219   // Lower .llvm.global_dtors into .llvm_global_ctors with __cxa_atexit calls.
220   addPass(createWebAssemblyLowerGlobalDtors());
221 
222   // Fix function bitcasts, as WebAssembly requires caller and callee signatures
223   // to match.
224   addPass(createWebAssemblyFixFunctionBitcasts());
225 
226   // Optimize "returned" function attributes.
227   if (getOptLevel() != CodeGenOpt::None)
228     addPass(createWebAssemblyOptimizeReturned());
229 
230   // If exception handling is not enabled and setjmp/longjmp handling is
231   // enabled, we lower invokes into calls and delete unreachable landingpad
232   // blocks. Lowering invokes when there is no EH support is done in
233   // TargetPassConfig::addPassesToHandleExceptions, but this runs after this
234   // function and SjLj handling expects all invokes to be lowered before.
235   if (!EnableEmException &&
236       TM->Options.ExceptionModel == ExceptionHandling::None) {
237     addPass(createLowerInvokePass());
238     // The lower invoke pass may create unreachable code. Remove it in order not
239     // to process dead blocks in setjmp/longjmp handling.
240     addPass(createUnreachableBlockEliminationPass());
241   }
242 
243   // Handle exceptions and setjmp/longjmp if enabled.
244   if (EnableEmException || EnableEmSjLj)
245     addPass(createWebAssemblyLowerEmscriptenEHSjLj(EnableEmException,
246                                                    EnableEmSjLj));
247 
248   TargetPassConfig::addIRPasses();
249 }
250 
251 bool WebAssemblyPassConfig::addInstSelector() {
252   (void)TargetPassConfig::addInstSelector();
253   addPass(
254       createWebAssemblyISelDag(getWebAssemblyTargetMachine(), getOptLevel()));
255   // Run the argument-move pass immediately after the ScheduleDAG scheduler
256   // so that we can fix up the ARGUMENT instructions before anything else
257   // sees them in the wrong place.
258   addPass(createWebAssemblyArgumentMove());
259   // Set the p2align operands. This information is present during ISel, however
260   // it's inconvenient to collect. Collect it now, and update the immediate
261   // operands.
262   addPass(createWebAssemblySetP2AlignOperands());
263   return false;
264 }
265 
266 void WebAssemblyPassConfig::addPostRegAlloc() {
267   // TODO: The following CodeGen passes don't currently support code containing
268   // virtual registers. Consider removing their restrictions and re-enabling
269   // them.
270 
271   // These functions all require the NoVRegs property.
272   disablePass(&MachineCopyPropagationID);
273   disablePass(&PostRAMachineSinkingID);
274   disablePass(&PostRASchedulerID);
275   disablePass(&FuncletLayoutID);
276   disablePass(&StackMapLivenessID);
277   disablePass(&LiveDebugValuesID);
278   disablePass(&PatchableFunctionID);
279   disablePass(&ShrinkWrapID);
280 
281   TargetPassConfig::addPostRegAlloc();
282 }
283 
284 void WebAssemblyPassConfig::addPreEmitPass() {
285   TargetPassConfig::addPreEmitPass();
286 
287   // Restore __stack_pointer global after an exception is thrown.
288   addPass(createWebAssemblyEHRestoreStackPointer());
289 
290   // Now that we have a prologue and epilogue and all frame indices are
291   // rewritten, eliminate SP and FP. This allows them to be stackified,
292   // colored, and numbered with the rest of the registers.
293   addPass(createWebAssemblyReplacePhysRegs());
294 
295   // Rewrite pseudo call_indirect instructions as real instructions.
296   // This needs to run before register stackification, because we change the
297   // order of the arguments.
298   addPass(createWebAssemblyCallIndirectFixup());
299 
300   // Eliminate multiple-entry loops.
301   addPass(createWebAssemblyFixIrreducibleControlFlow());
302 
303   // Do various transformations for exception handling.
304   addPass(createWebAssemblyLateEHPrepare());
305 
306   if (getOptLevel() != CodeGenOpt::None) {
307     // LiveIntervals isn't commonly run this late. Re-establish preconditions.
308     addPass(createWebAssemblyPrepareForLiveIntervals());
309 
310     // Depend on LiveIntervals and perform some optimizations on it.
311     addPass(createWebAssemblyOptimizeLiveIntervals());
312 
313     // Prepare memory intrinsic calls for register stackifying.
314     addPass(createWebAssemblyMemIntrinsicResults());
315 
316     // Mark registers as representing wasm's value stack. This is a key
317     // code-compression technique in WebAssembly. We run this pass (and
318     // MemIntrinsicResults above) very late, so that it sees as much code as
319     // possible, including code emitted by PEI and expanded by late tail
320     // duplication.
321     addPass(createWebAssemblyRegStackify());
322 
323     // Run the register coloring pass to reduce the total number of registers.
324     // This runs after stackification so that it doesn't consider registers
325     // that become stackified.
326     addPass(createWebAssemblyRegColoring());
327   }
328 
329   // Insert explicit local.get and local.set operators.
330   addPass(createWebAssemblyExplicitLocals());
331 
332   // Sort the blocks of the CFG into topological order, a prerequisite for
333   // BLOCK and LOOP markers.
334   addPass(createWebAssemblyCFGSort());
335 
336   // Insert BLOCK and LOOP markers.
337   addPass(createWebAssemblyCFGStackify());
338 
339   // Lower br_unless into br_if.
340   addPass(createWebAssemblyLowerBrUnless());
341 
342   // Perform the very last peephole optimizations on the code.
343   if (getOptLevel() != CodeGenOpt::None)
344     addPass(createWebAssemblyPeephole());
345 
346   // Create a mapping from LLVM CodeGen virtual registers to wasm registers.
347   addPass(createWebAssemblyRegNumbering());
348 }
349