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