1285163Sdim//===-- WebAssemblyRegisterInfo.cpp - WebAssembly Register Information ----===// 2285163Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6285163Sdim// 7285163Sdim//===----------------------------------------------------------------------===// 8285163Sdim/// 9285163Sdim/// \file 10341825Sdim/// This file contains the WebAssembly implementation of the 11285163Sdim/// TargetRegisterInfo class. 12285163Sdim/// 13285163Sdim//===----------------------------------------------------------------------===// 14285163Sdim 15285163Sdim#include "WebAssemblyRegisterInfo.h" 16285163Sdim#include "MCTargetDesc/WebAssemblyMCTargetDesc.h" 17285163Sdim#include "WebAssemblyFrameLowering.h" 18285163Sdim#include "WebAssemblyInstrInfo.h" 19285163Sdim#include "WebAssemblyMachineFunctionInfo.h" 20285163Sdim#include "WebAssemblySubtarget.h" 21285163Sdim#include "llvm/CodeGen/MachineFrameInfo.h" 22285163Sdim#include "llvm/CodeGen/MachineInstrBuilder.h" 23285163Sdim#include "llvm/CodeGen/MachineRegisterInfo.h" 24344779Sdim#include "llvm/CodeGen/TargetFrameLowering.h" 25285163Sdim#include "llvm/IR/Function.h" 26285163Sdim#include "llvm/Support/raw_ostream.h" 27285163Sdim#include "llvm/Target/TargetOptions.h" 28285163Sdimusing namespace llvm; 29285163Sdim 30285163Sdim#define DEBUG_TYPE "wasm-reg-info" 31285163Sdim 32286684Sdim#define GET_REGINFO_TARGET_DESC 33286684Sdim#include "WebAssemblyGenRegisterInfo.inc" 34286684Sdim 35286684SdimWebAssemblyRegisterInfo::WebAssemblyRegisterInfo(const Triple &TT) 36286684Sdim : WebAssemblyGenRegisterInfo(0), TT(TT) {} 37286684Sdim 38286684Sdimconst MCPhysReg * 39286684SdimWebAssemblyRegisterInfo::getCalleeSavedRegs(const MachineFunction *) const { 40286684Sdim static const MCPhysReg CalleeSavedRegs[] = {0}; 41286684Sdim return CalleeSavedRegs; 42286684Sdim} 43286684Sdim 44286684SdimBitVector 45296417SdimWebAssemblyRegisterInfo::getReservedRegs(const MachineFunction & /*MF*/) const { 46286684Sdim BitVector Reserved(getNumRegs()); 47286684Sdim for (auto Reg : {WebAssembly::SP32, WebAssembly::SP64, WebAssembly::FP32, 48286684Sdim WebAssembly::FP64}) 49286684Sdim Reserved.set(Reg); 50286684Sdim return Reserved; 51286684Sdim} 52286684Sdim 53286684Sdimvoid WebAssemblyRegisterInfo::eliminateFrameIndex( 54309124Sdim MachineBasicBlock::iterator II, int SPAdj, unsigned FIOperandNum, 55309124Sdim RegScavenger * /*RS*/) const { 56296417Sdim assert(SPAdj == 0); 57296417Sdim MachineInstr &MI = *II; 58296417Sdim 59296417Sdim MachineBasicBlock &MBB = *MI.getParent(); 60296417Sdim MachineFunction &MF = *MBB.getParent(); 61309124Sdim MachineRegisterInfo &MRI = MF.getRegInfo(); 62296417Sdim int FrameIndex = MI.getOperand(FIOperandNum).getIndex(); 63314564Sdim const MachineFrameInfo &MFI = MF.getFrameInfo(); 64296417Sdim int64_t FrameOffset = MFI.getStackSize() + MFI.getObjectOffset(FrameIndex); 65296417Sdim 66314564Sdim assert(MFI.getObjectSize(FrameIndex) != 0 && 67314564Sdim "We assume that variable-sized objects have already been lowered, " 68314564Sdim "and don't use FrameIndex operands."); 69353358Sdim Register FrameRegister = getFrameRegister(MF); 70314564Sdim 71309124Sdim // If this is the address operand of a load or store, make it relative to SP 72309124Sdim // and fold the frame offset directly in. 73353358Sdim unsigned AddrOperandNum = WebAssembly::getNamedOperandIdx( 74353358Sdim MI.getOpcode(), WebAssembly::OpName::addr); 75353358Sdim if (AddrOperandNum == FIOperandNum) { 76353358Sdim unsigned OffsetOperandNum = WebAssembly::getNamedOperandIdx( 77353358Sdim MI.getOpcode(), WebAssembly::OpName::off); 78353358Sdim assert(FrameOffset >= 0 && MI.getOperand(OffsetOperandNum).getImm() >= 0); 79353358Sdim int64_t Offset = MI.getOperand(OffsetOperandNum).getImm() + FrameOffset; 80296417Sdim 81309124Sdim if (static_cast<uint64_t>(Offset) <= std::numeric_limits<uint32_t>::max()) { 82353358Sdim MI.getOperand(OffsetOperandNum).setImm(Offset); 83309124Sdim MI.getOperand(FIOperandNum) 84353358Sdim .ChangeToRegister(FrameRegister, /*isDef=*/false); 85309124Sdim return; 86296417Sdim } 87309124Sdim } 88296417Sdim 89309124Sdim // If this is an address being added to a constant, fold the frame offset 90309124Sdim // into the constant. 91309124Sdim if (MI.getOpcode() == WebAssembly::ADD_I32) { 92309124Sdim MachineOperand &OtherMO = MI.getOperand(3 - FIOperandNum); 93309124Sdim if (OtherMO.isReg()) { 94360784Sdim Register OtherMOReg = OtherMO.getReg(); 95360784Sdim if (Register::isVirtualRegister(OtherMOReg)) { 96309124Sdim MachineInstr *Def = MF.getRegInfo().getUniqueVRegDef(OtherMOReg); 97309124Sdim // TODO: For now we just opportunistically do this in the case where 98309124Sdim // the CONST_I32 happens to have exactly one def and one use. We 99309124Sdim // should generalize this to optimize in more cases. 100309124Sdim if (Def && Def->getOpcode() == WebAssembly::CONST_I32 && 101309124Sdim MRI.hasOneNonDBGUse(Def->getOperand(0).getReg())) { 102309124Sdim MachineOperand &ImmMO = Def->getOperand(1); 103309124Sdim ImmMO.setImm(ImmMO.getImm() + uint32_t(FrameOffset)); 104309124Sdim MI.getOperand(FIOperandNum) 105353358Sdim .ChangeToRegister(FrameRegister, /*isDef=*/false); 106309124Sdim return; 107309124Sdim } 108309124Sdim } 109309124Sdim } 110309124Sdim } 111309124Sdim 112309124Sdim // Otherwise create an i32.add SP, offset and make it the operand. 113309124Sdim const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 114309124Sdim 115314564Sdim unsigned FIRegOperand = FrameRegister; 116309124Sdim if (FrameOffset) { 117309124Sdim // Create i32.add SP, offset and make it the operand. 118309124Sdim const TargetRegisterClass *PtrRC = 119309124Sdim MRI.getTargetRegisterInfo()->getPointerRegClass(MF); 120360784Sdim Register OffsetOp = MRI.createVirtualRegister(PtrRC); 121309124Sdim BuildMI(MBB, *II, II->getDebugLoc(), TII->get(WebAssembly::CONST_I32), 122309124Sdim OffsetOp) 123296417Sdim .addImm(FrameOffset); 124309124Sdim FIRegOperand = MRI.createVirtualRegister(PtrRC); 125309124Sdim BuildMI(MBB, *II, II->getDebugLoc(), TII->get(WebAssembly::ADD_I32), 126309124Sdim FIRegOperand) 127314564Sdim .addReg(FrameRegister) 128309124Sdim .addReg(OffsetOp); 129296417Sdim } 130353358Sdim MI.getOperand(FIOperandNum).ChangeToRegister(FIRegOperand, /*isDef=*/false); 131286684Sdim} 132286684Sdim 133353358SdimRegister 134286684SdimWebAssemblyRegisterInfo::getFrameRegister(const MachineFunction &MF) const { 135286684Sdim static const unsigned Regs[2][2] = { 136286684Sdim /* !isArch64Bit isArch64Bit */ 137286684Sdim /* !hasFP */ {WebAssembly::SP32, WebAssembly::SP64}, 138286684Sdim /* hasFP */ {WebAssembly::FP32, WebAssembly::FP64}}; 139286684Sdim const WebAssemblyFrameLowering *TFI = getFrameLowering(MF); 140286684Sdim return Regs[TFI->hasFP(MF)][TT.isArch64Bit()]; 141286684Sdim} 142286684Sdim 143296417Sdimconst TargetRegisterClass * 144296417SdimWebAssemblyRegisterInfo::getPointerRegClass(const MachineFunction &MF, 145296417Sdim unsigned Kind) const { 146296417Sdim assert(Kind == 0 && "Only one kind of pointer on WebAssembly"); 147296417Sdim if (MF.getSubtarget<WebAssemblySubtarget>().hasAddr64()) 148296417Sdim return &WebAssembly::I64RegClass; 149296417Sdim return &WebAssembly::I32RegClass; 150286684Sdim} 151