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