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