xref: /freebsd/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.cpp (revision 770cf0a5f02dc8983a89c6568d741fbc25baa999)
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/Target/TargetOptions.h"
26 using namespace llvm;
27 
28 #define DEBUG_TYPE "wasm-reg-info"
29 
30 #define GET_REGINFO_TARGET_DESC
31 #include "WebAssemblyGenRegisterInfo.inc"
32 
33 WebAssemblyRegisterInfo::WebAssemblyRegisterInfo(const Triple &TT)
34     : WebAssemblyGenRegisterInfo(0), TT(TT) {}
35 
36 const MCPhysReg *
37 WebAssemblyRegisterInfo::getCalleeSavedRegs(const MachineFunction *) const {
38   static const MCPhysReg CalleeSavedRegs[] = {0};
39   return CalleeSavedRegs;
40 }
41 
42 BitVector
43 WebAssemblyRegisterInfo::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 
51 bool 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 SP
70   // 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 offset
88   // 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 where
96         // the CONST_I32/64 happens to have exactly one def and one use. We
97         // 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(MF);
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 
137 Register
138 WebAssemblyRegisterInfo::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 
151 const TargetRegisterClass *
152 WebAssemblyRegisterInfo::getPointerRegClass(const MachineFunction &MF,
153                                             unsigned Kind) const {
154   assert(Kind == 0 && "Only one kind of pointer on WebAssembly");
155   if (MF.getSubtarget<WebAssemblySubtarget>().hasAddr64())
156     return &WebAssembly::I64RegClass;
157   return &WebAssembly::I32RegClass;
158 }
159