1 //===-- WebAssemblyRegStackify.cpp - Register Stackification --------------===// 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 /// \brief This file implements a register stacking pass. 12 /// 13 /// This pass reorders instructions to put register uses and defs in an order 14 /// such that they form single-use expression trees. Registers fitting this form 15 /// are then marked as "stackified", meaning references to them are replaced by 16 /// "push" and "pop" from the stack. 17 /// 18 /// This is primarily a code size optimiation, since temporary values on the 19 /// expression don't need to be named. 20 /// 21 //===----------------------------------------------------------------------===// 22 23 #include "WebAssembly.h" 24 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" // for WebAssembly::ARGUMENT_* 25 #include "WebAssemblyMachineFunctionInfo.h" 26 #include "llvm/Analysis/AliasAnalysis.h" 27 #include "llvm/CodeGen/MachineBlockFrequencyInfo.h" 28 #include "llvm/CodeGen/MachineRegisterInfo.h" 29 #include "llvm/CodeGen/Passes.h" 30 #include "llvm/Support/Debug.h" 31 #include "llvm/Support/raw_ostream.h" 32 using namespace llvm; 33 34 #define DEBUG_TYPE "wasm-reg-stackify" 35 36 namespace { 37 class WebAssemblyRegStackify final : public MachineFunctionPass { 38 const char *getPassName() const override { 39 return "WebAssembly Register Stackify"; 40 } 41 42 void getAnalysisUsage(AnalysisUsage &AU) const override { 43 AU.setPreservesCFG(); 44 AU.addRequired<AAResultsWrapperPass>(); 45 AU.addPreserved<MachineBlockFrequencyInfo>(); 46 AU.addPreservedID(MachineDominatorsID); 47 MachineFunctionPass::getAnalysisUsage(AU); 48 } 49 50 bool runOnMachineFunction(MachineFunction &MF) override; 51 52 public: 53 static char ID; // Pass identification, replacement for typeid 54 WebAssemblyRegStackify() : MachineFunctionPass(ID) {} 55 }; 56 } // end anonymous namespace 57 58 char WebAssemblyRegStackify::ID = 0; 59 FunctionPass *llvm::createWebAssemblyRegStackify() { 60 return new WebAssemblyRegStackify(); 61 } 62 63 // Decorate the given instruction with implicit operands that enforce the 64 // expression stack ordering constraints needed for an instruction which is 65 // consumed by an instruction using the expression stack. 66 static void ImposeStackInputOrdering(MachineInstr *MI) { 67 // Write the opaque EXPR_STACK register. 68 if (!MI->definesRegister(WebAssembly::EXPR_STACK)) 69 MI->addOperand(MachineOperand::CreateReg(WebAssembly::EXPR_STACK, 70 /*isDef=*/true, 71 /*isImp=*/true)); 72 } 73 74 // Decorate the given instruction with implicit operands that enforce the 75 // expression stack ordering constraints for an instruction which is on 76 // the expression stack. 77 static void ImposeStackOrdering(MachineInstr *MI, MachineRegisterInfo &MRI) { 78 ImposeStackInputOrdering(MI); 79 80 // Also read the opaque EXPR_STACK register. 81 MI->addOperand(MachineOperand::CreateReg(WebAssembly::EXPR_STACK, 82 /*isDef=*/false, 83 /*isImp=*/true)); 84 85 // Also, mark any inputs to this instruction as being consumed by an 86 // instruction on the expression stack. 87 // TODO: Find a lighter way to describe the appropriate constraints. 88 for (MachineOperand &MO : MI->uses()) { 89 if (!MO.isReg()) 90 continue; 91 unsigned Reg = MO.getReg(); 92 if (!TargetRegisterInfo::isVirtualRegister(Reg)) 93 continue; 94 MachineInstr *Def = MRI.getVRegDef(Reg); 95 if (Def->getOpcode() == TargetOpcode::PHI) 96 continue; 97 ImposeStackInputOrdering(Def); 98 } 99 } 100 101 // Test whether it's safe to move Def to just before Insert. Note that this 102 // doesn't account for physical register dependencies, because WebAssembly 103 // doesn't have any (other than special ones like EXPR_STACK). 104 // TODO: Compute memory dependencies in a way that doesn't require always 105 // walking the block. 106 // TODO: Compute memory dependencies in a way that uses AliasAnalysis to be 107 // more precise. 108 static bool IsSafeToMove(const MachineInstr *Def, const MachineInstr *Insert, 109 AliasAnalysis &AA) { 110 assert(Def->getParent() == Insert->getParent()); 111 bool SawStore = false, SawSideEffects = false; 112 MachineBasicBlock::const_iterator D(Def), I(Insert); 113 for (--I; I != D; --I) 114 SawSideEffects |= I->isSafeToMove(&AA, SawStore); 115 116 return !(SawStore && Def->mayLoad() && !Def->isInvariantLoad(&AA)) && 117 !(SawSideEffects && !Def->isSafeToMove(&AA, SawStore)); 118 } 119 120 bool WebAssemblyRegStackify::runOnMachineFunction(MachineFunction &MF) { 121 DEBUG(dbgs() << "********** Register Stackifying **********\n" 122 "********** Function: " 123 << MF.getName() << '\n'); 124 125 bool Changed = false; 126 MachineRegisterInfo &MRI = MF.getRegInfo(); 127 WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 128 AliasAnalysis &AA = getAnalysis<AAResultsWrapperPass>().getAAResults(); 129 130 // Walk the instructions from the bottom up. Currently we don't look past 131 // block boundaries, and the blocks aren't ordered so the block visitation 132 // order isn't significant, but we may want to change this in the future. 133 for (MachineBasicBlock &MBB : MF) { 134 for (MachineInstr &MI : reverse(MBB)) { 135 MachineInstr *Insert = &MI; 136 137 // Don't nest anything inside a phi. 138 if (Insert->getOpcode() == TargetOpcode::PHI) 139 break; 140 141 // Don't nest anything inside an inline asm, because we don't have 142 // constraints for $push inputs. 143 if (Insert->getOpcode() == TargetOpcode::INLINEASM) 144 break; 145 146 // Iterate through the inputs in reverse order, since we'll be pulling 147 // operands off the stack in LIFO order. 148 bool AnyStackified = false; 149 for (MachineOperand &Op : reverse(Insert->uses())) { 150 // We're only interested in explicit virtual register operands. 151 if (!Op.isReg() || Op.isImplicit() || !Op.isUse()) 152 continue; 153 154 unsigned Reg = Op.getReg(); 155 if (TargetRegisterInfo::isPhysicalRegister(Reg)) { 156 // An instruction with a physical register. Conservatively mark it as 157 // an expression stack input so that it isn't reordered with anything 158 // in an expression stack which might use it (physical registers 159 // aren't in SSA form so it's not trivial to determine this). 160 // TODO: Be less conservative. 161 ImposeStackInputOrdering(Insert); 162 continue; 163 } 164 165 // Only consider registers with a single definition. 166 // TODO: Eventually we may relax this, to stackify phi transfers. 167 MachineInstr *Def = MRI.getVRegDef(Reg); 168 if (!Def) 169 continue; 170 171 // There's no use in nesting implicit defs inside anything. 172 if (Def->getOpcode() == TargetOpcode::IMPLICIT_DEF) 173 continue; 174 175 // Don't nest an INLINE_ASM def into anything, because we don't have 176 // constraints for $pop outputs. 177 if (Def->getOpcode() == TargetOpcode::INLINEASM) 178 continue; 179 180 // Don't nest PHIs inside of anything. 181 if (Def->getOpcode() == TargetOpcode::PHI) 182 continue; 183 184 // Argument instructions represent live-in registers and not real 185 // instructions. 186 if (Def->getOpcode() == WebAssembly::ARGUMENT_I32 || 187 Def->getOpcode() == WebAssembly::ARGUMENT_I64 || 188 Def->getOpcode() == WebAssembly::ARGUMENT_F32 || 189 Def->getOpcode() == WebAssembly::ARGUMENT_F64) 190 continue; 191 192 // Single-use expression trees require defs that have one use. 193 // TODO: Eventually we'll relax this, to take advantage of set_local 194 // returning its result. 195 if (!MRI.hasOneUse(Reg)) 196 continue; 197 198 // For now, be conservative and don't look across block boundaries. 199 // TODO: Be more aggressive. 200 if (Def->getParent() != &MBB) 201 continue; 202 203 // Don't move instructions that have side effects or memory dependencies 204 // or other complications. 205 if (!IsSafeToMove(Def, Insert, AA)) 206 continue; 207 208 Changed = true; 209 AnyStackified = true; 210 // Move the def down and nest it in the current instruction. 211 MBB.insert(MachineBasicBlock::instr_iterator(Insert), 212 Def->removeFromParent()); 213 MFI.stackifyVReg(Reg); 214 ImposeStackOrdering(Def, MRI); 215 Insert = Def; 216 } 217 if (AnyStackified) 218 ImposeStackOrdering(&MI, MRI); 219 } 220 } 221 222 // If we used EXPR_STACK anywhere, add it to the live-in sets everywhere 223 // so that it never looks like a use-before-def. 224 if (Changed) { 225 MF.getRegInfo().addLiveIn(WebAssembly::EXPR_STACK); 226 for (MachineBasicBlock &MBB : MF) 227 MBB.addLiveIn(WebAssembly::EXPR_STACK); 228 } 229 230 #ifndef NDEBUG 231 // Verify that pushes and pops are performed in FIFO order. 232 SmallVector<unsigned, 0> Stack; 233 for (MachineBasicBlock &MBB : MF) { 234 for (MachineInstr &MI : MBB) { 235 for (MachineOperand &MO : reverse(MI.explicit_operands())) { 236 if (!MO.isReg()) 237 continue; 238 unsigned VReg = MO.getReg(); 239 240 // Don't stackify physregs like SP or FP. 241 if (!TargetRegisterInfo::isVirtualRegister(VReg)) 242 continue; 243 244 if (MFI.isVRegStackified(VReg)) { 245 if (MO.isDef()) 246 Stack.push_back(VReg); 247 else 248 assert(Stack.pop_back_val() == VReg); 249 } 250 } 251 } 252 // TODO: Generalize this code to support keeping values on the stack across 253 // basic block boundaries. 254 assert(Stack.empty()); 255 } 256 #endif 257 258 return Changed; 259 } 260