Index: lib/Target/WebAssembly/WebAssemblyOptimizeLiveIntervals.cpp =================================================================== --- lib/Target/WebAssembly/WebAssemblyOptimizeLiveIntervals.cpp +++ lib/Target/WebAssembly/WebAssemblyOptimizeLiveIntervals.cpp @@ -58,7 +58,7 @@ char WebAssemblyOptimizeLiveIntervals::ID = 0; INITIALIZE_PASS(WebAssemblyOptimizeLiveIntervals, DEBUG_TYPE, - "Optimize LiveIntervals for WebAssembly", false, false) + "Optimize LiveIntervals for WebAssembly", true, true) FunctionPass *llvm::createWebAssemblyOptimizeLiveIntervals() { return new WebAssemblyOptimizeLiveIntervals(); @@ -89,19 +89,5 @@ SplitLIs.clear(); } - // In PrepareForLiveIntervals, we conservatively inserted IMPLICIT_DEF - // instructions to satisfy LiveIntervals' requirement that all uses be - // dominated by defs. Now that LiveIntervals has computed which of these - // defs are actually needed and which are dead, remove the dead ones. - for (auto MII = MF.begin()->begin(), MIE = MF.begin()->end(); MII != MIE;) { - MachineInstr *MI = &*MII++; - if (MI->isImplicitDef() && MI->getOperand(0).isDead()) { - LiveInterval &LI = LIS.getInterval(MI->getOperand(0).getReg()); - LIS.removeVRegDefAt(LI, LIS.getInstructionIndex(*MI).getRegSlot()); - LIS.RemoveMachineInstrFromMaps(*MI); - MI->eraseFromParent(); - } - } - return false; } Index: lib/Target/WebAssembly/WebAssemblyPrepareForLiveIntervals.cpp =================================================================== --- lib/Target/WebAssembly/WebAssemblyPrepareForLiveIntervals.cpp +++ lib/Target/WebAssembly/WebAssemblyPrepareForLiveIntervals.cpp @@ -7,28 +7,16 @@ //===----------------------------------------------------------------------===// /// /// \file -/// Fix up code to meet LiveInterval's requirements. +/// Re-track liveness analysis before register stackification. /// -/// Some CodeGen passes don't preserve LiveInterval's requirements, because -/// they run after register allocation and it isn't important. However, -/// WebAssembly runs LiveIntervals in a late pass. This pass transforms code -/// to meet LiveIntervals' requirements; primarily, it ensures that all -/// virtual register uses have definitions (IMPLICIT_DEF definitions if -/// nothing else). +/// WebAssembly runs LiveIntervals in a late pass. This pass makes sure the +/// liveness analysis is correctly tracked again before optimizing liveness +/// intervals and register stackification pass. /// //===----------------------------------------------------------------------===// -#include "MCTargetDesc/WebAssemblyMCTargetDesc.h" #include "WebAssembly.h" -#include "WebAssemblyMachineFunctionInfo.h" -#include "WebAssemblySubtarget.h" -#include "WebAssemblyUtilities.h" #include "llvm/CodeGen/MachineFunctionPass.h" -#include "llvm/CodeGen/MachineInstrBuilder.h" -#include "llvm/CodeGen/MachineRegisterInfo.h" -#include "llvm/CodeGen/Passes.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/raw_ostream.h" using namespace llvm; #define DEBUG_TYPE "wasm-prepare-for-live-intervals" @@ -55,20 +43,12 @@ char WebAssemblyPrepareForLiveIntervals::ID = 0; INITIALIZE_PASS(WebAssemblyPrepareForLiveIntervals, DEBUG_TYPE, - "Fix up code for LiveIntervals", false, false) + "Fix up code for LiveIntervals", true, true) FunctionPass *llvm::createWebAssemblyPrepareForLiveIntervals() { return new WebAssemblyPrepareForLiveIntervals(); } -// Test whether the given register has an ARGUMENT def. -static bool hasArgumentDef(unsigned Reg, const MachineRegisterInfo &MRI) { - for (const auto &Def : MRI.def_instructions(Reg)) - if (WebAssembly::isArgument(Def)) - return true; - return false; -} - bool WebAssemblyPrepareForLiveIntervals::runOnMachineFunction( MachineFunction &MF) { LLVM_DEBUG({ @@ -76,52 +56,8 @@ << "********** Function: " << MF.getName() << '\n'; }); - bool Changed = false; - MachineRegisterInfo &MRI = MF.getRegInfo(); - const auto &TII = *MF.getSubtarget().getInstrInfo(); - MachineBasicBlock &Entry = *MF.begin(); - - assert(!mustPreserveAnalysisID(LiveIntervalsID) && - "LiveIntervals shouldn't be active yet!"); - - // We don't preserve SSA form. - MRI.leaveSSA(); - - // BranchFolding and perhaps other passes don't preserve IMPLICIT_DEF - // instructions. LiveIntervals requires that all paths to virtual register - // uses provide a definition. Insert IMPLICIT_DEFs in the entry block to - // conservatively satisfy this. - // - // TODO: This is fairly heavy-handed; find a better approach. - // - for (unsigned I = 0, E = MRI.getNumVirtRegs(); I < E; ++I) { - unsigned Reg = TargetRegisterInfo::index2VirtReg(I); - - // Skip unused registers. - if (MRI.use_nodbg_empty(Reg)) - continue; - - // Skip registers that have an ARGUMENT definition. - if (hasArgumentDef(Reg, MRI)) - continue; - - BuildMI(Entry, Entry.begin(), DebugLoc(), - TII.get(WebAssembly::IMPLICIT_DEF), Reg); - Changed = true; - } - - // Move ARGUMENT_* instructions to the top of the entry block, so that their - // liveness reflects the fact that these really are live-in values. - for (auto MII = Entry.begin(), MIE = Entry.end(); MII != MIE;) { - MachineInstr &MI = *MII++; - if (WebAssembly::isArgument(MI)) { - MI.removeFromParent(); - Entry.insert(Entry.begin(), &MI); - } - } - - // Ok, we're now ready to run the LiveIntervals analysis again. + // We're now ready to run the LiveIntervals analysis again. MF.getProperties().set(MachineFunctionProperties::Property::TracksLiveness); - return Changed; + return false; } Index: test/CodeGen/WebAssembly/reg-stackify.ll =================================================================== --- test/CodeGen/WebAssembly/reg-stackify.ll +++ test/CodeGen/WebAssembly/reg-stackify.ll @@ -336,9 +336,9 @@ ; NOREGS-NEXT: local.get 1{{$}} ; NOREGS-NEXT: local.get 0{{$}} ; NOREGS-NEXT: i32.mul -; NOREGS-NEXT: local.tee 1{{$}} +; NOREGS-NEXT: local.tee [[NUM0:[0-9]+]]{{$}} ; NOREGS-NEXT: call use_a{{$}} -; NOREGS-NEXT: local.get 1{{$}} +; NOREGS-NEXT: local.get [[NUM0]]{{$}} ; NOREGS-NEXT: call use_b{{$}} ; NOREGS-NEXT: return{{$}} declare void @use_a(i32) @@ -363,8 +363,8 @@ ; NOREGS-NEXT: local.get 1{{$}} ; NOREGS-NEXT: local.get 0{{$}} ; NOREGS-NEXT: i32.mul -; NOREGS-NEXT: local.tee 1{{$}} -; NOREGS-NEXT: local.get 1{{$}} +; NOREGS-NEXT: local.tee [[NUM0:[0-9]+]]{{$}} +; NOREGS-NEXT: local.get [[NUM0]]{{$}} ; NOREGS-NEXT: call use_2{{$}} ; NOREGS-NEXT: return{{$}} declare void @use_2(i32, i32) Index: test/CodeGen/WebAssembly/umulo-128-legalisation-lowering.ll =================================================================== --- test/CodeGen/WebAssembly/umulo-128-legalisation-lowering.ll +++ test/CodeGen/WebAssembly/umulo-128-legalisation-lowering.ll @@ -39,14 +39,14 @@ ; WASM32: i32.const $push5=, 40 ; WASM32: i32.add $push6=, $pop52, $pop5 ; WASM32: i64.load $push33=, 0($pop6) -; WASM32: local.tee $push32=, 1, $pop33 +; WASM32: local.tee $push32=, 3, $pop33 ; WASM32: local.get $push53=, 5 ; WASM32: i64.load $push3=, 0($pop53) ; WASM32: local.get $push54=, 5 ; WASM32: i64.load $push2=, 16($pop54) ; WASM32: i64.add $push4=, $pop3, $pop2 ; WASM32: i64.add $push31=, $pop32, $pop4 -; WASM32: local.tee $push30=, 3, $pop31 +; WASM32: local.tee $push30=, 1, $pop31 ; WASM32: i64.store 8($pop55), $pop30 ; WASM32: local.get $push62=, 0 ; WASM32: local.get $push56=, 2 @@ -66,8 +66,8 @@ ; WASM32: i64.const $push26=, 0 ; WASM32: i64.ne $push14=, $pop13, $pop26 ; WASM32: i32.or $push15=, $pop12, $pop14 -; WASM32: local.get $push61=, 3 -; WASM32: local.get $push60=, 1 +; WASM32: local.get $push61=, 1 +; WASM32: local.get $push60=, 3 ; WASM32: i64.lt_u $push16=, $pop61, $pop60 ; WASM32: i32.or $push17=, $pop15, $pop16 ; WASM32: i32.store8 16($pop62), $pop17 Index: test/CodeGen/WebAssembly/umulo-i64.ll =================================================================== --- test/CodeGen/WebAssembly/umulo-i64.ll +++ test/CodeGen/WebAssembly/umulo-i64.ll @@ -22,7 +22,7 @@ ; CHECK-LABEL: wut: ; CHECK: call __multi3, $2, $0, $pop0, $1, $pop7 -; CHECK: i64.load $0=, 8($2) +; CHECK: i64.load ${{.+}}=, 8($2) define i1 @wut(i64, i64) { start: %2 = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %0, i64 %1)