mirror of
https://github.com/Gericom/teak-llvm.git
synced 2025-06-22 21:15:40 -04:00

Move the register stackification and coloring passes to run very late, after PEI, tail duplication, and most other passes. This means that all code emitted and expanded by those passes is now exposed to these passes. This also eliminates the need for prologue/epilogue code to be manually stackified, which significantly simplifies the code. This does require running LiveIntervals a second time. It's useful to think of these late passes not as late optimization passes, but as a domain-specific compression algorithm based on knowledge of liveness information. It's used to compress the code after all conventional optimizations are complete, which is why it uses LiveIntervals at a phase when actual optimization passes don't typically need it. Differential Revision: http://reviews.llvm.org/D20075 llvm-svn: 269012
236 lines
8.9 KiB
C++
236 lines
8.9 KiB
C++
//===- WebAssemblyTargetMachine.cpp - Define TargetMachine for WebAssembly -==//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
///
|
|
/// \file
|
|
/// \brief This file defines the WebAssembly-specific subclass of TargetMachine.
|
|
///
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "WebAssembly.h"
|
|
#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
|
|
#include "WebAssemblyTargetMachine.h"
|
|
#include "WebAssemblyTargetObjectFile.h"
|
|
#include "WebAssemblyTargetTransformInfo.h"
|
|
#include "llvm/CodeGen/MachineFunctionPass.h"
|
|
#include "llvm/CodeGen/Passes.h"
|
|
#include "llvm/CodeGen/RegAllocRegistry.h"
|
|
#include "llvm/CodeGen/TargetPassConfig.h"
|
|
#include "llvm/IR/Function.h"
|
|
#include "llvm/Support/TargetRegistry.h"
|
|
#include "llvm/Target/TargetOptions.h"
|
|
#include "llvm/Transforms/Scalar.h"
|
|
using namespace llvm;
|
|
|
|
#define DEBUG_TYPE "wasm"
|
|
|
|
extern "C" void LLVMInitializeWebAssemblyTarget() {
|
|
// Register the target.
|
|
RegisterTargetMachine<WebAssemblyTargetMachine> X(TheWebAssemblyTarget32);
|
|
RegisterTargetMachine<WebAssemblyTargetMachine> Y(TheWebAssemblyTarget64);
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// WebAssembly Lowering public interface.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// Create an WebAssembly architecture model.
|
|
///
|
|
WebAssemblyTargetMachine::WebAssemblyTargetMachine(
|
|
const Target &T, const Triple &TT, StringRef CPU, StringRef FS,
|
|
const TargetOptions &Options, Reloc::Model RM, CodeModel::Model CM,
|
|
CodeGenOpt::Level OL)
|
|
: LLVMTargetMachine(T,
|
|
TT.isArch64Bit() ? "e-m:e-p:64:64-i64:64-n32:64-S128"
|
|
: "e-m:e-p:32:32-i64:64-n32:64-S128",
|
|
TT, CPU, FS, Options, RM, CM, OL),
|
|
TLOF(make_unique<WebAssemblyTargetObjectFile>()) {
|
|
// WebAssembly type-checks expressions, but a noreturn function with a return
|
|
// type that doesn't match the context will cause a check failure. So we lower
|
|
// LLVM 'unreachable' to ISD::TRAP and then lower that to WebAssembly's
|
|
// 'unreachable' expression which is meant for that case.
|
|
this->Options.TrapUnreachable = true;
|
|
|
|
initAsmInfo();
|
|
|
|
// Note that we don't use setRequiresStructuredCFG(true). It disables
|
|
// optimizations than we're ok with, and want, such as critical edge
|
|
// splitting and tail merging.
|
|
}
|
|
|
|
WebAssemblyTargetMachine::~WebAssemblyTargetMachine() {}
|
|
|
|
const WebAssemblySubtarget *
|
|
WebAssemblyTargetMachine::getSubtargetImpl(const Function &F) const {
|
|
Attribute CPUAttr = F.getFnAttribute("target-cpu");
|
|
Attribute FSAttr = F.getFnAttribute("target-features");
|
|
|
|
std::string CPU = !CPUAttr.hasAttribute(Attribute::None)
|
|
? CPUAttr.getValueAsString().str()
|
|
: TargetCPU;
|
|
std::string FS = !FSAttr.hasAttribute(Attribute::None)
|
|
? FSAttr.getValueAsString().str()
|
|
: TargetFS;
|
|
|
|
auto &I = SubtargetMap[CPU + FS];
|
|
if (!I) {
|
|
// This needs to be done before we create a new subtarget since any
|
|
// creation will depend on the TM and the code generation flags on the
|
|
// function that reside in TargetOptions.
|
|
resetTargetOptions(F);
|
|
I = llvm::make_unique<WebAssemblySubtarget>(TargetTriple, CPU, FS, *this);
|
|
}
|
|
return I.get();
|
|
}
|
|
|
|
namespace {
|
|
/// WebAssembly Code Generator Pass Configuration Options.
|
|
class WebAssemblyPassConfig final : public TargetPassConfig {
|
|
public:
|
|
WebAssemblyPassConfig(WebAssemblyTargetMachine *TM, PassManagerBase &PM)
|
|
: TargetPassConfig(TM, PM) {}
|
|
|
|
WebAssemblyTargetMachine &getWebAssemblyTargetMachine() const {
|
|
return getTM<WebAssemblyTargetMachine>();
|
|
}
|
|
|
|
FunctionPass *createTargetRegisterAllocator(bool) override;
|
|
|
|
void addIRPasses() override;
|
|
bool addInstSelector() override;
|
|
void addPostRegAlloc() override;
|
|
bool addGCPasses() override { return false; }
|
|
void addPreEmitPass() override;
|
|
};
|
|
} // end anonymous namespace
|
|
|
|
TargetIRAnalysis WebAssemblyTargetMachine::getTargetIRAnalysis() {
|
|
return TargetIRAnalysis([this](const Function &F) {
|
|
return TargetTransformInfo(WebAssemblyTTIImpl(this, F));
|
|
});
|
|
}
|
|
|
|
TargetPassConfig *
|
|
WebAssemblyTargetMachine::createPassConfig(PassManagerBase &PM) {
|
|
return new WebAssemblyPassConfig(this, PM);
|
|
}
|
|
|
|
FunctionPass *WebAssemblyPassConfig::createTargetRegisterAllocator(bool) {
|
|
return nullptr; // No reg alloc
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// The following functions are called from lib/CodeGen/Passes.cpp to modify
|
|
// the CodeGen pass sequence.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
void WebAssemblyPassConfig::addIRPasses() {
|
|
if (TM->Options.ThreadModel == ThreadModel::Single)
|
|
// In "single" mode, atomics get lowered to non-atomics.
|
|
addPass(createLowerAtomicPass());
|
|
else
|
|
// Expand some atomic operations. WebAssemblyTargetLowering has hooks which
|
|
// control specifically what gets lowered.
|
|
addPass(createAtomicExpandPass(TM));
|
|
|
|
// Optimize "returned" function attributes.
|
|
if (getOptLevel() != CodeGenOpt::None)
|
|
addPass(createWebAssemblyOptimizeReturned());
|
|
|
|
TargetPassConfig::addIRPasses();
|
|
}
|
|
|
|
bool WebAssemblyPassConfig::addInstSelector() {
|
|
(void)TargetPassConfig::addInstSelector();
|
|
addPass(
|
|
createWebAssemblyISelDag(getWebAssemblyTargetMachine(), getOptLevel()));
|
|
// Run the argument-move pass immediately after the ScheduleDAG scheduler
|
|
// so that we can fix up the ARGUMENT instructions before anything else
|
|
// sees them in the wrong place.
|
|
addPass(createWebAssemblyArgumentMove());
|
|
// Set the p2align operands. This information is present during ISel, however
|
|
// it's inconvenient to collect. Collect it now, and update the immediate
|
|
// operands.
|
|
addPass(createWebAssemblySetP2AlignOperands());
|
|
return false;
|
|
}
|
|
|
|
void WebAssemblyPassConfig::addPostRegAlloc() {
|
|
// TODO: The following CodeGen passes don't currently support code containing
|
|
// virtual registers. Consider removing their restrictions and re-enabling
|
|
// them.
|
|
|
|
// Has no asserts of its own, but was not written to handle virtual regs.
|
|
disablePass(&ShrinkWrapID);
|
|
// We use our own PrologEpilogInserter which is very slightly modified to
|
|
// tolerate virtual registers.
|
|
disablePass(&PrologEpilogCodeInserterID);
|
|
|
|
// These functions all require the AllVRegsAllocated property.
|
|
disablePass(&MachineCopyPropagationID);
|
|
disablePass(&PostRASchedulerID);
|
|
disablePass(&FuncletLayoutID);
|
|
disablePass(&StackMapLivenessID);
|
|
disablePass(&LiveDebugValuesID);
|
|
disablePass(&PatchableFunctionID);
|
|
|
|
TargetPassConfig::addPostRegAlloc();
|
|
|
|
// Run WebAssembly's version of the PrologEpilogInserter. Target-independent
|
|
// PEI runs after PostRegAlloc and after ShrinkWrap. Putting it here will run
|
|
// PEI before ShrinkWrap but otherwise in the same position in the order.
|
|
addPass(createWebAssemblyPEI());
|
|
}
|
|
|
|
void WebAssemblyPassConfig::addPreEmitPass() {
|
|
TargetPassConfig::addPreEmitPass();
|
|
|
|
// Now that we have a prologue and epilogue and all frame indices are
|
|
// rewritten, eliminate SP and FP. This allows them to be stackified,
|
|
// colored, and numbered with the rest of the registers.
|
|
addPass(createWebAssemblyReplacePhysRegs());
|
|
|
|
if (getOptLevel() != CodeGenOpt::None) {
|
|
// LiveIntervals isn't commonly run this late. Re-establish preconditions.
|
|
addPass(createWebAssemblyPrepareForLiveIntervals());
|
|
|
|
// Depend on LiveIntervals and perform some optimizations on it.
|
|
addPass(createWebAssemblyOptimizeLiveIntervals());
|
|
|
|
// Prepare store instructions for register stackifying.
|
|
addPass(createWebAssemblyStoreResults());
|
|
|
|
// Mark registers as representing wasm's expression stack. This is a key
|
|
// code-compression technique in WebAssembly. We run this pass (and
|
|
// StoreResults above) very late, so that it sees as much code as possible,
|
|
// including code emitted by PEI and expanded by late tail duplication.
|
|
addPass(createWebAssemblyRegStackify());
|
|
|
|
// Run the register coloring pass to reduce the total number of registers.
|
|
// This runs after stackification so that it doesn't consider registers
|
|
// that become stackified.
|
|
addPass(createWebAssemblyRegColoring());
|
|
}
|
|
|
|
// Eliminate multiple-entry loops.
|
|
addPass(createWebAssemblyFixIrreducibleControlFlow());
|
|
|
|
// Put the CFG in structured form; insert BLOCK and LOOP markers.
|
|
addPass(createWebAssemblyCFGStackify());
|
|
|
|
// Lower br_unless into br_if.
|
|
addPass(createWebAssemblyLowerBrUnless());
|
|
|
|
// Create a mapping from LLVM CodeGen virtual registers to wasm registers.
|
|
addPass(createWebAssemblyRegNumbering());
|
|
|
|
// Perform the very last peephole optimizations on the code.
|
|
if (getOptLevel() != CodeGenOpt::None)
|
|
addPass(createWebAssemblyPeephole());
|
|
}
|