110e730a2SDan Gohman //===-- WebAssemblyRegisterInfo.cpp - WebAssembly Register Information ----===//
210e730a2SDan Gohman //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
610e730a2SDan Gohman //
710e730a2SDan Gohman //===----------------------------------------------------------------------===//
810e730a2SDan Gohman ///
910e730a2SDan Gohman /// \file
105f8f34e4SAdrian Prantl /// This file contains the WebAssembly implementation of the
1110e730a2SDan Gohman /// TargetRegisterInfo class.
1210e730a2SDan Gohman ///
1310e730a2SDan Gohman //===----------------------------------------------------------------------===//
1410e730a2SDan Gohman 
1510e730a2SDan Gohman #include "WebAssemblyRegisterInfo.h"
1610e730a2SDan Gohman #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
1710e730a2SDan Gohman #include "WebAssemblyFrameLowering.h"
1810e730a2SDan Gohman #include "WebAssemblyInstrInfo.h"
1910e730a2SDan Gohman #include "WebAssemblyMachineFunctionInfo.h"
2010e730a2SDan Gohman #include "WebAssemblySubtarget.h"
2110e730a2SDan Gohman #include "llvm/CodeGen/MachineFrameInfo.h"
2210e730a2SDan Gohman #include "llvm/CodeGen/MachineInstrBuilder.h"
2310e730a2SDan Gohman #include "llvm/CodeGen/MachineRegisterInfo.h"
24f208f631SHeejin Ahn #include "llvm/CodeGen/TargetFrameLowering.h"
2510e730a2SDan Gohman #include "llvm/IR/Function.h"
2610e730a2SDan Gohman #include "llvm/Support/raw_ostream.h"
2710e730a2SDan Gohman #include "llvm/Target/TargetOptions.h"
2810e730a2SDan Gohman using namespace llvm;
2910e730a2SDan Gohman 
3010e730a2SDan Gohman #define DEBUG_TYPE "wasm-reg-info"
3110e730a2SDan Gohman 
325ca0bacaSJF Bastien #define GET_REGINFO_TARGET_DESC
335ca0bacaSJF Bastien #include "WebAssemblyGenRegisterInfo.inc"
345ca0bacaSJF Bastien 
WebAssemblyRegisterInfo(const Triple & TT)355ca0bacaSJF Bastien WebAssemblyRegisterInfo::WebAssemblyRegisterInfo(const Triple &TT)
365ca0bacaSJF Bastien     : WebAssemblyGenRegisterInfo(0), TT(TT) {}
375ca0bacaSJF Bastien 
385ca0bacaSJF Bastien const MCPhysReg *
getCalleeSavedRegs(const MachineFunction *) const395ca0bacaSJF Bastien WebAssemblyRegisterInfo::getCalleeSavedRegs(const MachineFunction *) const {
405ca0bacaSJF Bastien   static const MCPhysReg CalleeSavedRegs[] = {0};
415ca0bacaSJF Bastien   return CalleeSavedRegs;
425ca0bacaSJF Bastien }
435ca0bacaSJF Bastien 
445ca0bacaSJF Bastien BitVector
getReservedRegs(const MachineFunction &) const457a6b9825SDan Gohman WebAssemblyRegisterInfo::getReservedRegs(const MachineFunction & /*MF*/) const {
465ca0bacaSJF Bastien   BitVector Reserved(getNumRegs());
475ca0bacaSJF Bastien   for (auto Reg : {WebAssembly::SP32, WebAssembly::SP64, WebAssembly::FP32,
485ca0bacaSJF Bastien                    WebAssembly::FP64})
495ca0bacaSJF Bastien     Reserved.set(Reg);
505ca0bacaSJF Bastien   return Reserved;
515ca0bacaSJF Bastien }
525ca0bacaSJF Bastien 
eliminateFrameIndex(MachineBasicBlock::iterator II,int SPAdj,unsigned FIOperandNum,RegScavenger *) const535ca0bacaSJF Bastien void WebAssemblyRegisterInfo::eliminateFrameIndex(
54ec977b07SDan Gohman     MachineBasicBlock::iterator II, int SPAdj, unsigned FIOperandNum,
55ec977b07SDan Gohman     RegScavenger * /*RS*/) const {
569769debfSDerek Schuff   assert(SPAdj == 0);
579769debfSDerek Schuff   MachineInstr &MI = *II;
589769debfSDerek Schuff 
599769debfSDerek Schuff   MachineBasicBlock &MBB = *MI.getParent();
609769debfSDerek Schuff   MachineFunction &MF = *MBB.getParent();
610cfb5f85SDan Gohman   MachineRegisterInfo &MRI = MF.getRegInfo();
629769debfSDerek Schuff   int FrameIndex = MI.getOperand(FIOperandNum).getIndex();
63941a705bSMatthias Braun   const MachineFrameInfo &MFI = MF.getFrameInfo();
649bfea27cSDerek Schuff   int64_t FrameOffset = MFI.getStackSize() + MFI.getObjectOffset(FrameIndex);
659769debfSDerek Schuff 
6692d300ebSDerek Schuff   assert(MFI.getObjectSize(FrameIndex) != 0 &&
6792d300ebSDerek Schuff          "We assume that variable-sized objects have already been lowered, "
6892d300ebSDerek Schuff          "and don't use FrameIndex operands.");
69e3a676e9SMatt Arsenault   Register FrameRegister = getFrameRegister(MF);
7092d300ebSDerek Schuff 
71c97ba939SDerek Schuff   // If this is the address operand of a load or store, make it relative to SP
72c97ba939SDerek Schuff   // and fold the frame offset directly in.
73972d7d51SThomas Lively   unsigned AddrOperandNum = WebAssembly::getNamedOperandIdx(
74972d7d51SThomas Lively       MI.getOpcode(), WebAssembly::OpName::addr);
75972d7d51SThomas Lively   if (AddrOperandNum == FIOperandNum) {
76972d7d51SThomas Lively     unsigned OffsetOperandNum = WebAssembly::getNamedOperandIdx(
77972d7d51SThomas Lively         MI.getOpcode(), WebAssembly::OpName::off);
78972d7d51SThomas Lively     assert(FrameOffset >= 0 && MI.getOperand(OffsetOperandNum).getImm() >= 0);
79972d7d51SThomas Lively     int64_t Offset = MI.getOperand(OffsetOperandNum).getImm() + FrameOffset;
809bfea27cSDerek Schuff 
810cfb5f85SDan Gohman     if (static_cast<uint64_t>(Offset) <= std::numeric_limits<uint32_t>::max()) {
82972d7d51SThomas Lively       MI.getOperand(OffsetOperandNum).setImm(Offset);
83fbc89d21SJF Bastien       MI.getOperand(FIOperandNum)
8449a3ad21SRui Ueyama           .ChangeToRegister(FrameRegister, /*isDef=*/false);
850cfb5f85SDan Gohman       return;
860cfb5f85SDan Gohman     }
870cfb5f85SDan Gohman   }
880cfb5f85SDan Gohman 
890cfb5f85SDan Gohman   // If this is an address being added to a constant, fold the frame offset
900cfb5f85SDan Gohman   // into the constant.
91b9a539c0SWouter van Oortmerssen   if (MI.getOpcode() == WebAssemblyFrameLowering::getOpcAdd(MF)) {
920cfb5f85SDan Gohman     MachineOperand &OtherMO = MI.getOperand(3 - FIOperandNum);
930cfb5f85SDan Gohman     if (OtherMO.isReg()) {
9405c145d6SDaniel Sanders       Register OtherMOReg = OtherMO.getReg();
952bea69bfSDaniel Sanders       if (Register::isVirtualRegister(OtherMOReg)) {
960cfb5f85SDan Gohman         MachineInstr *Def = MF.getRegInfo().getUniqueVRegDef(OtherMOReg);
970cfb5f85SDan Gohman         // TODO: For now we just opportunistically do this in the case where
98b9a539c0SWouter van Oortmerssen         // the CONST_I32/64 happens to have exactly one def and one use. We
990cfb5f85SDan Gohman         // should generalize this to optimize in more cases.
100b9a539c0SWouter van Oortmerssen         if (Def && Def->getOpcode() ==
101b9a539c0SWouter van Oortmerssen               WebAssemblyFrameLowering::getOpcConst(MF) &&
1020cfb5f85SDan Gohman             MRI.hasOneNonDBGUse(Def->getOperand(0).getReg())) {
1030cfb5f85SDan Gohman           MachineOperand &ImmMO = Def->getOperand(1);
104*0fca6517SJulien Jorge           if (ImmMO.isImm()) {
1050cfb5f85SDan Gohman             ImmMO.setImm(ImmMO.getImm() + uint32_t(FrameOffset));
1060cfb5f85SDan Gohman             MI.getOperand(FIOperandNum)
10749a3ad21SRui Ueyama                 .ChangeToRegister(FrameRegister, /*isDef=*/false);
1080cfb5f85SDan Gohman             return;
1090cfb5f85SDan Gohman           }
1100cfb5f85SDan Gohman         }
1110cfb5f85SDan Gohman       }
1120cfb5f85SDan Gohman     }
113*0fca6517SJulien Jorge   }
1140cfb5f85SDan Gohman 
115b9a539c0SWouter van Oortmerssen   // Otherwise create an i32/64.add SP, offset and make it the operand.
1163196650bSDan Gohman   const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
1179769debfSDerek Schuff 
11892d300ebSDerek Schuff   unsigned FIRegOperand = FrameRegister;
11990d9e8d3SDerek Schuff   if (FrameOffset) {
120b9a539c0SWouter van Oortmerssen     // Create i32/64.add SP, offset and make it the operand.
1210cfb5f85SDan Gohman     const TargetRegisterClass *PtrRC =
1220cfb5f85SDan Gohman         MRI.getTargetRegisterInfo()->getPointerRegClass(MF);
12305c145d6SDaniel Sanders     Register OffsetOp = MRI.createVirtualRegister(PtrRC);
124b9a539c0SWouter van Oortmerssen     BuildMI(MBB, *II, II->getDebugLoc(),
125b9a539c0SWouter van Oortmerssen             TII->get(WebAssemblyFrameLowering::getOpcConst(MF)),
126d4207ba0SDerek Schuff             OffsetOp)
127f9c0a5c3SDerek Schuff         .addImm(FrameOffset);
1280cfb5f85SDan Gohman     FIRegOperand = MRI.createVirtualRegister(PtrRC);
129b9a539c0SWouter van Oortmerssen     BuildMI(MBB, *II, II->getDebugLoc(),
130b9a539c0SWouter van Oortmerssen             TII->get(WebAssemblyFrameLowering::getOpcAdd(MF)),
13190d9e8d3SDerek Schuff             FIRegOperand)
13292d300ebSDerek Schuff         .addReg(FrameRegister)
133d4207ba0SDerek Schuff         .addReg(OffsetOp);
13490d9e8d3SDerek Schuff   }
13549a3ad21SRui Ueyama   MI.getOperand(FIOperandNum).ChangeToRegister(FIRegOperand, /*isDef=*/false);
1369769debfSDerek Schuff }
1375ca0bacaSJF Bastien 
138e3a676e9SMatt Arsenault Register
getFrameRegister(const MachineFunction & MF) const1395ca0bacaSJF Bastien WebAssemblyRegisterInfo::getFrameRegister(const MachineFunction &MF) const {
140ff171acfSDerek Schuff   // If the PReg has been replaced by a VReg, return that.
141ff171acfSDerek Schuff   const auto &MFI = MF.getInfo<WebAssemblyFunctionInfo>();
142ff171acfSDerek Schuff   if (MFI->isFrameBaseVirtual())
143ff171acfSDerek Schuff     return MFI->getFrameBaseVreg();
1445ca0bacaSJF Bastien   static const unsigned Regs[2][2] = {
1455ca0bacaSJF Bastien       /*            !isArch64Bit       isArch64Bit      */
1465ca0bacaSJF Bastien       /* !hasFP */ {WebAssembly::SP32, WebAssembly::SP64},
1475ca0bacaSJF Bastien       /*  hasFP */ {WebAssembly::FP32, WebAssembly::FP64}};
1485ca0bacaSJF Bastien   const WebAssemblyFrameLowering *TFI = getFrameLowering(MF);
1495ca0bacaSJF Bastien   return Regs[TFI->hasFP(MF)][TT.isArch64Bit()];
1505ca0bacaSJF Bastien }
15135bfb24cSDan Gohman 
15235bfb24cSDan Gohman const TargetRegisterClass *
getPointerRegClass(const MachineFunction & MF,unsigned Kind) const15335bfb24cSDan Gohman WebAssemblyRegisterInfo::getPointerRegClass(const MachineFunction &MF,
15435bfb24cSDan Gohman                                             unsigned Kind) const {
15535bfb24cSDan Gohman   assert(Kind == 0 && "Only one kind of pointer on WebAssembly");
15635bfb24cSDan Gohman   if (MF.getSubtarget<WebAssemblySubtarget>().hasAddr64())
15735bfb24cSDan Gohman     return &WebAssembly::I64RegClass;
15835bfb24cSDan Gohman   return &WebAssembly::I32RegClass;
15935bfb24cSDan Gohman }
160