1 //===-- WebAssemblyRegisterInfo.cpp - WebAssembly Register Information ----===// 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 contains the WebAssembly implementation of the 12 /// TargetRegisterInfo class. 13 /// 14 //===----------------------------------------------------------------------===// 15 16 #include "WebAssemblyRegisterInfo.h" 17 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" 18 #include "WebAssemblyFrameLowering.h" 19 #include "WebAssemblyInstrInfo.h" 20 #include "WebAssemblyMachineFunctionInfo.h" 21 #include "WebAssemblySubtarget.h" 22 #include "llvm/CodeGen/MachineFrameInfo.h" 23 #include "llvm/CodeGen/MachineInstrBuilder.h" 24 #include "llvm/CodeGen/MachineRegisterInfo.h" 25 #include "llvm/IR/Function.h" 26 #include "llvm/Support/raw_ostream.h" 27 #include "llvm/Target/TargetFrameLowering.h" 28 #include "llvm/Target/TargetOptions.h" 29 using namespace llvm; 30 31 #define DEBUG_TYPE "wasm-reg-info" 32 33 #define GET_REGINFO_TARGET_DESC 34 #include "WebAssemblyGenRegisterInfo.inc" 35 36 WebAssemblyRegisterInfo::WebAssemblyRegisterInfo(const Triple &TT) 37 : WebAssemblyGenRegisterInfo(0), TT(TT) {} 38 39 const MCPhysReg * 40 WebAssemblyRegisterInfo::getCalleeSavedRegs(const MachineFunction *) const { 41 static const MCPhysReg CalleeSavedRegs[] = {0}; 42 return CalleeSavedRegs; 43 } 44 45 BitVector 46 WebAssemblyRegisterInfo::getReservedRegs(const MachineFunction & /*MF*/) const { 47 BitVector Reserved(getNumRegs()); 48 for (auto Reg : {WebAssembly::SP32, WebAssembly::SP64, WebAssembly::FP32, 49 WebAssembly::FP64}) 50 Reserved.set(Reg); 51 return Reserved; 52 } 53 54 static bool isStackifiedVReg(const WebAssemblyFunctionInfo *WFI, 55 const MachineOperand& Op) { 56 if (Op.isReg()) { 57 unsigned Reg = Op.getReg(); 58 return TargetRegisterInfo::isVirtualRegister(Reg) && 59 WFI->isVRegStackified(Reg); 60 } 61 return false; 62 } 63 64 static bool canStackifyOperand(const MachineInstr& Inst) { 65 unsigned Op = Inst.getOpcode(); 66 return Op != TargetOpcode::PHI && 67 Op != TargetOpcode::INLINEASM && 68 Op != TargetOpcode::DBG_VALUE; 69 } 70 71 // Determine if the FI sequence can be stackified, and if so, where the code can 72 // be inserted. If stackification is possible, returns true and ajusts II to 73 // point to the insertion point. 74 bool findInsertPt(const WebAssemblyFunctionInfo *WFI, MachineBasicBlock &MBB, 75 unsigned OperandNum, MachineBasicBlock::iterator &II) { 76 if (!canStackifyOperand(*II)) return false; 77 78 MachineBasicBlock::iterator InsertPt(II); 79 int StackCount = 0; 80 // Operands are popped in reverse order, so any operands after FIOperand 81 // impose a constraint 82 for (unsigned i = OperandNum; i < II->getNumOperands(); i++) { 83 if (isStackifiedVReg(WFI, II->getOperand(i))) ++StackCount; 84 } 85 // Walk backwards, tracking stack depth. When it reaches 0 we have reached the 86 // top of the subtree. 87 while (StackCount) { 88 if (InsertPt == MBB.begin()) return false; 89 --InsertPt; 90 for (const auto &def : InsertPt->defs()) 91 if (isStackifiedVReg(WFI, def)) --StackCount; 92 for (const auto &use : InsertPt->explicit_uses()) 93 if (isStackifiedVReg(WFI, use)) ++StackCount; 94 } 95 II = InsertPt; 96 return true; 97 } 98 99 void WebAssemblyRegisterInfo::eliminateFrameIndex( 100 MachineBasicBlock::iterator II, int SPAdj, unsigned FIOperandNum, 101 RegScavenger * /*RS*/) const { 102 assert(SPAdj == 0); 103 MachineInstr &MI = *II; 104 105 MachineBasicBlock &MBB = *MI.getParent(); 106 MachineFunction &MF = *MBB.getParent(); 107 int FrameIndex = MI.getOperand(FIOperandNum).getIndex(); 108 const MachineFrameInfo &MFI = *MF.getFrameInfo(); 109 int64_t FrameOffset = MFI.getStackSize() + MFI.getObjectOffset(FrameIndex); 110 111 if (MI.mayLoadOrStore() && FIOperandNum == WebAssembly::MemOpAddressOperandNo) { 112 // If this is the address operand of a load or store, make it relative to SP 113 // and fold the frame offset directly in. 114 assert(FrameOffset >= 0 && MI.getOperand(1).getImm() >= 0); 115 int64_t Offset = MI.getOperand(1).getImm() + FrameOffset; 116 117 if (static_cast<uint64_t>(Offset) > std::numeric_limits<uint32_t>::max()) { 118 // If this happens the program is invalid, but better to error here than 119 // generate broken code. 120 report_fatal_error("Memory offset field overflow"); 121 } 122 MI.getOperand(FIOperandNum - 1).setImm(Offset); 123 MI.getOperand(FIOperandNum) 124 .ChangeToRegister(WebAssembly::SP32, /*IsDef=*/false); 125 } else { 126 // Otherwise calculate the address 127 auto &MRI = MF.getRegInfo(); 128 const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 129 130 unsigned FIRegOperand = WebAssembly::SP32; 131 if (FrameOffset) { 132 // Create i32.add SP, offset and make it the operand. We want to stackify 133 // this sequence, but we need to preserve the LIFO expr stack ordering 134 // (i.e. we can't insert our code in between MI and any operands it 135 // pops before FIOperand). 136 auto *WFI = MF.getInfo<WebAssemblyFunctionInfo>(); 137 bool CanStackifyFI = findInsertPt(WFI, MBB, FIOperandNum, II); 138 139 unsigned OffsetOp = MRI.createVirtualRegister(&WebAssembly::I32RegClass); 140 BuildMI(MBB, *II, II->getDebugLoc(), TII->get(WebAssembly::CONST_I32), 141 OffsetOp) 142 .addImm(FrameOffset); 143 if (CanStackifyFI) { 144 WFI->stackifyVReg(OffsetOp); 145 FIRegOperand = MRI.createVirtualRegister(&WebAssembly::I32RegClass); 146 WFI->stackifyVReg(FIRegOperand); 147 } else { 148 FIRegOperand = OffsetOp; 149 } 150 BuildMI(MBB, *II, II->getDebugLoc(), TII->get(WebAssembly::ADD_I32), 151 FIRegOperand) 152 .addReg(WebAssembly::SP32) 153 .addReg(OffsetOp); 154 } 155 MI.getOperand(FIOperandNum).ChangeToRegister(FIRegOperand, /*IsDef=*/false); 156 } 157 } 158 159 unsigned 160 WebAssemblyRegisterInfo::getFrameRegister(const MachineFunction &MF) const { 161 static const unsigned Regs[2][2] = { 162 /* !isArch64Bit isArch64Bit */ 163 /* !hasFP */ {WebAssembly::SP32, WebAssembly::SP64}, 164 /* hasFP */ {WebAssembly::FP32, WebAssembly::FP64}}; 165 const WebAssemblyFrameLowering *TFI = getFrameLowering(MF); 166 return Regs[TFI->hasFP(MF)][TT.isArch64Bit()]; 167 } 168 169 const TargetRegisterClass * 170 WebAssemblyRegisterInfo::getPointerRegClass(const MachineFunction &MF, 171 unsigned Kind) const { 172 assert(Kind == 0 && "Only one kind of pointer on WebAssembly"); 173 if (MF.getSubtarget<WebAssemblySubtarget>().hasAddr64()) 174 return &WebAssembly::I64RegClass; 175 return &WebAssembly::I32RegClass; 176 } 177