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