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