WebAssemblyRegisterInfo.cpp revision 360784
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" 28using namespace llvm; 29 30#define DEBUG_TYPE "wasm-reg-info" 31 32#define GET_REGINFO_TARGET_DESC 33#include "WebAssemblyGenRegisterInfo.inc" 34 35WebAssemblyRegisterInfo::WebAssemblyRegisterInfo(const Triple &TT) 36 : WebAssemblyGenRegisterInfo(0), TT(TT) {} 37 38const MCPhysReg * 39WebAssemblyRegisterInfo::getCalleeSavedRegs(const MachineFunction *) const { 40 static const MCPhysReg CalleeSavedRegs[] = {0}; 41 return CalleeSavedRegs; 42} 43 44BitVector 45WebAssemblyRegisterInfo::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 53void 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; 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() == WebAssembly::ADD_I32) { 92 MachineOperand &OtherMO = MI.getOperand(3 - FIOperandNum); 93 if (OtherMO.isReg()) { 94 Register OtherMOReg = OtherMO.getReg(); 95 if (Register::isVirtualRegister(OtherMOReg)) { 96 MachineInstr *Def = MF.getRegInfo().getUniqueVRegDef(OtherMOReg); 97 // TODO: For now we just opportunistically do this in the case where 98 // the CONST_I32 happens to have exactly one def and one use. We 99 // should generalize this to optimize in more cases. 100 if (Def && Def->getOpcode() == WebAssembly::CONST_I32 && 101 MRI.hasOneNonDBGUse(Def->getOperand(0).getReg())) { 102 MachineOperand &ImmMO = Def->getOperand(1); 103 ImmMO.setImm(ImmMO.getImm() + uint32_t(FrameOffset)); 104 MI.getOperand(FIOperandNum) 105 .ChangeToRegister(FrameRegister, /*isDef=*/false); 106 return; 107 } 108 } 109 } 110 } 111 112 // Otherwise create an i32.add SP, offset and make it the operand. 113 const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 114 115 unsigned FIRegOperand = FrameRegister; 116 if (FrameOffset) { 117 // Create i32.add SP, offset and make it the operand. 118 const TargetRegisterClass *PtrRC = 119 MRI.getTargetRegisterInfo()->getPointerRegClass(MF); 120 Register OffsetOp = MRI.createVirtualRegister(PtrRC); 121 BuildMI(MBB, *II, II->getDebugLoc(), TII->get(WebAssembly::CONST_I32), 122 OffsetOp) 123 .addImm(FrameOffset); 124 FIRegOperand = MRI.createVirtualRegister(PtrRC); 125 BuildMI(MBB, *II, II->getDebugLoc(), TII->get(WebAssembly::ADD_I32), 126 FIRegOperand) 127 .addReg(FrameRegister) 128 .addReg(OffsetOp); 129 } 130 MI.getOperand(FIOperandNum).ChangeToRegister(FIRegOperand, /*isDef=*/false); 131} 132 133Register 134WebAssemblyRegisterInfo::getFrameRegister(const MachineFunction &MF) const { 135 static const unsigned Regs[2][2] = { 136 /* !isArch64Bit isArch64Bit */ 137 /* !hasFP */ {WebAssembly::SP32, WebAssembly::SP64}, 138 /* hasFP */ {WebAssembly::FP32, WebAssembly::FP64}}; 139 const WebAssemblyFrameLowering *TFI = getFrameLowering(MF); 140 return Regs[TFI->hasFP(MF)][TT.isArch64Bit()]; 141} 142 143const TargetRegisterClass * 144WebAssemblyRegisterInfo::getPointerRegClass(const MachineFunction &MF, 145 unsigned Kind) const { 146 assert(Kind == 0 && "Only one kind of pointer on WebAssembly"); 147 if (MF.getSubtarget<WebAssemblySubtarget>().hasAddr64()) 148 return &WebAssembly::I64RegClass; 149 return &WebAssembly::I32RegClass; 150} 151