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