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 optimization, 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 "WebAssemblySubtarget.h" 27 #include "llvm/Analysis/AliasAnalysis.h" 28 #include "llvm/CodeGen/LiveIntervalAnalysis.h" 29 #include "llvm/CodeGen/MachineBlockFrequencyInfo.h" 30 #include "llvm/CodeGen/MachineRegisterInfo.h" 31 #include "llvm/CodeGen/Passes.h" 32 #include "llvm/Support/Debug.h" 33 #include "llvm/Support/raw_ostream.h" 34 using namespace llvm; 35 36 #define DEBUG_TYPE "wasm-reg-stackify" 37 38 namespace { 39 class WebAssemblyRegStackify final : public MachineFunctionPass { 40 const char *getPassName() const override { 41 return "WebAssembly Register Stackify"; 42 } 43 44 void getAnalysisUsage(AnalysisUsage &AU) const override { 45 AU.setPreservesCFG(); 46 AU.addRequired<AAResultsWrapperPass>(); 47 AU.addRequired<LiveIntervals>(); 48 AU.addPreserved<MachineBlockFrequencyInfo>(); 49 AU.addPreserved<SlotIndexes>(); 50 AU.addPreserved<LiveIntervals>(); 51 AU.addPreservedID(MachineDominatorsID); 52 AU.addPreservedID(LiveVariablesID); 53 MachineFunctionPass::getAnalysisUsage(AU); 54 } 55 56 bool runOnMachineFunction(MachineFunction &MF) override; 57 58 public: 59 static char ID; // Pass identification, replacement for typeid 60 WebAssemblyRegStackify() : MachineFunctionPass(ID) {} 61 }; 62 } // end anonymous namespace 63 64 char WebAssemblyRegStackify::ID = 0; 65 FunctionPass *llvm::createWebAssemblyRegStackify() { 66 return new WebAssemblyRegStackify(); 67 } 68 69 // Decorate the given instruction with implicit operands that enforce the 70 // expression stack ordering constraints for an instruction which is on 71 // the expression stack. 72 static void ImposeStackOrdering(MachineInstr *MI) { 73 // Write the opaque EXPR_STACK register. 74 if (!MI->definesRegister(WebAssembly::EXPR_STACK)) 75 MI->addOperand(MachineOperand::CreateReg(WebAssembly::EXPR_STACK, 76 /*isDef=*/true, 77 /*isImp=*/true)); 78 79 // Also read the opaque EXPR_STACK register. 80 if (!MI->readsRegister(WebAssembly::EXPR_STACK)) 81 MI->addOperand(MachineOperand::CreateReg(WebAssembly::EXPR_STACK, 82 /*isDef=*/false, 83 /*isImp=*/true)); 84 } 85 86 // Test whether it's safe to move Def to just before Insert. 87 // TODO: Compute memory dependencies in a way that doesn't require always 88 // walking the block. 89 // TODO: Compute memory dependencies in a way that uses AliasAnalysis to be 90 // more precise. 91 static bool IsSafeToMove(const MachineInstr *Def, const MachineInstr *Insert, 92 AliasAnalysis &AA, LiveIntervals &LIS, 93 MachineRegisterInfo &MRI) { 94 assert(Def->getParent() == Insert->getParent()); 95 bool SawStore = false, SawSideEffects = false; 96 MachineBasicBlock::const_iterator D(Def), I(Insert); 97 98 // Check for register dependencies. 99 for (const MachineOperand &MO : Def->operands()) { 100 if (!MO.isReg() || MO.isUndef()) 101 continue; 102 unsigned Reg = MO.getReg(); 103 104 // If the register is dead here and at Insert, ignore it. 105 if (MO.isDead() && Insert->definesRegister(Reg) && 106 !Insert->readsRegister(Reg)) 107 continue; 108 109 if (TargetRegisterInfo::isPhysicalRegister(Reg)) { 110 // If the physical register is never modified, ignore it. 111 if (!MRI.isPhysRegModified(Reg)) 112 continue; 113 // Otherwise, it's a physical register with unknown liveness. 114 return false; 115 } 116 117 // Ask LiveIntervals whether moving this virtual register use or def to 118 // Insert will change value numbers are seen. 119 const LiveInterval &LI = LIS.getInterval(Reg); 120 VNInfo *DefVNI = 121 MO.isDef() ? LI.getVNInfoAt(LIS.getInstructionIndex(Def).getRegSlot()) 122 : LI.getVNInfoBefore(LIS.getInstructionIndex(Def)); 123 assert(DefVNI && "Instruction input missing value number"); 124 VNInfo *InsVNI = LI.getVNInfoBefore(LIS.getInstructionIndex(Insert)); 125 if (InsVNI && DefVNI != InsVNI) 126 return false; 127 } 128 129 // Check for memory dependencies and side effects. 130 for (--I; I != D; --I) 131 SawSideEffects |= !I->isSafeToMove(&AA, SawStore); 132 return !(SawStore && Def->mayLoad() && !Def->isInvariantLoad(&AA)) && 133 !(SawSideEffects && !Def->isSafeToMove(&AA, SawStore)); 134 } 135 136 bool WebAssemblyRegStackify::runOnMachineFunction(MachineFunction &MF) { 137 DEBUG(dbgs() << "********** Register Stackifying **********\n" 138 "********** Function: " 139 << MF.getName() << '\n'); 140 141 bool Changed = false; 142 MachineRegisterInfo &MRI = MF.getRegInfo(); 143 WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 144 const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 145 const auto *TRI = MF.getSubtarget<WebAssemblySubtarget>().getRegisterInfo(); 146 AliasAnalysis &AA = getAnalysis<AAResultsWrapperPass>().getAAResults(); 147 LiveIntervals &LIS = getAnalysis<LiveIntervals>(); 148 149 // Walk the instructions from the bottom up. Currently we don't look past 150 // block boundaries, and the blocks aren't ordered so the block visitation 151 // order isn't significant, but we may want to change this in the future. 152 for (MachineBasicBlock &MBB : MF) { 153 // Don't use a range-based for loop, because we modify the list as we're 154 // iterating over it and the end iterator may change. 155 for (auto MII = MBB.rbegin(); MII != MBB.rend(); ++MII) { 156 MachineInstr *Insert = &*MII; 157 // Don't nest anything inside a phi. 158 if (Insert->getOpcode() == TargetOpcode::PHI) 159 break; 160 161 // Don't nest anything inside an inline asm, because we don't have 162 // constraints for $push inputs. 163 if (Insert->getOpcode() == TargetOpcode::INLINEASM) 164 break; 165 166 // Iterate through the inputs in reverse order, since we'll be pulling 167 // operands off the stack in LIFO order. 168 bool AnyStackified = false; 169 for (MachineOperand &Op : reverse(Insert->uses())) { 170 // We're only interested in explicit virtual register operands. 171 if (!Op.isReg() || Op.isImplicit() || !Op.isUse()) 172 continue; 173 174 unsigned Reg = Op.getReg(); 175 176 // Only consider registers with a single definition. 177 // TODO: Eventually we may relax this, to stackify phi transfers. 178 MachineInstr *Def = MRI.getUniqueVRegDef(Reg); 179 if (!Def) 180 continue; 181 182 // Don't nest an INLINE_ASM def into anything, because we don't have 183 // constraints for $pop outputs. 184 if (Def->getOpcode() == TargetOpcode::INLINEASM) 185 continue; 186 187 // Don't nest PHIs inside of anything. 188 if (Def->getOpcode() == TargetOpcode::PHI) 189 continue; 190 191 // Argument instructions represent live-in registers and not real 192 // instructions. 193 if (Def->getOpcode() == WebAssembly::ARGUMENT_I32 || 194 Def->getOpcode() == WebAssembly::ARGUMENT_I64 || 195 Def->getOpcode() == WebAssembly::ARGUMENT_F32 || 196 Def->getOpcode() == WebAssembly::ARGUMENT_F64) 197 continue; 198 199 if (MRI.hasOneUse(Reg) && Def->getParent() == &MBB && 200 IsSafeToMove(Def, Insert, AA, LIS, MRI)) { 201 // A single-use def in the same block with no intervening memory or 202 // register dependencies; move the def down and nest it with the 203 // current instruction. 204 // TODO: Stackify multiple-use values, taking advantage of set_local 205 // returning its result. 206 Changed = true; 207 AnyStackified = true; 208 MBB.splice(Insert, &MBB, Def); 209 LIS.handleMove(Def); 210 MFI.stackifyVReg(Reg); 211 ImposeStackOrdering(Def); 212 Insert = Def; 213 } else if (Def->isAsCheapAsAMove() && 214 TII->isTriviallyReMaterializable(Def, &AA)) { 215 // A trivially cloneable instruction; clone it and nest the new copy 216 // with the current instruction. 217 Changed = true; 218 AnyStackified = true; 219 unsigned OldReg = Def->getOperand(0).getReg(); 220 unsigned NewReg = MRI.createVirtualRegister(MRI.getRegClass(OldReg)); 221 TII->reMaterialize(MBB, Insert, NewReg, 0, Def, *TRI); 222 Op.setReg(NewReg); 223 MachineInstr *Clone = 224 &*std::prev(MachineBasicBlock::instr_iterator(Insert)); 225 LIS.InsertMachineInstrInMaps(Clone); 226 LIS.createAndComputeVirtRegInterval(NewReg); 227 MFI.stackifyVReg(NewReg); 228 ImposeStackOrdering(Clone); 229 Insert = Clone; 230 231 // If that was the last use of the original, delete the original. 232 // Otherwise shrink the LiveInterval. 233 if (MRI.use_empty(OldReg)) { 234 SlotIndex Idx = LIS.getInstructionIndex(Def).getRegSlot(); 235 LIS.removePhysRegDefAt(WebAssembly::ARGUMENTS, Idx); 236 LIS.removeVRegDefAt(LIS.getInterval(OldReg), Idx); 237 LIS.removeInterval(OldReg); 238 LIS.RemoveMachineInstrFromMaps(Def); 239 Def->eraseFromParent(); 240 } else { 241 LIS.shrinkToUses(&LIS.getInterval(OldReg)); 242 } 243 } 244 } 245 if (AnyStackified) 246 ImposeStackOrdering(&*MII); 247 } 248 } 249 250 // If we used EXPR_STACK anywhere, add it to the live-in sets everywhere 251 // so that it never looks like a use-before-def. 252 if (Changed) { 253 MF.getRegInfo().addLiveIn(WebAssembly::EXPR_STACK); 254 for (MachineBasicBlock &MBB : MF) 255 MBB.addLiveIn(WebAssembly::EXPR_STACK); 256 } 257 258 #ifndef NDEBUG 259 // Verify that pushes and pops are performed in LIFO order. 260 SmallVector<unsigned, 0> Stack; 261 for (MachineBasicBlock &MBB : MF) { 262 for (MachineInstr &MI : MBB) { 263 for (MachineOperand &MO : reverse(MI.explicit_operands())) { 264 if (!MO.isReg()) 265 continue; 266 unsigned VReg = MO.getReg(); 267 268 // Don't stackify physregs like SP or FP. 269 if (!TargetRegisterInfo::isVirtualRegister(VReg)) 270 continue; 271 272 if (MFI.isVRegStackified(VReg)) { 273 if (MO.isDef()) 274 Stack.push_back(VReg); 275 else 276 assert(Stack.pop_back_val() == VReg); 277 } 278 } 279 } 280 // TODO: Generalize this code to support keeping values on the stack across 281 // basic block boundaries. 282 assert(Stack.empty()); 283 } 284 #endif 285 286 return Changed; 287 } 288