//===-- WebAssemblyRegisterInfo.cpp - WebAssembly Register Information ----===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// /// /// \file /// \brief This file contains the WebAssembly implementation of the /// TargetRegisterInfo class. /// //===----------------------------------------------------------------------===// #include "WebAssemblyRegisterInfo.h" #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" #include "WebAssemblyFrameLowering.h" #include "WebAssemblyInstrInfo.h" #include "WebAssemblyMachineFunctionInfo.h" #include "WebAssemblySubtarget.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/IR/Function.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetFrameLowering.h" #include "llvm/Target/TargetOptions.h" using namespace llvm; #define DEBUG_TYPE "wasm-reg-info" #define GET_REGINFO_TARGET_DESC #include "WebAssemblyGenRegisterInfo.inc" WebAssemblyRegisterInfo::WebAssemblyRegisterInfo(const Triple &TT) : WebAssemblyGenRegisterInfo(0), TT(TT) {} const MCPhysReg * WebAssemblyRegisterInfo::getCalleeSavedRegs(const MachineFunction *) const { static const MCPhysReg CalleeSavedRegs[] = {0}; return CalleeSavedRegs; } BitVector WebAssemblyRegisterInfo::getReservedRegs(const MachineFunction & /*MF*/) const { BitVector Reserved(getNumRegs()); for (auto Reg : {WebAssembly::SP32, WebAssembly::SP64, WebAssembly::FP32, WebAssembly::FP64}) Reserved.set(Reg); return Reserved; } static bool isStackifiedVReg(const WebAssemblyFunctionInfo *WFI, const MachineOperand& Op) { if (Op.isReg()) { unsigned Reg = Op.getReg(); return TargetRegisterInfo::isVirtualRegister(Reg) && WFI->isVRegStackified(Reg); } return false; } static bool canStackifyOperand(const MachineInstr& Inst) { unsigned Op = Inst.getOpcode(); return Op != TargetOpcode::PHI && Op != TargetOpcode::INLINEASM && Op != TargetOpcode::DBG_VALUE; } // Determine if the FI sequence can be stackified, and if so, where the code can // be inserted. If stackification is possible, returns true and ajusts II to // point to the insertion point. bool findInsertPt(const WebAssemblyFunctionInfo *WFI, MachineBasicBlock &MBB, unsigned OperandNum, MachineBasicBlock::iterator &II) { if (!canStackifyOperand(*II)) return false; MachineBasicBlock::iterator InsertPt(II); int StackCount = 0; // Operands are popped in reverse order, so any operands after FIOperand // impose a constraint for (unsigned i = OperandNum; i < II->getNumOperands(); i++) { if (isStackifiedVReg(WFI, II->getOperand(i))) ++StackCount; } // Walk backwards, tracking stack depth. When it reaches 0 we have reached the // top of the subtree. while (StackCount) { if (InsertPt == MBB.begin()) return false; --InsertPt; for (const auto &def : InsertPt->defs()) if (isStackifiedVReg(WFI, def)) --StackCount; for (const auto &use : InsertPt->explicit_uses()) if (isStackifiedVReg(WFI, use)) ++StackCount; } II = InsertPt; return true; } void WebAssemblyRegisterInfo::eliminateFrameIndex( MachineBasicBlock::iterator II, int SPAdj, unsigned FIOperandNum, RegScavenger * /*RS*/) const { assert(SPAdj == 0); MachineInstr &MI = *II; MachineBasicBlock &MBB = *MI.getParent(); MachineFunction &MF = *MBB.getParent(); int FrameIndex = MI.getOperand(FIOperandNum).getIndex(); const MachineFrameInfo &MFI = *MF.getFrameInfo(); int64_t FrameOffset = MFI.getStackSize() + MFI.getObjectOffset(FrameIndex); if (MI.mayLoadOrStore() && FIOperandNum == WebAssembly::MemOpAddressOperandNo) { // If this is the address operand of a load or store, make it relative to SP // and fold the frame offset directly in. assert(FrameOffset >= 0 && MI.getOperand(1).getImm() >= 0); int64_t Offset = MI.getOperand(1).getImm() + FrameOffset; if (static_cast(Offset) > std::numeric_limits::max()) { // If this happens the program is invalid, but better to error here than // generate broken code. report_fatal_error("Memory offset field overflow"); } MI.getOperand(FIOperandNum - 1).setImm(Offset); MI.getOperand(FIOperandNum) .ChangeToRegister(WebAssembly::SP32, /*IsDef=*/false); } else { // Otherwise calculate the address auto &MRI = MF.getRegInfo(); const auto *TII = MF.getSubtarget().getInstrInfo(); unsigned FIRegOperand = WebAssembly::SP32; if (FrameOffset) { // Create i32.add SP, offset and make it the operand. We want to stackify // this sequence, but we need to preserve the LIFO expr stack ordering // (i.e. we can't insert our code in between MI and any operands it // pops before FIOperand). auto *WFI = MF.getInfo(); bool CanStackifyFI = findInsertPt(WFI, MBB, FIOperandNum, II); unsigned OffsetOp = MRI.createVirtualRegister(&WebAssembly::I32RegClass); BuildMI(MBB, *II, II->getDebugLoc(), TII->get(WebAssembly::CONST_I32), OffsetOp) .addImm(FrameOffset); if (CanStackifyFI) { WFI->stackifyVReg(OffsetOp); FIRegOperand = MRI.createVirtualRegister(&WebAssembly::I32RegClass); WFI->stackifyVReg(FIRegOperand); } else { FIRegOperand = OffsetOp; } BuildMI(MBB, *II, II->getDebugLoc(), TII->get(WebAssembly::ADD_I32), FIRegOperand) .addReg(WebAssembly::SP32) .addReg(OffsetOp); } MI.getOperand(FIOperandNum).ChangeToRegister(FIRegOperand, /*IsDef=*/false); } } unsigned WebAssemblyRegisterInfo::getFrameRegister(const MachineFunction &MF) const { static const unsigned Regs[2][2] = { /* !isArch64Bit isArch64Bit */ /* !hasFP */ {WebAssembly::SP32, WebAssembly::SP64}, /* hasFP */ {WebAssembly::FP32, WebAssembly::FP64}}; const WebAssemblyFrameLowering *TFI = getFrameLowering(MF); return Regs[TFI->hasFP(MF)][TT.isArch64Bit()]; } const TargetRegisterClass * WebAssemblyRegisterInfo::getPointerRegClass(const MachineFunction &MF, unsigned Kind) const { assert(Kind == 0 && "Only one kind of pointer on WebAssembly"); if (MF.getSubtarget().hasAddr64()) return &WebAssembly::I64RegClass; return &WebAssembly::I32RegClass; }