WebAssemblyRegisterInfo.cpp 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  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. #include "WebAssemblyRegisterInfo.h"
  15. #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
  16. #include "WebAssemblyFrameLowering.h"
  17. #include "WebAssemblyInstrInfo.h"
  18. #include "WebAssemblyMachineFunctionInfo.h"
  19. #include "WebAssemblySubtarget.h"
  20. #include "llvm/CodeGen/MachineFrameInfo.h"
  21. #include "llvm/CodeGen/MachineInstrBuilder.h"
  22. #include "llvm/CodeGen/MachineRegisterInfo.h"
  23. #include "llvm/CodeGen/TargetFrameLowering.h"
  24. #include "llvm/IR/Function.h"
  25. #include "llvm/Support/raw_ostream.h"
  26. #include "llvm/Target/TargetOptions.h"
  27. using namespace llvm;
  28. #define DEBUG_TYPE "wasm-reg-info"
  29. #define GET_REGINFO_TARGET_DESC
  30. #include "WebAssemblyGenRegisterInfo.inc"
  31. WebAssemblyRegisterInfo::WebAssemblyRegisterInfo(const Triple &TT)
  32. : WebAssemblyGenRegisterInfo(0), TT(TT) {}
  33. const MCPhysReg *
  34. WebAssemblyRegisterInfo::getCalleeSavedRegs(const MachineFunction *) const {
  35. static const MCPhysReg CalleeSavedRegs[] = {0};
  36. return CalleeSavedRegs;
  37. }
  38. BitVector
  39. WebAssemblyRegisterInfo::getReservedRegs(const MachineFunction & /*MF*/) const {
  40. BitVector Reserved(getNumRegs());
  41. for (auto Reg : {WebAssembly::SP32, WebAssembly::SP64, WebAssembly::FP32,
  42. WebAssembly::FP64})
  43. Reserved.set(Reg);
  44. return Reserved;
  45. }
  46. bool WebAssemblyRegisterInfo::eliminateFrameIndex(
  47. MachineBasicBlock::iterator II, int SPAdj, unsigned FIOperandNum,
  48. RegScavenger * /*RS*/) const {
  49. assert(SPAdj == 0);
  50. MachineInstr &MI = *II;
  51. MachineBasicBlock &MBB = *MI.getParent();
  52. MachineFunction &MF = *MBB.getParent();
  53. MachineRegisterInfo &MRI = MF.getRegInfo();
  54. int FrameIndex = MI.getOperand(FIOperandNum).getIndex();
  55. const MachineFrameInfo &MFI = MF.getFrameInfo();
  56. int64_t FrameOffset = MFI.getStackSize() + MFI.getObjectOffset(FrameIndex);
  57. assert(MFI.getObjectSize(FrameIndex) != 0 &&
  58. "We assume that variable-sized objects have already been lowered, "
  59. "and don't use FrameIndex operands.");
  60. Register FrameRegister = getFrameRegister(MF);
  61. // If this is the address operand of a load or store, make it relative to SP
  62. // and fold the frame offset directly in.
  63. unsigned AddrOperandNum = WebAssembly::getNamedOperandIdx(
  64. MI.getOpcode(), WebAssembly::OpName::addr);
  65. if (AddrOperandNum == FIOperandNum) {
  66. unsigned OffsetOperandNum = WebAssembly::getNamedOperandIdx(
  67. MI.getOpcode(), WebAssembly::OpName::off);
  68. assert(FrameOffset >= 0 && MI.getOperand(OffsetOperandNum).getImm() >= 0);
  69. int64_t Offset = MI.getOperand(OffsetOperandNum).getImm() + FrameOffset;
  70. if (static_cast<uint64_t>(Offset) <= std::numeric_limits<uint32_t>::max()) {
  71. MI.getOperand(OffsetOperandNum).setImm(Offset);
  72. MI.getOperand(FIOperandNum)
  73. .ChangeToRegister(FrameRegister, /*isDef=*/false);
  74. return false;
  75. }
  76. }
  77. // If this is an address being added to a constant, fold the frame offset
  78. // into the constant.
  79. if (MI.getOpcode() == WebAssemblyFrameLowering::getOpcAdd(MF)) {
  80. MachineOperand &OtherMO = MI.getOperand(3 - FIOperandNum);
  81. if (OtherMO.isReg()) {
  82. Register OtherMOReg = OtherMO.getReg();
  83. if (OtherMOReg.isVirtual()) {
  84. MachineInstr *Def = MF.getRegInfo().getUniqueVRegDef(OtherMOReg);
  85. // TODO: For now we just opportunistically do this in the case where
  86. // the CONST_I32/64 happens to have exactly one def and one use. We
  87. // should generalize this to optimize in more cases.
  88. if (Def && Def->getOpcode() ==
  89. WebAssemblyFrameLowering::getOpcConst(MF) &&
  90. MRI.hasOneNonDBGUse(Def->getOperand(0).getReg())) {
  91. MachineOperand &ImmMO = Def->getOperand(1);
  92. if (ImmMO.isImm()) {
  93. ImmMO.setImm(ImmMO.getImm() + uint32_t(FrameOffset));
  94. MI.getOperand(FIOperandNum)
  95. .ChangeToRegister(FrameRegister, /*isDef=*/false);
  96. return false;
  97. }
  98. }
  99. }
  100. }
  101. }
  102. // Otherwise create an i32/64.add SP, offset and make it the operand.
  103. const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
  104. unsigned FIRegOperand = FrameRegister;
  105. if (FrameOffset) {
  106. // Create i32/64.add SP, offset and make it the operand.
  107. const TargetRegisterClass *PtrRC =
  108. MRI.getTargetRegisterInfo()->getPointerRegClass(MF);
  109. Register OffsetOp = MRI.createVirtualRegister(PtrRC);
  110. BuildMI(MBB, *II, II->getDebugLoc(),
  111. TII->get(WebAssemblyFrameLowering::getOpcConst(MF)),
  112. OffsetOp)
  113. .addImm(FrameOffset);
  114. FIRegOperand = MRI.createVirtualRegister(PtrRC);
  115. BuildMI(MBB, *II, II->getDebugLoc(),
  116. TII->get(WebAssemblyFrameLowering::getOpcAdd(MF)),
  117. FIRegOperand)
  118. .addReg(FrameRegister)
  119. .addReg(OffsetOp);
  120. }
  121. MI.getOperand(FIOperandNum).ChangeToRegister(FIRegOperand, /*isDef=*/false);
  122. return false;
  123. }
  124. Register
  125. WebAssemblyRegisterInfo::getFrameRegister(const MachineFunction &MF) const {
  126. // If the PReg has been replaced by a VReg, return that.
  127. const auto &MFI = MF.getInfo<WebAssemblyFunctionInfo>();
  128. if (MFI->isFrameBaseVirtual())
  129. return MFI->getFrameBaseVreg();
  130. static const unsigned Regs[2][2] = {
  131. /* !isArch64Bit isArch64Bit */
  132. /* !hasFP */ {WebAssembly::SP32, WebAssembly::SP64},
  133. /* hasFP */ {WebAssembly::FP32, WebAssembly::FP64}};
  134. const WebAssemblyFrameLowering *TFI = getFrameLowering(MF);
  135. return Regs[TFI->hasFP(MF)][TT.isArch64Bit()];
  136. }
  137. const TargetRegisterClass *
  138. WebAssemblyRegisterInfo::getPointerRegClass(const MachineFunction &MF,
  139. unsigned Kind) const {
  140. assert(Kind == 0 && "Only one kind of pointer on WebAssembly");
  141. if (MF.getSubtarget<WebAssemblySubtarget>().hasAddr64())
  142. return &WebAssembly::I64RegClass;
  143. return &WebAssembly::I32RegClass;
  144. }