xref: /src/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
11a82d4c0SDimitry Andric //===-- WebAssemblyRegisterInfo.cpp - WebAssembly Register Information ----===//
21a82d4c0SDimitry Andric //
3e6d15924SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e6d15924SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e6d15924SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
61a82d4c0SDimitry Andric //
71a82d4c0SDimitry Andric //===----------------------------------------------------------------------===//
81a82d4c0SDimitry Andric ///
91a82d4c0SDimitry Andric /// \file
10eb11fae6SDimitry Andric /// This file contains the WebAssembly implementation of the
111a82d4c0SDimitry Andric /// TargetRegisterInfo class.
121a82d4c0SDimitry Andric ///
131a82d4c0SDimitry Andric //===----------------------------------------------------------------------===//
141a82d4c0SDimitry Andric 
151a82d4c0SDimitry Andric #include "WebAssemblyRegisterInfo.h"
161a82d4c0SDimitry Andric #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
171a82d4c0SDimitry Andric #include "WebAssemblyFrameLowering.h"
181a82d4c0SDimitry Andric #include "WebAssemblyInstrInfo.h"
191a82d4c0SDimitry Andric #include "WebAssemblyMachineFunctionInfo.h"
201a82d4c0SDimitry Andric #include "WebAssemblySubtarget.h"
211a82d4c0SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h"
221a82d4c0SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
231a82d4c0SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
24d8e91e46SDimitry Andric #include "llvm/CodeGen/TargetFrameLowering.h"
251a82d4c0SDimitry Andric #include "llvm/IR/Function.h"
261a82d4c0SDimitry Andric #include "llvm/Support/raw_ostream.h"
271a82d4c0SDimitry Andric #include "llvm/Target/TargetOptions.h"
281a82d4c0SDimitry Andric using namespace llvm;
291a82d4c0SDimitry Andric 
301a82d4c0SDimitry Andric #define DEBUG_TYPE "wasm-reg-info"
311a82d4c0SDimitry Andric 
32ee8648bdSDimitry Andric #define GET_REGINFO_TARGET_DESC
33ee8648bdSDimitry Andric #include "WebAssemblyGenRegisterInfo.inc"
34ee8648bdSDimitry Andric 
WebAssemblyRegisterInfo(const Triple & TT)35ee8648bdSDimitry Andric WebAssemblyRegisterInfo::WebAssemblyRegisterInfo(const Triple &TT)
36ee8648bdSDimitry Andric     : WebAssemblyGenRegisterInfo(0), TT(TT) {}
37ee8648bdSDimitry Andric 
38ee8648bdSDimitry Andric const MCPhysReg *
getCalleeSavedRegs(const MachineFunction *) const39ee8648bdSDimitry Andric WebAssemblyRegisterInfo::getCalleeSavedRegs(const MachineFunction *) const {
40ee8648bdSDimitry Andric   static const MCPhysReg CalleeSavedRegs[] = {0};
41ee8648bdSDimitry Andric   return CalleeSavedRegs;
42ee8648bdSDimitry Andric }
43ee8648bdSDimitry Andric 
44ee8648bdSDimitry Andric BitVector
getReservedRegs(const MachineFunction &) const45dd58ef01SDimitry Andric WebAssemblyRegisterInfo::getReservedRegs(const MachineFunction & /*MF*/) const {
46ee8648bdSDimitry Andric   BitVector Reserved(getNumRegs());
47ee8648bdSDimitry Andric   for (auto Reg : {WebAssembly::SP32, WebAssembly::SP64, WebAssembly::FP32,
48ee8648bdSDimitry Andric                    WebAssembly::FP64})
49ee8648bdSDimitry Andric     Reserved.set(Reg);
50ee8648bdSDimitry Andric   return Reserved;
51ee8648bdSDimitry Andric }
52ee8648bdSDimitry Andric 
eliminateFrameIndex(MachineBasicBlock::iterator II,int SPAdj,unsigned FIOperandNum,RegScavenger *) const53e3b55780SDimitry Andric bool WebAssemblyRegisterInfo::eliminateFrameIndex(
5401095a5dSDimitry Andric     MachineBasicBlock::iterator II, int SPAdj, unsigned FIOperandNum,
5501095a5dSDimitry Andric     RegScavenger * /*RS*/) const {
56dd58ef01SDimitry Andric   assert(SPAdj == 0);
57dd58ef01SDimitry Andric   MachineInstr &MI = *II;
58dd58ef01SDimitry Andric 
59dd58ef01SDimitry Andric   MachineBasicBlock &MBB = *MI.getParent();
60dd58ef01SDimitry Andric   MachineFunction &MF = *MBB.getParent();
6101095a5dSDimitry Andric   MachineRegisterInfo &MRI = MF.getRegInfo();
62dd58ef01SDimitry Andric   int FrameIndex = MI.getOperand(FIOperandNum).getIndex();
63b915e9e0SDimitry Andric   const MachineFrameInfo &MFI = MF.getFrameInfo();
64050e163aSDimitry Andric   int64_t FrameOffset = MFI.getStackSize() + MFI.getObjectOffset(FrameIndex);
65dd58ef01SDimitry Andric 
66b915e9e0SDimitry Andric   assert(MFI.getObjectSize(FrameIndex) != 0 &&
67b915e9e0SDimitry Andric          "We assume that variable-sized objects have already been lowered, "
68b915e9e0SDimitry Andric          "and don't use FrameIndex operands.");
69e6d15924SDimitry Andric   Register FrameRegister = getFrameRegister(MF);
70b915e9e0SDimitry Andric 
7101095a5dSDimitry Andric   // If this is the address operand of a load or store, make it relative to SP
7201095a5dSDimitry Andric   // and fold the frame offset directly in.
73e6d15924SDimitry Andric   unsigned AddrOperandNum = WebAssembly::getNamedOperandIdx(
74e6d15924SDimitry Andric       MI.getOpcode(), WebAssembly::OpName::addr);
75e6d15924SDimitry Andric   if (AddrOperandNum == FIOperandNum) {
76e6d15924SDimitry Andric     unsigned OffsetOperandNum = WebAssembly::getNamedOperandIdx(
77e6d15924SDimitry Andric         MI.getOpcode(), WebAssembly::OpName::off);
78e6d15924SDimitry Andric     assert(FrameOffset >= 0 && MI.getOperand(OffsetOperandNum).getImm() >= 0);
79e6d15924SDimitry Andric     int64_t Offset = MI.getOperand(OffsetOperandNum).getImm() + FrameOffset;
80050e163aSDimitry Andric 
8101095a5dSDimitry Andric     if (static_cast<uint64_t>(Offset) <= std::numeric_limits<uint32_t>::max()) {
82e6d15924SDimitry Andric       MI.getOperand(OffsetOperandNum).setImm(Offset);
8301095a5dSDimitry Andric       MI.getOperand(FIOperandNum)
84e6d15924SDimitry Andric           .ChangeToRegister(FrameRegister, /*isDef=*/false);
85e3b55780SDimitry Andric       return false;
86050e163aSDimitry Andric     }
8701095a5dSDimitry Andric   }
88dd58ef01SDimitry Andric 
8901095a5dSDimitry Andric   // If this is an address being added to a constant, fold the frame offset
9001095a5dSDimitry Andric   // into the constant.
91cfca06d7SDimitry Andric   if (MI.getOpcode() == WebAssemblyFrameLowering::getOpcAdd(MF)) {
9201095a5dSDimitry Andric     MachineOperand &OtherMO = MI.getOperand(3 - FIOperandNum);
9301095a5dSDimitry Andric     if (OtherMO.isReg()) {
941d5ae102SDimitry Andric       Register OtherMOReg = OtherMO.getReg();
95e3b55780SDimitry Andric       if (OtherMOReg.isVirtual()) {
9601095a5dSDimitry Andric         MachineInstr *Def = MF.getRegInfo().getUniqueVRegDef(OtherMOReg);
9701095a5dSDimitry Andric         // TODO: For now we just opportunistically do this in the case where
98cfca06d7SDimitry Andric         // the CONST_I32/64 happens to have exactly one def and one use. We
9901095a5dSDimitry Andric         // should generalize this to optimize in more cases.
100cfca06d7SDimitry Andric         if (Def && Def->getOpcode() ==
101cfca06d7SDimitry Andric               WebAssemblyFrameLowering::getOpcConst(MF) &&
10201095a5dSDimitry Andric             MRI.hasOneNonDBGUse(Def->getOperand(0).getReg())) {
10301095a5dSDimitry Andric           MachineOperand &ImmMO = Def->getOperand(1);
104b60736ecSDimitry Andric           if (ImmMO.isImm()) {
10501095a5dSDimitry Andric             ImmMO.setImm(ImmMO.getImm() + uint32_t(FrameOffset));
10601095a5dSDimitry Andric             MI.getOperand(FIOperandNum)
107e6d15924SDimitry Andric                 .ChangeToRegister(FrameRegister, /*isDef=*/false);
108e3b55780SDimitry Andric             return false;
109dd58ef01SDimitry Andric           }
110ee8648bdSDimitry Andric         }
11101095a5dSDimitry Andric       }
11201095a5dSDimitry Andric     }
113b60736ecSDimitry Andric   }
11401095a5dSDimitry Andric 
115cfca06d7SDimitry Andric   // Otherwise create an i32/64.add SP, offset and make it the operand.
11601095a5dSDimitry Andric   const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
11701095a5dSDimitry Andric 
118b915e9e0SDimitry Andric   unsigned FIRegOperand = FrameRegister;
11901095a5dSDimitry Andric   if (FrameOffset) {
120cfca06d7SDimitry Andric     // Create i32/64.add SP, offset and make it the operand.
12101095a5dSDimitry Andric     const TargetRegisterClass *PtrRC =
12201095a5dSDimitry Andric         MRI.getTargetRegisterInfo()->getPointerRegClass(MF);
1231d5ae102SDimitry Andric     Register OffsetOp = MRI.createVirtualRegister(PtrRC);
124cfca06d7SDimitry Andric     BuildMI(MBB, *II, II->getDebugLoc(),
125cfca06d7SDimitry Andric             TII->get(WebAssemblyFrameLowering::getOpcConst(MF)),
12601095a5dSDimitry Andric             OffsetOp)
12701095a5dSDimitry Andric         .addImm(FrameOffset);
12801095a5dSDimitry Andric     FIRegOperand = MRI.createVirtualRegister(PtrRC);
129cfca06d7SDimitry Andric     BuildMI(MBB, *II, II->getDebugLoc(),
130cfca06d7SDimitry Andric             TII->get(WebAssemblyFrameLowering::getOpcAdd(MF)),
13101095a5dSDimitry Andric             FIRegOperand)
132b915e9e0SDimitry Andric         .addReg(FrameRegister)
13301095a5dSDimitry Andric         .addReg(OffsetOp);
13401095a5dSDimitry Andric   }
135e6d15924SDimitry Andric   MI.getOperand(FIOperandNum).ChangeToRegister(FIRegOperand, /*isDef=*/false);
136e3b55780SDimitry Andric   return false;
13701095a5dSDimitry Andric }
138ee8648bdSDimitry Andric 
139e6d15924SDimitry Andric Register
getFrameRegister(const MachineFunction & MF) const140ee8648bdSDimitry Andric WebAssemblyRegisterInfo::getFrameRegister(const MachineFunction &MF) const {
141cfca06d7SDimitry Andric   // If the PReg has been replaced by a VReg, return that.
142cfca06d7SDimitry Andric   const auto &MFI = MF.getInfo<WebAssemblyFunctionInfo>();
143cfca06d7SDimitry Andric   if (MFI->isFrameBaseVirtual())
144cfca06d7SDimitry Andric     return MFI->getFrameBaseVreg();
145ee8648bdSDimitry Andric   static const unsigned Regs[2][2] = {
146ee8648bdSDimitry Andric       /*            !isArch64Bit       isArch64Bit      */
147ee8648bdSDimitry Andric       /* !hasFP */ {WebAssembly::SP32, WebAssembly::SP64},
148ee8648bdSDimitry Andric       /*  hasFP */ {WebAssembly::FP32, WebAssembly::FP64}};
149ee8648bdSDimitry Andric   const WebAssemblyFrameLowering *TFI = getFrameLowering(MF);
150ee8648bdSDimitry Andric   return Regs[TFI->hasFP(MF)][TT.isArch64Bit()];
151ee8648bdSDimitry Andric }
152ee8648bdSDimitry Andric 
153dd58ef01SDimitry Andric const TargetRegisterClass *
getPointerRegClass(const MachineFunction & MF,unsigned Kind) const154dd58ef01SDimitry Andric WebAssemblyRegisterInfo::getPointerRegClass(const MachineFunction &MF,
155dd58ef01SDimitry Andric                                             unsigned Kind) const {
156dd58ef01SDimitry Andric   assert(Kind == 0 && "Only one kind of pointer on WebAssembly");
157dd58ef01SDimitry Andric   if (MF.getSubtarget<WebAssemblySubtarget>().hasAddr64())
158dd58ef01SDimitry Andric     return &WebAssembly::I64RegClass;
159dd58ef01SDimitry Andric   return &WebAssembly::I32RegClass;
160ee8648bdSDimitry Andric }
161