13dac3a9bSDimitry Andric //===- WebAssemblyTargetMachine.cpp - Define TargetMachine for WebAssembly -==//
23dac3a9bSDimitry Andric //
33dac3a9bSDimitry Andric //                     The LLVM Compiler Infrastructure
43dac3a9bSDimitry Andric //
53dac3a9bSDimitry Andric // This file is distributed under the University of Illinois Open Source
63dac3a9bSDimitry Andric // License. See LICENSE.TXT for details.
73dac3a9bSDimitry Andric //
83dac3a9bSDimitry Andric //===----------------------------------------------------------------------===//
93dac3a9bSDimitry Andric ///
103dac3a9bSDimitry Andric /// \file
113dac3a9bSDimitry Andric /// \brief This file defines the WebAssembly-specific subclass of TargetMachine.
123dac3a9bSDimitry Andric ///
133dac3a9bSDimitry Andric //===----------------------------------------------------------------------===//
143dac3a9bSDimitry Andric 
153dac3a9bSDimitry Andric #include "WebAssemblyTargetMachine.h"
16db17bf38SDimitry Andric #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
17db17bf38SDimitry Andric #include "WebAssembly.h"
183dac3a9bSDimitry Andric #include "WebAssemblyTargetObjectFile.h"
193dac3a9bSDimitry Andric #include "WebAssemblyTargetTransformInfo.h"
203dac3a9bSDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
213dac3a9bSDimitry Andric #include "llvm/CodeGen/Passes.h"
223dac3a9bSDimitry Andric #include "llvm/CodeGen/RegAllocRegistry.h"
233ca95b02SDimitry Andric #include "llvm/CodeGen/TargetPassConfig.h"
243dac3a9bSDimitry Andric #include "llvm/IR/Function.h"
253dac3a9bSDimitry Andric #include "llvm/Support/TargetRegistry.h"
263dac3a9bSDimitry Andric #include "llvm/Target/TargetOptions.h"
273dac3a9bSDimitry Andric #include "llvm/Transforms/Scalar.h"
283dac3a9bSDimitry Andric using namespace llvm;
293dac3a9bSDimitry Andric 
303dac3a9bSDimitry Andric #define DEBUG_TYPE "wasm"
313dac3a9bSDimitry Andric 
32d88c1a5aSDimitry Andric // Emscripten's asm.js-style exception handling
33d88c1a5aSDimitry Andric static cl::opt<bool> EnableEmException(
34d88c1a5aSDimitry Andric     "enable-emscripten-cxx-exceptions",
35d88c1a5aSDimitry Andric     cl::desc("WebAssembly Emscripten-style exception handling"),
36d88c1a5aSDimitry Andric     cl::init(false));
37d88c1a5aSDimitry Andric 
38d88c1a5aSDimitry Andric // Emscripten's asm.js-style setjmp/longjmp handling
39d88c1a5aSDimitry Andric static cl::opt<bool> EnableEmSjLj(
40d88c1a5aSDimitry Andric     "enable-emscripten-sjlj",
41d88c1a5aSDimitry Andric     cl::desc("WebAssembly Emscripten-style setjmp/longjmp handling"),
42d88c1a5aSDimitry Andric     cl::init(false));
43d88c1a5aSDimitry Andric 
443dac3a9bSDimitry Andric extern "C" void LLVMInitializeWebAssemblyTarget() {
453dac3a9bSDimitry Andric   // Register the target.
46d88c1a5aSDimitry Andric   RegisterTargetMachine<WebAssemblyTargetMachine> X(
47d88c1a5aSDimitry Andric       getTheWebAssemblyTarget32());
48d88c1a5aSDimitry Andric   RegisterTargetMachine<WebAssemblyTargetMachine> Y(
49d88c1a5aSDimitry Andric       getTheWebAssemblyTarget64());
50d88c1a5aSDimitry Andric 
51d88c1a5aSDimitry Andric   // Register exception handling pass to opt
52d88c1a5aSDimitry Andric   initializeWebAssemblyLowerEmscriptenEHSjLjPass(
53d88c1a5aSDimitry Andric       *PassRegistry::getPassRegistry());
543dac3a9bSDimitry Andric }
553dac3a9bSDimitry Andric 
563dac3a9bSDimitry Andric //===----------------------------------------------------------------------===//
573dac3a9bSDimitry Andric // WebAssembly Lowering public interface.
583dac3a9bSDimitry Andric //===----------------------------------------------------------------------===//
593dac3a9bSDimitry Andric 
603ca95b02SDimitry Andric static Reloc::Model getEffectiveRelocModel(Optional<Reloc::Model> RM) {
613ca95b02SDimitry Andric   if (!RM.hasValue())
623ca95b02SDimitry Andric     return Reloc::PIC_;
633ca95b02SDimitry Andric   return *RM;
643ca95b02SDimitry Andric }
653ca95b02SDimitry Andric 
663dac3a9bSDimitry Andric /// Create an WebAssembly architecture model.
673dac3a9bSDimitry Andric ///
683dac3a9bSDimitry Andric WebAssemblyTargetMachine::WebAssemblyTargetMachine(
693dac3a9bSDimitry Andric     const Target &T, const Triple &TT, StringRef CPU, StringRef FS,
703ca95b02SDimitry Andric     const TargetOptions &Options, Optional<Reloc::Model> RM,
712cab237bSDimitry Andric     Optional<CodeModel::Model> CM, CodeGenOpt::Level OL, bool JIT)
72444ed5c5SDimitry Andric     : LLVMTargetMachine(T,
73444ed5c5SDimitry Andric                         TT.isArch64Bit() ? "e-m:e-p:64:64-i64:64-n32:64-S128"
74444ed5c5SDimitry Andric                                          : "e-m:e-p:32:32-i64:64-n32:64-S128",
753ca95b02SDimitry Andric                         TT, CPU, FS, Options, getEffectiveRelocModel(RM),
762cab237bSDimitry Andric                         CM ? *CM : CodeModel::Large, OL),
777a7e6055SDimitry Andric       TLOF(TT.isOSBinFormatELF() ?
787a7e6055SDimitry Andric               static_cast<TargetLoweringObjectFile*>(
797a7e6055SDimitry Andric                   new WebAssemblyTargetObjectFileELF()) :
807a7e6055SDimitry Andric               static_cast<TargetLoweringObjectFile*>(
817a7e6055SDimitry Andric                   new WebAssemblyTargetObjectFile())) {
82d88c1a5aSDimitry Andric   // WebAssembly type-checks instructions, but a noreturn function with a return
837d523365SDimitry Andric   // type that doesn't match the context will cause a check failure. So we lower
847d523365SDimitry Andric   // LLVM 'unreachable' to ISD::TRAP and then lower that to WebAssembly's
85d88c1a5aSDimitry Andric   // 'unreachable' instructions which is meant for that case.
867d523365SDimitry Andric   this->Options.TrapUnreachable = true;
877d523365SDimitry Andric 
887a7e6055SDimitry Andric   // WebAssembly treats each function as an independent unit. Force
897a7e6055SDimitry Andric   // -ffunction-sections, effectively, so that we can emit them independently.
907a7e6055SDimitry Andric   if (!TT.isOSBinFormatELF()) {
917a7e6055SDimitry Andric     this->Options.FunctionSections = true;
927a7e6055SDimitry Andric     this->Options.DataSections = true;
937a7e6055SDimitry Andric     this->Options.UniqueSectionNames = true;
947a7e6055SDimitry Andric   }
957a7e6055SDimitry Andric 
963dac3a9bSDimitry Andric   initAsmInfo();
973dac3a9bSDimitry Andric 
983ca95b02SDimitry Andric   // Note that we don't use setRequiresStructuredCFG(true). It disables
993ca95b02SDimitry Andric   // optimizations than we're ok with, and want, such as critical edge
1003ca95b02SDimitry Andric   // splitting and tail merging.
1013dac3a9bSDimitry Andric }
1023dac3a9bSDimitry Andric 
1033dac3a9bSDimitry Andric WebAssemblyTargetMachine::~WebAssemblyTargetMachine() {}
1043dac3a9bSDimitry Andric 
1053dac3a9bSDimitry Andric const WebAssemblySubtarget *
1063dac3a9bSDimitry Andric WebAssemblyTargetMachine::getSubtargetImpl(const Function &F) const {
1073dac3a9bSDimitry Andric   Attribute CPUAttr = F.getFnAttribute("target-cpu");
1083dac3a9bSDimitry Andric   Attribute FSAttr = F.getFnAttribute("target-features");
1093dac3a9bSDimitry Andric 
1103dac3a9bSDimitry Andric   std::string CPU = !CPUAttr.hasAttribute(Attribute::None)
1113dac3a9bSDimitry Andric                         ? CPUAttr.getValueAsString().str()
1123dac3a9bSDimitry Andric                         : TargetCPU;
1133dac3a9bSDimitry Andric   std::string FS = !FSAttr.hasAttribute(Attribute::None)
1143dac3a9bSDimitry Andric                        ? FSAttr.getValueAsString().str()
1153dac3a9bSDimitry Andric                        : TargetFS;
1163dac3a9bSDimitry Andric 
1173dac3a9bSDimitry Andric   auto &I = SubtargetMap[CPU + FS];
1183dac3a9bSDimitry Andric   if (!I) {
1193dac3a9bSDimitry Andric     // This needs to be done before we create a new subtarget since any
1203dac3a9bSDimitry Andric     // creation will depend on the TM and the code generation flags on the
1213dac3a9bSDimitry Andric     // function that reside in TargetOptions.
1223dac3a9bSDimitry Andric     resetTargetOptions(F);
1237d523365SDimitry Andric     I = llvm::make_unique<WebAssemblySubtarget>(TargetTriple, CPU, FS, *this);
1243dac3a9bSDimitry Andric   }
1253dac3a9bSDimitry Andric   return I.get();
1263dac3a9bSDimitry Andric }
1273dac3a9bSDimitry Andric 
1283dac3a9bSDimitry Andric namespace {
1293dac3a9bSDimitry Andric /// WebAssembly Code Generator Pass Configuration Options.
1303dac3a9bSDimitry Andric class WebAssemblyPassConfig final : public TargetPassConfig {
1313dac3a9bSDimitry Andric public:
132f9448bf3SDimitry Andric   WebAssemblyPassConfig(WebAssemblyTargetMachine &TM, PassManagerBase &PM)
1333dac3a9bSDimitry Andric       : TargetPassConfig(TM, PM) {}
1343dac3a9bSDimitry Andric 
1353dac3a9bSDimitry Andric   WebAssemblyTargetMachine &getWebAssemblyTargetMachine() const {
1363dac3a9bSDimitry Andric     return getTM<WebAssemblyTargetMachine>();
1373dac3a9bSDimitry Andric   }
1383dac3a9bSDimitry Andric 
1393dac3a9bSDimitry Andric   FunctionPass *createTargetRegisterAllocator(bool) override;
1403dac3a9bSDimitry Andric 
1413dac3a9bSDimitry Andric   void addIRPasses() override;
1423dac3a9bSDimitry Andric   bool addInstSelector() override;
1433dac3a9bSDimitry Andric   void addPostRegAlloc() override;
1443ca95b02SDimitry Andric   bool addGCPasses() override { return false; }
1453dac3a9bSDimitry Andric   void addPreEmitPass() override;
1463dac3a9bSDimitry Andric };
1473dac3a9bSDimitry Andric } // end anonymous namespace
1483dac3a9bSDimitry Andric 
1493dac3a9bSDimitry Andric TargetIRAnalysis WebAssemblyTargetMachine::getTargetIRAnalysis() {
1507d523365SDimitry Andric   return TargetIRAnalysis([this](const Function &F) {
1513dac3a9bSDimitry Andric     return TargetTransformInfo(WebAssemblyTTIImpl(this, F));
1523dac3a9bSDimitry Andric   });
1533dac3a9bSDimitry Andric }
1543dac3a9bSDimitry Andric 
1553dac3a9bSDimitry Andric TargetPassConfig *
1563dac3a9bSDimitry Andric WebAssemblyTargetMachine::createPassConfig(PassManagerBase &PM) {
157f9448bf3SDimitry Andric   return new WebAssemblyPassConfig(*this, PM);
1583dac3a9bSDimitry Andric }
1593dac3a9bSDimitry Andric 
1603dac3a9bSDimitry Andric FunctionPass *WebAssemblyPassConfig::createTargetRegisterAllocator(bool) {
1613dac3a9bSDimitry Andric   return nullptr; // No reg alloc
1623dac3a9bSDimitry Andric }
1633dac3a9bSDimitry Andric 
1643dac3a9bSDimitry Andric //===----------------------------------------------------------------------===//
1653dac3a9bSDimitry Andric // The following functions are called from lib/CodeGen/Passes.cpp to modify
1663dac3a9bSDimitry Andric // the CodeGen pass sequence.
1673dac3a9bSDimitry Andric //===----------------------------------------------------------------------===//
1683dac3a9bSDimitry Andric 
1693dac3a9bSDimitry Andric void WebAssemblyPassConfig::addIRPasses() {
1703dac3a9bSDimitry Andric   if (TM->Options.ThreadModel == ThreadModel::Single)
1717d523365SDimitry Andric     // In "single" mode, atomics get lowered to non-atomics.
1723dac3a9bSDimitry Andric     addPass(createLowerAtomicPass());
1733dac3a9bSDimitry Andric   else
1743dac3a9bSDimitry Andric     // Expand some atomic operations. WebAssemblyTargetLowering has hooks which
1753dac3a9bSDimitry Andric     // control specifically what gets lowered.
176d8866befSDimitry Andric     addPass(createAtomicExpandPass());
1773dac3a9bSDimitry Andric 
1782cab237bSDimitry Andric   // Lower .llvm.global_dtors into .llvm_global_ctors with __cxa_atexit calls.
1792cab237bSDimitry Andric   addPass(createWebAssemblyLowerGlobalDtors());
1802cab237bSDimitry Andric 
18124e2fe98SDimitry Andric   // Fix function bitcasts, as WebAssembly requires caller and callee signatures
18224e2fe98SDimitry Andric   // to match.
18324e2fe98SDimitry Andric   addPass(createWebAssemblyFixFunctionBitcasts());
18424e2fe98SDimitry Andric 
1857d523365SDimitry Andric   // Optimize "returned" function attributes.
1863ca95b02SDimitry Andric   if (getOptLevel() != CodeGenOpt::None)
1877d523365SDimitry Andric     addPass(createWebAssemblyOptimizeReturned());
1887d523365SDimitry Andric 
189d88c1a5aSDimitry Andric   // If exception handling is not enabled and setjmp/longjmp handling is
190d88c1a5aSDimitry Andric   // enabled, we lower invokes into calls and delete unreachable landingpad
191d88c1a5aSDimitry Andric   // blocks. Lowering invokes when there is no EH support is done in
192d88c1a5aSDimitry Andric   // TargetPassConfig::addPassesToHandleExceptions, but this runs after this
193d88c1a5aSDimitry Andric   // function and SjLj handling expects all invokes to be lowered before.
194d88c1a5aSDimitry Andric   if (!EnableEmException) {
195d88c1a5aSDimitry Andric     addPass(createLowerInvokePass());
196d88c1a5aSDimitry Andric     // The lower invoke pass may create unreachable code. Remove it in order not
197d88c1a5aSDimitry Andric     // to process dead blocks in setjmp/longjmp handling.
198d88c1a5aSDimitry Andric     addPass(createUnreachableBlockEliminationPass());
199d88c1a5aSDimitry Andric   }
200d88c1a5aSDimitry Andric 
201d88c1a5aSDimitry Andric   // Handle exceptions and setjmp/longjmp if enabled.
202d88c1a5aSDimitry Andric   if (EnableEmException || EnableEmSjLj)
203d88c1a5aSDimitry Andric     addPass(createWebAssemblyLowerEmscriptenEHSjLj(EnableEmException,
204d88c1a5aSDimitry Andric                                                    EnableEmSjLj));
205d88c1a5aSDimitry Andric 
2063dac3a9bSDimitry Andric   TargetPassConfig::addIRPasses();
2073dac3a9bSDimitry Andric }
2083dac3a9bSDimitry Andric 
2093dac3a9bSDimitry Andric bool WebAssemblyPassConfig::addInstSelector() {
2107d523365SDimitry Andric   (void)TargetPassConfig::addInstSelector();
2113dac3a9bSDimitry Andric   addPass(
2123dac3a9bSDimitry Andric       createWebAssemblyISelDag(getWebAssemblyTargetMachine(), getOptLevel()));
2137d523365SDimitry Andric   // Run the argument-move pass immediately after the ScheduleDAG scheduler
2147d523365SDimitry Andric   // so that we can fix up the ARGUMENT instructions before anything else
2157d523365SDimitry Andric   // sees them in the wrong place.
2167d523365SDimitry Andric   addPass(createWebAssemblyArgumentMove());
2173ca95b02SDimitry Andric   // Set the p2align operands. This information is present during ISel, however
2183ca95b02SDimitry Andric   // it's inconvenient to collect. Collect it now, and update the immediate
2193ca95b02SDimitry Andric   // operands.
2203ca95b02SDimitry Andric   addPass(createWebAssemblySetP2AlignOperands());
2213dac3a9bSDimitry Andric   return false;
2223dac3a9bSDimitry Andric }
2233dac3a9bSDimitry Andric 
2247d523365SDimitry Andric void WebAssemblyPassConfig::addPostRegAlloc() {
2257d523365SDimitry Andric   // TODO: The following CodeGen passes don't currently support code containing
2267d523365SDimitry Andric   // virtual registers. Consider removing their restrictions and re-enabling
2277d523365SDimitry Andric   // them.
2283ca95b02SDimitry Andric 
2293ca95b02SDimitry Andric   // Has no asserts of its own, but was not written to handle virtual regs.
2303ca95b02SDimitry Andric   disablePass(&ShrinkWrapID);
2313ca95b02SDimitry Andric 
232d88c1a5aSDimitry Andric   // These functions all require the NoVRegs property.
2337d523365SDimitry Andric   disablePass(&MachineCopyPropagationID);
2343ca95b02SDimitry Andric   disablePass(&PostRASchedulerID);
2353ca95b02SDimitry Andric   disablePass(&FuncletLayoutID);
2363ca95b02SDimitry Andric   disablePass(&StackMapLivenessID);
2373ca95b02SDimitry Andric   disablePass(&LiveDebugValuesID);
2383ca95b02SDimitry Andric   disablePass(&PatchableFunctionID);
2397d523365SDimitry Andric 
2407d523365SDimitry Andric   TargetPassConfig::addPostRegAlloc();
2417d523365SDimitry Andric }
2427d523365SDimitry Andric 
2437d523365SDimitry Andric void WebAssemblyPassConfig::addPreEmitPass() {
2447d523365SDimitry Andric   TargetPassConfig::addPreEmitPass();
2457d523365SDimitry Andric 
2463ca95b02SDimitry Andric   // Now that we have a prologue and epilogue and all frame indices are
2473ca95b02SDimitry Andric   // rewritten, eliminate SP and FP. This allows them to be stackified,
2483ca95b02SDimitry Andric   // colored, and numbered with the rest of the registers.
2493ca95b02SDimitry Andric   addPass(createWebAssemblyReplacePhysRegs());
2503ca95b02SDimitry Andric 
251d88c1a5aSDimitry Andric   // Rewrite pseudo call_indirect instructions as real instructions.
252d88c1a5aSDimitry Andric   // This needs to run before register stackification, because we change the
253d88c1a5aSDimitry Andric   // order of the arguments.
254d88c1a5aSDimitry Andric   addPass(createWebAssemblyCallIndirectFixup());
255d88c1a5aSDimitry Andric 
2563ca95b02SDimitry Andric   if (getOptLevel() != CodeGenOpt::None) {
2573ca95b02SDimitry Andric     // LiveIntervals isn't commonly run this late. Re-establish preconditions.
2583ca95b02SDimitry Andric     addPass(createWebAssemblyPrepareForLiveIntervals());
2593ca95b02SDimitry Andric 
2603ca95b02SDimitry Andric     // Depend on LiveIntervals and perform some optimizations on it.
2613ca95b02SDimitry Andric     addPass(createWebAssemblyOptimizeLiveIntervals());
2623ca95b02SDimitry Andric 
2633ca95b02SDimitry Andric     // Prepare store instructions for register stackifying.
2643ca95b02SDimitry Andric     addPass(createWebAssemblyStoreResults());
2653ca95b02SDimitry Andric 
266d88c1a5aSDimitry Andric     // Mark registers as representing wasm's value stack. This is a key
2673ca95b02SDimitry Andric     // code-compression technique in WebAssembly. We run this pass (and
2683ca95b02SDimitry Andric     // StoreResults above) very late, so that it sees as much code as possible,
2693ca95b02SDimitry Andric     // including code emitted by PEI and expanded by late tail duplication.
2703ca95b02SDimitry Andric     addPass(createWebAssemblyRegStackify());
2713ca95b02SDimitry Andric 
2723ca95b02SDimitry Andric     // Run the register coloring pass to reduce the total number of registers.
2733ca95b02SDimitry Andric     // This runs after stackification so that it doesn't consider registers
2743ca95b02SDimitry Andric     // that become stackified.
2753ca95b02SDimitry Andric     addPass(createWebAssemblyRegColoring());
2763ca95b02SDimitry Andric   }
2773ca95b02SDimitry Andric 
2787a7e6055SDimitry Andric   // Eliminate multiple-entry loops. Do this before inserting explicit get_local
2797a7e6055SDimitry Andric   // and set_local operators because we create a new variable that we want
2807a7e6055SDimitry Andric   // converted into a local.
2817a7e6055SDimitry Andric   addPass(createWebAssemblyFixIrreducibleControlFlow());
2827a7e6055SDimitry Andric 
283d88c1a5aSDimitry Andric   // Insert explicit get_local and set_local operators.
284d88c1a5aSDimitry Andric   addPass(createWebAssemblyExplicitLocals());
285d88c1a5aSDimitry Andric 
2867a7e6055SDimitry Andric   // Sort the blocks of the CFG into topological order, a prerequisite for
2877a7e6055SDimitry Andric   // BLOCK and LOOP markers.
2887a7e6055SDimitry Andric   addPass(createWebAssemblyCFGSort());
2893ca95b02SDimitry Andric 
2907a7e6055SDimitry Andric   // Insert BLOCK and LOOP markers.
2917d523365SDimitry Andric   addPass(createWebAssemblyCFGStackify());
2927d523365SDimitry Andric 
2937d523365SDimitry Andric   // Lower br_unless into br_if.
2947d523365SDimitry Andric   addPass(createWebAssemblyLowerBrUnless());
2957d523365SDimitry Andric 
2963ca95b02SDimitry Andric   // Perform the very last peephole optimizations on the code.
2973ca95b02SDimitry Andric   if (getOptLevel() != CodeGenOpt::None)
2983ca95b02SDimitry Andric     addPass(createWebAssemblyPeephole());
2993ca95b02SDimitry Andric 
3007d523365SDimitry Andric   // Create a mapping from LLVM CodeGen virtual registers to wasm registers.
3017d523365SDimitry Andric   addPass(createWebAssemblyRegNumbering());
3027d523365SDimitry Andric }
303