10b57cec5SDimitry Andric //===-- WebAssemblyRegisterInfo.cpp - WebAssembly Register Information ----===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric ///
90b57cec5SDimitry Andric /// \file
100b57cec5SDimitry Andric /// This file contains the WebAssembly implementation of the
110b57cec5SDimitry Andric /// TargetRegisterInfo class.
120b57cec5SDimitry Andric ///
130b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
140b57cec5SDimitry Andric 
150b57cec5SDimitry Andric #include "WebAssemblyRegisterInfo.h"
160b57cec5SDimitry Andric #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
170b57cec5SDimitry Andric #include "WebAssemblyFrameLowering.h"
180b57cec5SDimitry Andric #include "WebAssemblyInstrInfo.h"
190b57cec5SDimitry Andric #include "WebAssemblyMachineFunctionInfo.h"
200b57cec5SDimitry Andric #include "WebAssemblySubtarget.h"
210b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h"
220b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
230b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
240b57cec5SDimitry Andric #include "llvm/CodeGen/TargetFrameLowering.h"
250b57cec5SDimitry Andric #include "llvm/IR/Function.h"
260b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
270b57cec5SDimitry Andric #include "llvm/Target/TargetOptions.h"
280b57cec5SDimitry Andric using namespace llvm;
290b57cec5SDimitry Andric 
300b57cec5SDimitry Andric #define DEBUG_TYPE "wasm-reg-info"
310b57cec5SDimitry Andric 
320b57cec5SDimitry Andric #define GET_REGINFO_TARGET_DESC
330b57cec5SDimitry Andric #include "WebAssemblyGenRegisterInfo.inc"
340b57cec5SDimitry Andric 
WebAssemblyRegisterInfo(const Triple & TT)350b57cec5SDimitry Andric WebAssemblyRegisterInfo::WebAssemblyRegisterInfo(const Triple &TT)
360b57cec5SDimitry Andric     : WebAssemblyGenRegisterInfo(0), TT(TT) {}
370b57cec5SDimitry Andric 
380b57cec5SDimitry Andric const MCPhysReg *
getCalleeSavedRegs(const MachineFunction *) const390b57cec5SDimitry Andric WebAssemblyRegisterInfo::getCalleeSavedRegs(const MachineFunction *) const {
400b57cec5SDimitry Andric   static const MCPhysReg CalleeSavedRegs[] = {0};
410b57cec5SDimitry Andric   return CalleeSavedRegs;
420b57cec5SDimitry Andric }
430b57cec5SDimitry Andric 
440b57cec5SDimitry Andric BitVector
getReservedRegs(const MachineFunction &) const450b57cec5SDimitry Andric WebAssemblyRegisterInfo::getReservedRegs(const MachineFunction & /*MF*/) const {
460b57cec5SDimitry Andric   BitVector Reserved(getNumRegs());
470b57cec5SDimitry Andric   for (auto Reg : {WebAssembly::SP32, WebAssembly::SP64, WebAssembly::FP32,
480b57cec5SDimitry Andric                    WebAssembly::FP64})
490b57cec5SDimitry Andric     Reserved.set(Reg);
500b57cec5SDimitry Andric   return Reserved;
510b57cec5SDimitry Andric }
520b57cec5SDimitry Andric 
eliminateFrameIndex(MachineBasicBlock::iterator II,int SPAdj,unsigned FIOperandNum,RegScavenger *) const53bdd1243dSDimitry Andric bool WebAssemblyRegisterInfo::eliminateFrameIndex(
540b57cec5SDimitry Andric     MachineBasicBlock::iterator II, int SPAdj, unsigned FIOperandNum,
550b57cec5SDimitry Andric     RegScavenger * /*RS*/) const {
560b57cec5SDimitry Andric   assert(SPAdj == 0);
570b57cec5SDimitry Andric   MachineInstr &MI = *II;
580b57cec5SDimitry Andric 
590b57cec5SDimitry Andric   MachineBasicBlock &MBB = *MI.getParent();
600b57cec5SDimitry Andric   MachineFunction &MF = *MBB.getParent();
610b57cec5SDimitry Andric   MachineRegisterInfo &MRI = MF.getRegInfo();
620b57cec5SDimitry Andric   int FrameIndex = MI.getOperand(FIOperandNum).getIndex();
630b57cec5SDimitry Andric   const MachineFrameInfo &MFI = MF.getFrameInfo();
640b57cec5SDimitry Andric   int64_t FrameOffset = MFI.getStackSize() + MFI.getObjectOffset(FrameIndex);
650b57cec5SDimitry Andric 
660b57cec5SDimitry Andric   assert(MFI.getObjectSize(FrameIndex) != 0 &&
670b57cec5SDimitry Andric          "We assume that variable-sized objects have already been lowered, "
680b57cec5SDimitry Andric          "and don't use FrameIndex operands.");
690b57cec5SDimitry Andric   Register FrameRegister = getFrameRegister(MF);
700b57cec5SDimitry Andric 
710b57cec5SDimitry Andric   // If this is the address operand of a load or store, make it relative to SP
720b57cec5SDimitry Andric   // and fold the frame offset directly in.
730b57cec5SDimitry Andric   unsigned AddrOperandNum = WebAssembly::getNamedOperandIdx(
740b57cec5SDimitry Andric       MI.getOpcode(), WebAssembly::OpName::addr);
750b57cec5SDimitry Andric   if (AddrOperandNum == FIOperandNum) {
760b57cec5SDimitry Andric     unsigned OffsetOperandNum = WebAssembly::getNamedOperandIdx(
770b57cec5SDimitry Andric         MI.getOpcode(), WebAssembly::OpName::off);
780b57cec5SDimitry Andric     assert(FrameOffset >= 0 && MI.getOperand(OffsetOperandNum).getImm() >= 0);
790b57cec5SDimitry Andric     int64_t Offset = MI.getOperand(OffsetOperandNum).getImm() + FrameOffset;
800b57cec5SDimitry Andric 
810b57cec5SDimitry Andric     if (static_cast<uint64_t>(Offset) <= std::numeric_limits<uint32_t>::max()) {
820b57cec5SDimitry Andric       MI.getOperand(OffsetOperandNum).setImm(Offset);
830b57cec5SDimitry Andric       MI.getOperand(FIOperandNum)
840b57cec5SDimitry Andric           .ChangeToRegister(FrameRegister, /*isDef=*/false);
85bdd1243dSDimitry Andric       return false;
860b57cec5SDimitry Andric     }
870b57cec5SDimitry Andric   }
880b57cec5SDimitry Andric 
890b57cec5SDimitry Andric   // If this is an address being added to a constant, fold the frame offset
900b57cec5SDimitry Andric   // into the constant.
915ffd83dbSDimitry Andric   if (MI.getOpcode() == WebAssemblyFrameLowering::getOpcAdd(MF)) {
920b57cec5SDimitry Andric     MachineOperand &OtherMO = MI.getOperand(3 - FIOperandNum);
930b57cec5SDimitry Andric     if (OtherMO.isReg()) {
948bcb0991SDimitry Andric       Register OtherMOReg = OtherMO.getReg();
95bdd1243dSDimitry Andric       if (OtherMOReg.isVirtual()) {
960b57cec5SDimitry Andric         MachineInstr *Def = MF.getRegInfo().getUniqueVRegDef(OtherMOReg);
970b57cec5SDimitry Andric         // TODO: For now we just opportunistically do this in the case where
985ffd83dbSDimitry Andric         // the CONST_I32/64 happens to have exactly one def and one use. We
990b57cec5SDimitry Andric         // should generalize this to optimize in more cases.
1005ffd83dbSDimitry Andric         if (Def && Def->getOpcode() ==
1015ffd83dbSDimitry Andric               WebAssemblyFrameLowering::getOpcConst(MF) &&
1020b57cec5SDimitry Andric             MRI.hasOneNonDBGUse(Def->getOperand(0).getReg())) {
1030b57cec5SDimitry Andric           MachineOperand &ImmMO = Def->getOperand(1);
104eaeb601bSDimitry Andric           if (ImmMO.isImm()) {
1050b57cec5SDimitry Andric             ImmMO.setImm(ImmMO.getImm() + uint32_t(FrameOffset));
1060b57cec5SDimitry Andric             MI.getOperand(FIOperandNum)
1070b57cec5SDimitry Andric                 .ChangeToRegister(FrameRegister, /*isDef=*/false);
108bdd1243dSDimitry Andric             return false;
1090b57cec5SDimitry Andric           }
1100b57cec5SDimitry Andric         }
1110b57cec5SDimitry Andric       }
1120b57cec5SDimitry Andric     }
113eaeb601bSDimitry Andric   }
1140b57cec5SDimitry Andric 
1155ffd83dbSDimitry Andric   // Otherwise create an i32/64.add SP, offset and make it the operand.
1160b57cec5SDimitry Andric   const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
1170b57cec5SDimitry Andric 
1180b57cec5SDimitry Andric   unsigned FIRegOperand = FrameRegister;
1190b57cec5SDimitry Andric   if (FrameOffset) {
1205ffd83dbSDimitry Andric     // Create i32/64.add SP, offset and make it the operand.
1210b57cec5SDimitry Andric     const TargetRegisterClass *PtrRC =
1220b57cec5SDimitry Andric         MRI.getTargetRegisterInfo()->getPointerRegClass(MF);
1238bcb0991SDimitry Andric     Register OffsetOp = MRI.createVirtualRegister(PtrRC);
1245ffd83dbSDimitry Andric     BuildMI(MBB, *II, II->getDebugLoc(),
1255ffd83dbSDimitry Andric             TII->get(WebAssemblyFrameLowering::getOpcConst(MF)),
1260b57cec5SDimitry Andric             OffsetOp)
1270b57cec5SDimitry Andric         .addImm(FrameOffset);
1280b57cec5SDimitry Andric     FIRegOperand = MRI.createVirtualRegister(PtrRC);
1295ffd83dbSDimitry Andric     BuildMI(MBB, *II, II->getDebugLoc(),
1305ffd83dbSDimitry Andric             TII->get(WebAssemblyFrameLowering::getOpcAdd(MF)),
1310b57cec5SDimitry Andric             FIRegOperand)
1320b57cec5SDimitry Andric         .addReg(FrameRegister)
1330b57cec5SDimitry Andric         .addReg(OffsetOp);
1340b57cec5SDimitry Andric   }
1350b57cec5SDimitry Andric   MI.getOperand(FIOperandNum).ChangeToRegister(FIRegOperand, /*isDef=*/false);
136bdd1243dSDimitry Andric   return false;
1370b57cec5SDimitry Andric }
1380b57cec5SDimitry Andric 
1390b57cec5SDimitry Andric Register
getFrameRegister(const MachineFunction & MF) const1400b57cec5SDimitry Andric WebAssemblyRegisterInfo::getFrameRegister(const MachineFunction &MF) const {
1415ffd83dbSDimitry Andric   // If the PReg has been replaced by a VReg, return that.
1425ffd83dbSDimitry Andric   const auto &MFI = MF.getInfo<WebAssemblyFunctionInfo>();
1435ffd83dbSDimitry Andric   if (MFI->isFrameBaseVirtual())
1445ffd83dbSDimitry Andric     return MFI->getFrameBaseVreg();
1450b57cec5SDimitry Andric   static const unsigned Regs[2][2] = {
1460b57cec5SDimitry Andric       /*            !isArch64Bit       isArch64Bit      */
1470b57cec5SDimitry Andric       /* !hasFP */ {WebAssembly::SP32, WebAssembly::SP64},
1480b57cec5SDimitry Andric       /*  hasFP */ {WebAssembly::FP32, WebAssembly::FP64}};
1490b57cec5SDimitry Andric   const WebAssemblyFrameLowering *TFI = getFrameLowering(MF);
1500b57cec5SDimitry Andric   return Regs[TFI->hasFP(MF)][TT.isArch64Bit()];
1510b57cec5SDimitry Andric }
1520b57cec5SDimitry Andric 
1530b57cec5SDimitry Andric const TargetRegisterClass *
getPointerRegClass(const MachineFunction & MF,unsigned Kind) const1540b57cec5SDimitry Andric WebAssemblyRegisterInfo::getPointerRegClass(const MachineFunction &MF,
1550b57cec5SDimitry Andric                                             unsigned Kind) const {
1560b57cec5SDimitry Andric   assert(Kind == 0 && "Only one kind of pointer on WebAssembly");
1570b57cec5SDimitry Andric   if (MF.getSubtarget<WebAssemblySubtarget>().hasAddr64())
1580b57cec5SDimitry Andric     return &WebAssembly::I64RegClass;
1590b57cec5SDimitry Andric   return &WebAssembly::I32RegClass;
1600b57cec5SDimitry Andric }
161