summaryrefslogtreecommitdiffstats
path: root/llvm/lib
diff options
context:
space:
mode:
authorDan Gohman <dan433584@gmail.com>2016-05-21 00:21:56 +0000
committerDan Gohman <dan433584@gmail.com>2016-05-21 00:21:56 +0000
commitb7c2400fa744c032dc96a2e180f24425911bc794 (patch)
tree484ce7a4b2401ae6b97de9e54543eb83d598703b /llvm/lib
parent2907e51246a8cf0a440fa1767f94dc10eda195eb (diff)
downloadbcm5719-llvm-b7c2400fa744c032dc96a2e180f24425911bc794.tar.gz
bcm5719-llvm-b7c2400fa744c032dc96a2e180f24425911bc794.zip
[WebAssembly] Optimize away return instructions using fallthroughs.
This saves a small amount of code size, and is a first small step toward passing values on the stack across block boundaries. Differential Review: http://reviews.llvm.org/D20450 llvm-svn: 270294
Diffstat (limited to 'llvm/lib')
-rw-r--r--llvm/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp4
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp24
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td8
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h6
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyPeephole.cpp73
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp6
6 files changed, 111 insertions, 10 deletions
diff --git a/llvm/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp b/llvm/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp
index a450a24bd49..267d716dd1d 100644
--- a/llvm/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp
+++ b/llvm/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp
@@ -145,9 +145,9 @@ void WebAssemblyInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
if (int(WAReg) >= 0)
printRegName(O, WAReg);
else if (OpNo >= MII.get(MI->getOpcode()).getNumDefs())
- O << "$pop" << (WAReg & INT32_MAX);
+ O << "$pop" << WebAssemblyFunctionInfo::getWARegStackId(WAReg);
else if (WAReg != WebAssemblyFunctionInfo::UnusedReg)
- O << "$push" << (WAReg & INT32_MAX);
+ O << "$push" << WebAssemblyFunctionInfo::getWARegStackId(WAReg);
else
O << "$drop";
// Add a '=' suffix if this is a def.
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
index d7a753d978b..64128bf031e 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
@@ -201,6 +201,30 @@ void WebAssemblyAsmPrinter::EmitInstruction(const MachineInstr *MI) {
// These represent values which are live into the function entry, so there's
// no instruction to emit.
break;
+ case WebAssembly::FALLTHROUGH_RETURN_I32:
+ case WebAssembly::FALLTHROUGH_RETURN_I64:
+ case WebAssembly::FALLTHROUGH_RETURN_F32:
+ case WebAssembly::FALLTHROUGH_RETURN_F64: {
+ // These instructions represent the implicit return at the end of a
+ // function body. The operand is always a pop.
+ assert(MFI->isVRegStackified(MI->getOperand(0).getReg()));
+
+ if (isVerbose()) {
+ OutStreamer->AddComment("fallthrough-return: $pop" +
+ utostr(MFI->getWARegStackId(
+ MFI->getWAReg(MI->getOperand(0).getReg()))));
+ OutStreamer->AddBlankLine();
+ }
+ break;
+ }
+ case WebAssembly::FALLTHROUGH_RETURN_VOID:
+ // This instruction represents the implicit return at the end of a
+ // function body with no return value.
+ if (isVerbose()) {
+ OutStreamer->AddComment("fallthrough-return");
+ OutStreamer->AddBlankLine();
+ }
+ break;
default: {
WebAssemblyMCInstLower MCInstLowering(OutContext, *this);
MCInst TmpInst;
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td
index ba4e1f989a9..444e275c6eb 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td
@@ -71,6 +71,10 @@ def END_LOOP : I<(outs), (ins), [], "end_loop">;
multiclass RETURN<WebAssemblyRegClass vt> {
def RETURN_#vt : I<(outs), (ins vt:$val), [(WebAssemblyreturn vt:$val)],
"return \t$val">;
+ // Equivalent to RETURN_#vt, for use at the end of a function when wasm
+ // semantics return by falling off the end of the block.
+ let isCodeGenOnly = 1 in
+ def FALLTHROUGH_RETURN_#vt : I<(outs), (ins vt:$val), []>;
}
let isTerminator = 1, hasCtrlDep = 1, isBarrier = 1 in {
@@ -80,6 +84,10 @@ let isReturn = 1 in {
defm : RETURN<F32>;
defm : RETURN<F64>;
def RETURN_VOID : I<(outs), (ins), [(WebAssemblyreturn)], "return">;
+
+ // This is to RETURN_VOID what FALLTHROUGH_RETURN_#vt is to RETURN_#vt.
+ let isCodeGenOnly = 1 in
+ def FALLTHROUGH_RETURN_VOID : I<(outs), (ins), []>;
} // isReturn = 1
def UNREACHABLE : I<(outs), (ins), [(trap)], "unreachable">;
} // isTerminator = 1, hasCtrlDep = 1, isBarrier = 1
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h b/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h
index 79950a6b257..c2f695db4a0 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h
@@ -86,6 +86,12 @@ class WebAssemblyFunctionInfo final : public MachineFunctionInfo {
assert(VReg = WARegs.size());
WARegs.push_back(WAReg);
}
+
+ // For a given stackified WAReg, return the id number to print with push/pop.
+ static unsigned getWARegStackId(unsigned Reg) {
+ assert(Reg & INT32_MIN);
+ return Reg & INT32_MAX;
+ }
};
} // end namespace llvm
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyPeephole.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyPeephole.cpp
index 19c227d2f94..56d44e6466e 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyPeephole.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyPeephole.cpp
@@ -12,17 +12,23 @@
///
//===----------------------------------------------------------------------===//
-#include "WebAssembly.h"
#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
+#include "WebAssembly.h"
#include "WebAssemblyMachineFunctionInfo.h"
#include "WebAssemblySubtarget.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
using namespace llvm;
#define DEBUG_TYPE "wasm-peephole"
+static cl::opt<bool> DisableWebAssemblyFallthroughReturnOpt(
+ "disable-wasm-fallthrough-return-opt", cl::Hidden,
+ cl::desc("WebAssembly: Disable fallthrough-return optimizations."),
+ cl::init(false));
+
namespace {
class WebAssemblyPeephole final : public MachineFunctionPass {
const char *getPassName() const override {
@@ -50,8 +56,7 @@ FunctionPass *llvm::createWebAssemblyPeephole() {
/// If desirable, rewrite NewReg to a drop register.
static bool MaybeRewriteToDrop(unsigned OldReg, unsigned NewReg,
- MachineOperand &MO,
- WebAssemblyFunctionInfo &MFI,
+ MachineOperand &MO, WebAssemblyFunctionInfo &MFI,
MachineRegisterInfo &MRI) {
bool Changed = false;
if (OldReg == NewReg) {
@@ -60,19 +65,50 @@ static bool MaybeRewriteToDrop(unsigned OldReg, unsigned NewReg,
MO.setReg(NewReg);
MO.setIsDead();
MFI.stackifyVReg(NewReg);
- MFI.addWAReg(NewReg, WebAssemblyFunctionInfo::UnusedReg);
}
return Changed;
}
+static bool MaybeRewriteToFallthrough(MachineInstr &MI, MachineBasicBlock &MBB,
+ const MachineFunction &MF,
+ WebAssemblyFunctionInfo &MFI,
+ MachineRegisterInfo &MRI,
+ const WebAssemblyInstrInfo &TII,
+ unsigned FallthroughOpc,
+ unsigned CopyLocalOpc) {
+ if (DisableWebAssemblyFallthroughReturnOpt)
+ return false;
+ if (&MBB != &MF.back())
+ return false;
+ if (&MI != &MBB.back())
+ return false;
+
+ // If the operand isn't stackified, insert a COPY_LOCAL to read the operand
+ // and stackify it.
+ MachineOperand &MO = MI.getOperand(0);
+ unsigned Reg = MO.getReg();
+ if (!MFI.isVRegStackified(Reg)) {
+ unsigned NewReg = MRI.createVirtualRegister(MRI.getRegClass(Reg));
+ BuildMI(MBB, MI, MI.getDebugLoc(), TII.get(CopyLocalOpc), NewReg)
+ .addReg(Reg);
+ MO.setReg(NewReg);
+ MFI.stackifyVReg(NewReg);
+ }
+
+ // Rewrite the return.
+ MI.setDesc(TII.get(FallthroughOpc));
+ return true;
+}
+
bool WebAssemblyPeephole::runOnMachineFunction(MachineFunction &MF) {
DEBUG({
- dbgs() << "********** Store Results **********\n"
+ dbgs() << "********** Peephole **********\n"
<< "********** Function: " << MF.getName() << '\n';
});
MachineRegisterInfo &MRI = MF.getRegInfo();
WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
+ const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
const WebAssemblyTargetLowering &TLI =
*MF.getSubtarget<WebAssemblySubtarget>().getTargetLowering();
auto &LibInfo = getAnalysis<TargetLibraryInfoWrapperPass>().getTLI();
@@ -127,7 +163,34 @@ bool WebAssemblyPeephole::runOnMachineFunction(MachineFunction &MF) {
}
}
}
+ break;
}
+ // Optimize away an explicit void return at the end of the function.
+ case WebAssembly::RETURN_I32:
+ Changed |= MaybeRewriteToFallthrough(
+ MI, MBB, MF, MFI, MRI, TII, WebAssembly::FALLTHROUGH_RETURN_I32,
+ WebAssembly::COPY_LOCAL_I32);
+ break;
+ case WebAssembly::RETURN_I64:
+ Changed |= MaybeRewriteToFallthrough(
+ MI, MBB, MF, MFI, MRI, TII, WebAssembly::FALLTHROUGH_RETURN_I64,
+ WebAssembly::COPY_LOCAL_I64);
+ break;
+ case WebAssembly::RETURN_F32:
+ Changed |= MaybeRewriteToFallthrough(
+ MI, MBB, MF, MFI, MRI, TII, WebAssembly::FALLTHROUGH_RETURN_F32,
+ WebAssembly::COPY_LOCAL_F32);
+ break;
+ case WebAssembly::RETURN_F64:
+ Changed |= MaybeRewriteToFallthrough(
+ MI, MBB, MF, MFI, MRI, TII, WebAssembly::FALLTHROUGH_RETURN_F64,
+ WebAssembly::COPY_LOCAL_F64);
+ break;
+ case WebAssembly::RETURN_VOID:
+ if (!DisableWebAssemblyFallthroughReturnOpt &&
+ &MBB == &MF.back() && &MI == &MBB.back())
+ MI.setDesc(TII.get(WebAssembly::FALLTHROUGH_RETURN_VOID));
+ break;
}
return Changed;
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
index e4b049dd15d..32154af3c1c 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
@@ -225,10 +225,10 @@ void WebAssemblyPassConfig::addPreEmitPass() {
// 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());
+
+ // Create a mapping from LLVM CodeGen virtual registers to wasm registers.
+ addPass(createWebAssemblyRegNumbering());
}
OpenPOWER on IntegriCloud