1 //===-- WebAssemblyRegisterInfo.cpp - WebAssembly Register Information ----===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 /// 9 /// \file 10 /// This file contains the WebAssembly implementation of the 11 /// TargetRegisterInfo class. 12 /// 13 //===----------------------------------------------------------------------===// 14 15 #include "WebAssemblyRegisterInfo.h" 16 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" 17 #include "WebAssemblyFrameLowering.h" 18 #include "WebAssemblyInstrInfo.h" 19 #include "WebAssemblyMachineFunctionInfo.h" 20 #include "WebAssemblySubtarget.h" 21 #include "llvm/CodeGen/MachineFrameInfo.h" 22 #include "llvm/CodeGen/MachineInstrBuilder.h" 23 #include "llvm/CodeGen/MachineRegisterInfo.h" 24 #include "llvm/CodeGen/TargetFrameLowering.h" 25 #include "llvm/IR/Function.h" 26 #include "llvm/Support/raw_ostream.h" 27 #include "llvm/Target/TargetOptions.h" 28 using namespace llvm; 29 30 #define DEBUG_TYPE "wasm-reg-info" 31 32 #define GET_REGINFO_TARGET_DESC 33 #include "WebAssemblyGenRegisterInfo.inc" 34 35 WebAssemblyRegisterInfo::WebAssemblyRegisterInfo(const Triple &TT) 36 : WebAssemblyGenRegisterInfo(0), TT(TT) {} 37 38 const MCPhysReg * 39 WebAssemblyRegisterInfo::getCalleeSavedRegs(const MachineFunction *) const { 40 static const MCPhysReg CalleeSavedRegs[] = {0}; 41 return CalleeSavedRegs; 42 } 43 44 BitVector 45 WebAssemblyRegisterInfo::getReservedRegs(const MachineFunction & /*MF*/) const { 46 BitVector Reserved(getNumRegs()); 47 for (auto Reg : {WebAssembly::SP32, WebAssembly::SP64, WebAssembly::FP32, 48 WebAssembly::FP64}) 49 Reserved.set(Reg); 50 return Reserved; 51 } 52 53 bool WebAssemblyRegisterInfo::eliminateFrameIndex( 54 MachineBasicBlock::iterator II, int SPAdj, unsigned FIOperandNum, 55 RegScavenger * /*RS*/) const { 56 assert(SPAdj == 0); 57 MachineInstr &MI = *II; 58 59 MachineBasicBlock &MBB = *MI.getParent(); 60 MachineFunction &MF = *MBB.getParent(); 61 MachineRegisterInfo &MRI = MF.getRegInfo(); 62 int FrameIndex = MI.getOperand(FIOperandNum).getIndex(); 63 const MachineFrameInfo &MFI = MF.getFrameInfo(); 64 int64_t FrameOffset = MFI.getStackSize() + MFI.getObjectOffset(FrameIndex); 65 66 assert(MFI.getObjectSize(FrameIndex) != 0 && 67 "We assume that variable-sized objects have already been lowered, " 68 "and don't use FrameIndex operands."); 69 Register FrameRegister = getFrameRegister(MF); 70 71 // If this is the address operand of a load or store, make it relative to SP 72 // and fold the frame offset directly in. 73 unsigned AddrOperandNum = WebAssembly::getNamedOperandIdx( 74 MI.getOpcode(), WebAssembly::OpName::addr); 75 if (AddrOperandNum == FIOperandNum) { 76 unsigned OffsetOperandNum = WebAssembly::getNamedOperandIdx( 77 MI.getOpcode(), WebAssembly::OpName::off); 78 assert(FrameOffset >= 0 && MI.getOperand(OffsetOperandNum).getImm() >= 0); 79 int64_t Offset = MI.getOperand(OffsetOperandNum).getImm() + FrameOffset; 80 81 if (static_cast<uint64_t>(Offset) <= std::numeric_limits<uint32_t>::max()) { 82 MI.getOperand(OffsetOperandNum).setImm(Offset); 83 MI.getOperand(FIOperandNum) 84 .ChangeToRegister(FrameRegister, /*isDef=*/false); 85 return false; 86 } 87 } 88 89 // If this is an address being added to a constant, fold the frame offset 90 // into the constant. 91 if (MI.getOpcode() == WebAssemblyFrameLowering::getOpcAdd(MF)) { 92 MachineOperand &OtherMO = MI.getOperand(3 - FIOperandNum); 93 if (OtherMO.isReg()) { 94 Register OtherMOReg = OtherMO.getReg(); 95 if (OtherMOReg.isVirtual()) { 96 MachineInstr *Def = MF.getRegInfo().getUniqueVRegDef(OtherMOReg); 97 // TODO: For now we just opportunistically do this in the case where 98 // the CONST_I32/64 happens to have exactly one def and one use. We 99 // should generalize this to optimize in more cases. 100 if (Def && Def->getOpcode() == 101 WebAssemblyFrameLowering::getOpcConst(MF) && 102 MRI.hasOneNonDBGUse(Def->getOperand(0).getReg())) { 103 MachineOperand &ImmMO = Def->getOperand(1); 104 if (ImmMO.isImm()) { 105 ImmMO.setImm(ImmMO.getImm() + uint32_t(FrameOffset)); 106 MI.getOperand(FIOperandNum) 107 .ChangeToRegister(FrameRegister, /*isDef=*/false); 108 return false; 109 } 110 } 111 } 112 } 113 } 114 115 // Otherwise create an i32/64.add SP, offset and make it the operand. 116 const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 117 118 unsigned FIRegOperand = FrameRegister; 119 if (FrameOffset) { 120 // Create i32/64.add SP, offset and make it the operand. 121 const TargetRegisterClass *PtrRC = 122 MRI.getTargetRegisterInfo()->getPointerRegClass(MF); 123 Register OffsetOp = MRI.createVirtualRegister(PtrRC); 124 BuildMI(MBB, *II, II->getDebugLoc(), 125 TII->get(WebAssemblyFrameLowering::getOpcConst(MF)), 126 OffsetOp) 127 .addImm(FrameOffset); 128 FIRegOperand = MRI.createVirtualRegister(PtrRC); 129 BuildMI(MBB, *II, II->getDebugLoc(), 130 TII->get(WebAssemblyFrameLowering::getOpcAdd(MF)), 131 FIRegOperand) 132 .addReg(FrameRegister) 133 .addReg(OffsetOp); 134 } 135 MI.getOperand(FIOperandNum).ChangeToRegister(FIRegOperand, /*isDef=*/false); 136 return false; 137 } 138 139 Register 140 WebAssemblyRegisterInfo::getFrameRegister(const MachineFunction &MF) const { 141 // If the PReg has been replaced by a VReg, return that. 142 const auto &MFI = MF.getInfo<WebAssemblyFunctionInfo>(); 143 if (MFI->isFrameBaseVirtual()) 144 return MFI->getFrameBaseVreg(); 145 static const unsigned Regs[2][2] = { 146 /* !isArch64Bit isArch64Bit */ 147 /* !hasFP */ {WebAssembly::SP32, WebAssembly::SP64}, 148 /* hasFP */ {WebAssembly::FP32, WebAssembly::FP64}}; 149 const WebAssemblyFrameLowering *TFI = getFrameLowering(MF); 150 return Regs[TFI->hasFP(MF)][TT.isArch64Bit()]; 151 } 152 153 const TargetRegisterClass * 154 WebAssemblyRegisterInfo::getPointerRegClass(const MachineFunction &MF, 155 unsigned Kind) const { 156 assert(Kind == 0 && "Only one kind of pointer on WebAssembly"); 157 if (MF.getSubtarget<WebAssemblySubtarget>().hasAddr64()) 158 return &WebAssembly::I64RegClass; 159 return &WebAssembly::I32RegClass; 160 } 161