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