xref: /aosp_15_r20/external/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp (revision 9880d6810fe72a1726cb53787c6711e909410d58)
1*9880d681SAndroid Build Coastguard Worker //===-- WebAssemblyFrameLowering.cpp - WebAssembly Frame Lowering ----------==//
2*9880d681SAndroid Build Coastguard Worker //
3*9880d681SAndroid Build Coastguard Worker //                     The LLVM Compiler Infrastructure
4*9880d681SAndroid Build Coastguard Worker //
5*9880d681SAndroid Build Coastguard Worker // This file is distributed under the University of Illinois Open Source
6*9880d681SAndroid Build Coastguard Worker // License. See LICENSE.TXT for details.
7*9880d681SAndroid Build Coastguard Worker //
8*9880d681SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
9*9880d681SAndroid Build Coastguard Worker ///
10*9880d681SAndroid Build Coastguard Worker /// \file
11*9880d681SAndroid Build Coastguard Worker /// \brief This file contains the WebAssembly implementation of
12*9880d681SAndroid Build Coastguard Worker /// TargetFrameLowering class.
13*9880d681SAndroid Build Coastguard Worker ///
14*9880d681SAndroid Build Coastguard Worker /// On WebAssembly, there aren't a lot of things to do here. There are no
15*9880d681SAndroid Build Coastguard Worker /// callee-saved registers to save, and no spill slots.
16*9880d681SAndroid Build Coastguard Worker ///
17*9880d681SAndroid Build Coastguard Worker /// The stack grows downward.
18*9880d681SAndroid Build Coastguard Worker ///
19*9880d681SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
20*9880d681SAndroid Build Coastguard Worker 
21*9880d681SAndroid Build Coastguard Worker #include "WebAssemblyFrameLowering.h"
22*9880d681SAndroid Build Coastguard Worker #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
23*9880d681SAndroid Build Coastguard Worker #include "WebAssemblyInstrInfo.h"
24*9880d681SAndroid Build Coastguard Worker #include "WebAssemblyMachineFunctionInfo.h"
25*9880d681SAndroid Build Coastguard Worker #include "WebAssemblySubtarget.h"
26*9880d681SAndroid Build Coastguard Worker #include "WebAssemblyTargetMachine.h"
27*9880d681SAndroid Build Coastguard Worker #include "llvm/CodeGen/MachineFrameInfo.h"
28*9880d681SAndroid Build Coastguard Worker #include "llvm/CodeGen/MachineFunction.h"
29*9880d681SAndroid Build Coastguard Worker #include "llvm/CodeGen/MachineInstrBuilder.h"
30*9880d681SAndroid Build Coastguard Worker #include "llvm/CodeGen/MachineModuleInfo.h"
31*9880d681SAndroid Build Coastguard Worker #include "llvm/CodeGen/MachineRegisterInfo.h"
32*9880d681SAndroid Build Coastguard Worker #include "llvm/Support/Debug.h"
33*9880d681SAndroid Build Coastguard Worker using namespace llvm;
34*9880d681SAndroid Build Coastguard Worker 
35*9880d681SAndroid Build Coastguard Worker #define DEBUG_TYPE "wasm-frame-info"
36*9880d681SAndroid Build Coastguard Worker 
37*9880d681SAndroid Build Coastguard Worker // TODO: wasm64
38*9880d681SAndroid Build Coastguard Worker // TODO: Emit TargetOpcode::CFI_INSTRUCTION instructions
39*9880d681SAndroid Build Coastguard Worker 
40*9880d681SAndroid Build Coastguard Worker /// Return true if the specified function should have a dedicated frame pointer
41*9880d681SAndroid Build Coastguard Worker /// register.
hasFP(const MachineFunction & MF) const42*9880d681SAndroid Build Coastguard Worker bool WebAssemblyFrameLowering::hasFP(const MachineFunction &MF) const {
43*9880d681SAndroid Build Coastguard Worker   const MachineFrameInfo *MFI = MF.getFrameInfo();
44*9880d681SAndroid Build Coastguard Worker   const auto *RegInfo =
45*9880d681SAndroid Build Coastguard Worker       MF.getSubtarget<WebAssemblySubtarget>().getRegisterInfo();
46*9880d681SAndroid Build Coastguard Worker   return MFI->isFrameAddressTaken() || MFI->hasVarSizedObjects() ||
47*9880d681SAndroid Build Coastguard Worker          MFI->hasStackMap() || MFI->hasPatchPoint() ||
48*9880d681SAndroid Build Coastguard Worker          RegInfo->needsStackRealignment(MF);
49*9880d681SAndroid Build Coastguard Worker }
50*9880d681SAndroid Build Coastguard Worker 
51*9880d681SAndroid Build Coastguard Worker /// Under normal circumstances, when a frame pointer is not required, we reserve
52*9880d681SAndroid Build Coastguard Worker /// argument space for call sites in the function immediately on entry to the
53*9880d681SAndroid Build Coastguard Worker /// current function. This eliminates the need for add/sub sp brackets around
54*9880d681SAndroid Build Coastguard Worker /// call sites. Returns true if the call frame is included as part of the stack
55*9880d681SAndroid Build Coastguard Worker /// frame.
hasReservedCallFrame(const MachineFunction & MF) const56*9880d681SAndroid Build Coastguard Worker bool WebAssemblyFrameLowering::hasReservedCallFrame(
57*9880d681SAndroid Build Coastguard Worker     const MachineFunction &MF) const {
58*9880d681SAndroid Build Coastguard Worker   return !MF.getFrameInfo()->hasVarSizedObjects();
59*9880d681SAndroid Build Coastguard Worker }
60*9880d681SAndroid Build Coastguard Worker 
61*9880d681SAndroid Build Coastguard Worker 
62*9880d681SAndroid Build Coastguard Worker /// Returns true if this function needs a local user-space stack pointer.
63*9880d681SAndroid Build Coastguard Worker /// Unlike a machine stack pointer, the wasm user stack pointer is a global
64*9880d681SAndroid Build Coastguard Worker /// variable, so it is loaded into a register in the prolog.
needsSP(const MachineFunction & MF,const MachineFrameInfo & MFI) const65*9880d681SAndroid Build Coastguard Worker bool WebAssemblyFrameLowering::needsSP(const MachineFunction &MF,
66*9880d681SAndroid Build Coastguard Worker                                        const MachineFrameInfo &MFI) const {
67*9880d681SAndroid Build Coastguard Worker   return MFI.getStackSize() || MFI.adjustsStack() || hasFP(MF);
68*9880d681SAndroid Build Coastguard Worker }
69*9880d681SAndroid Build Coastguard Worker 
70*9880d681SAndroid Build Coastguard Worker /// Returns true if the local user-space stack pointer needs to be written back
71*9880d681SAndroid Build Coastguard Worker /// to memory by this function (this is not meaningful if needsSP is false). If
72*9880d681SAndroid Build Coastguard Worker /// false, the stack red zone can be used and only a local SP is needed.
needsSPWriteback(const MachineFunction & MF,const MachineFrameInfo & MFI) const73*9880d681SAndroid Build Coastguard Worker bool WebAssemblyFrameLowering::needsSPWriteback(
74*9880d681SAndroid Build Coastguard Worker     const MachineFunction &MF, const MachineFrameInfo &MFI) const {
75*9880d681SAndroid Build Coastguard Worker   assert(needsSP(MF, MFI));
76*9880d681SAndroid Build Coastguard Worker   return MFI.getStackSize() > RedZoneSize || MFI.hasCalls() ||
77*9880d681SAndroid Build Coastguard Worker          MF.getFunction()->hasFnAttribute(Attribute::NoRedZone);
78*9880d681SAndroid Build Coastguard Worker }
79*9880d681SAndroid Build Coastguard Worker 
writeSPToMemory(unsigned SrcReg,MachineFunction & MF,MachineBasicBlock & MBB,MachineBasicBlock::iterator & InsertAddr,MachineBasicBlock::iterator & InsertStore,const DebugLoc & DL)80*9880d681SAndroid Build Coastguard Worker static void writeSPToMemory(unsigned SrcReg, MachineFunction &MF,
81*9880d681SAndroid Build Coastguard Worker                             MachineBasicBlock &MBB,
82*9880d681SAndroid Build Coastguard Worker                             MachineBasicBlock::iterator &InsertAddr,
83*9880d681SAndroid Build Coastguard Worker                             MachineBasicBlock::iterator &InsertStore,
84*9880d681SAndroid Build Coastguard Worker                             const DebugLoc &DL) {
85*9880d681SAndroid Build Coastguard Worker   const char *ES = "__stack_pointer";
86*9880d681SAndroid Build Coastguard Worker   auto *SPSymbol = MF.createExternalSymbolName(ES);
87*9880d681SAndroid Build Coastguard Worker   MachineRegisterInfo &MRI = MF.getRegInfo();
88*9880d681SAndroid Build Coastguard Worker   const TargetRegisterClass *PtrRC =
89*9880d681SAndroid Build Coastguard Worker       MRI.getTargetRegisterInfo()->getPointerRegClass(MF);
90*9880d681SAndroid Build Coastguard Worker   unsigned Zero = MRI.createVirtualRegister(PtrRC);
91*9880d681SAndroid Build Coastguard Worker   unsigned Drop = MRI.createVirtualRegister(PtrRC);
92*9880d681SAndroid Build Coastguard Worker   const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
93*9880d681SAndroid Build Coastguard Worker 
94*9880d681SAndroid Build Coastguard Worker   BuildMI(MBB, InsertAddr, DL, TII->get(WebAssembly::CONST_I32), Zero)
95*9880d681SAndroid Build Coastguard Worker       .addImm(0);
96*9880d681SAndroid Build Coastguard Worker   auto *MMO = new MachineMemOperand(MachinePointerInfo(MF.getPSVManager()
97*9880d681SAndroid Build Coastguard Worker                                         .getExternalSymbolCallEntry(ES)),
98*9880d681SAndroid Build Coastguard Worker                                     MachineMemOperand::MOStore, 4, 4);
99*9880d681SAndroid Build Coastguard Worker   BuildMI(MBB, InsertStore, DL, TII->get(WebAssembly::STORE_I32), Drop)
100*9880d681SAndroid Build Coastguard Worker       .addExternalSymbol(SPSymbol)
101*9880d681SAndroid Build Coastguard Worker       .addReg(Zero)
102*9880d681SAndroid Build Coastguard Worker       .addImm(2)  // p2align
103*9880d681SAndroid Build Coastguard Worker       .addReg(SrcReg)
104*9880d681SAndroid Build Coastguard Worker       .addMemOperand(MMO);
105*9880d681SAndroid Build Coastguard Worker }
106*9880d681SAndroid Build Coastguard Worker 
107*9880d681SAndroid Build Coastguard Worker MachineBasicBlock::iterator
eliminateCallFramePseudoInstr(MachineFunction & MF,MachineBasicBlock & MBB,MachineBasicBlock::iterator I) const108*9880d681SAndroid Build Coastguard Worker WebAssemblyFrameLowering::eliminateCallFramePseudoInstr(
109*9880d681SAndroid Build Coastguard Worker     MachineFunction &MF, MachineBasicBlock &MBB,
110*9880d681SAndroid Build Coastguard Worker     MachineBasicBlock::iterator I) const {
111*9880d681SAndroid Build Coastguard Worker   assert(!I->getOperand(0).getImm() && hasFP(MF) &&
112*9880d681SAndroid Build Coastguard Worker          "Call frame pseudos should only be used for dynamic stack adjustment");
113*9880d681SAndroid Build Coastguard Worker   const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
114*9880d681SAndroid Build Coastguard Worker   if (I->getOpcode() == TII->getCallFrameDestroyOpcode() &&
115*9880d681SAndroid Build Coastguard Worker       needsSPWriteback(MF, *MF.getFrameInfo())) {
116*9880d681SAndroid Build Coastguard Worker     DebugLoc DL = I->getDebugLoc();
117*9880d681SAndroid Build Coastguard Worker     writeSPToMemory(WebAssembly::SP32, MF, MBB, I, I, DL);
118*9880d681SAndroid Build Coastguard Worker   }
119*9880d681SAndroid Build Coastguard Worker   return MBB.erase(I);
120*9880d681SAndroid Build Coastguard Worker }
121*9880d681SAndroid Build Coastguard Worker 
emitPrologue(MachineFunction & MF,MachineBasicBlock & MBB) const122*9880d681SAndroid Build Coastguard Worker void WebAssemblyFrameLowering::emitPrologue(MachineFunction &MF,
123*9880d681SAndroid Build Coastguard Worker                                             MachineBasicBlock &MBB) const {
124*9880d681SAndroid Build Coastguard Worker   // TODO: Do ".setMIFlag(MachineInstr::FrameSetup)" on emitted instructions
125*9880d681SAndroid Build Coastguard Worker   auto *MFI = MF.getFrameInfo();
126*9880d681SAndroid Build Coastguard Worker   assert(MFI->getCalleeSavedInfo().empty() &&
127*9880d681SAndroid Build Coastguard Worker          "WebAssembly should not have callee-saved registers");
128*9880d681SAndroid Build Coastguard Worker 
129*9880d681SAndroid Build Coastguard Worker   if (!needsSP(MF, *MFI)) return;
130*9880d681SAndroid Build Coastguard Worker   uint64_t StackSize = MFI->getStackSize();
131*9880d681SAndroid Build Coastguard Worker 
132*9880d681SAndroid Build Coastguard Worker   const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
133*9880d681SAndroid Build Coastguard Worker   auto &MRI = MF.getRegInfo();
134*9880d681SAndroid Build Coastguard Worker 
135*9880d681SAndroid Build Coastguard Worker   auto InsertPt = MBB.begin();
136*9880d681SAndroid Build Coastguard Worker   DebugLoc DL;
137*9880d681SAndroid Build Coastguard Worker 
138*9880d681SAndroid Build Coastguard Worker   const TargetRegisterClass *PtrRC =
139*9880d681SAndroid Build Coastguard Worker       MRI.getTargetRegisterInfo()->getPointerRegClass(MF);
140*9880d681SAndroid Build Coastguard Worker   unsigned Zero = MRI.createVirtualRegister(PtrRC);
141*9880d681SAndroid Build Coastguard Worker   unsigned SPReg = MRI.createVirtualRegister(PtrRC);
142*9880d681SAndroid Build Coastguard Worker   const char *ES = "__stack_pointer";
143*9880d681SAndroid Build Coastguard Worker   auto *SPSymbol = MF.createExternalSymbolName(ES);
144*9880d681SAndroid Build Coastguard Worker   BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), Zero)
145*9880d681SAndroid Build Coastguard Worker       .addImm(0);
146*9880d681SAndroid Build Coastguard Worker   auto *LoadMMO = new MachineMemOperand(MachinePointerInfo(MF.getPSVManager()
147*9880d681SAndroid Build Coastguard Worker                                             .getExternalSymbolCallEntry(ES)),
148*9880d681SAndroid Build Coastguard Worker                                         MachineMemOperand::MOLoad, 4, 4);
149*9880d681SAndroid Build Coastguard Worker   // Load the SP value.
150*9880d681SAndroid Build Coastguard Worker   BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::LOAD_I32),
151*9880d681SAndroid Build Coastguard Worker           StackSize ? SPReg : (unsigned)WebAssembly::SP32)
152*9880d681SAndroid Build Coastguard Worker       .addExternalSymbol(SPSymbol)
153*9880d681SAndroid Build Coastguard Worker       .addReg(Zero)    // addr
154*9880d681SAndroid Build Coastguard Worker       .addImm(2)       // p2align
155*9880d681SAndroid Build Coastguard Worker       .addMemOperand(LoadMMO);
156*9880d681SAndroid Build Coastguard Worker 
157*9880d681SAndroid Build Coastguard Worker   if (StackSize) {
158*9880d681SAndroid Build Coastguard Worker     // Subtract the frame size
159*9880d681SAndroid Build Coastguard Worker     unsigned OffsetReg = MRI.createVirtualRegister(PtrRC);
160*9880d681SAndroid Build Coastguard Worker     BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), OffsetReg)
161*9880d681SAndroid Build Coastguard Worker         .addImm(StackSize);
162*9880d681SAndroid Build Coastguard Worker     BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::SUB_I32),
163*9880d681SAndroid Build Coastguard Worker             WebAssembly::SP32)
164*9880d681SAndroid Build Coastguard Worker         .addReg(SPReg)
165*9880d681SAndroid Build Coastguard Worker         .addReg(OffsetReg);
166*9880d681SAndroid Build Coastguard Worker   }
167*9880d681SAndroid Build Coastguard Worker   if (hasFP(MF)) {
168*9880d681SAndroid Build Coastguard Worker     // Unlike most conventional targets (where FP points to the saved FP),
169*9880d681SAndroid Build Coastguard Worker     // FP points to the bottom of the fixed-size locals, so we can use positive
170*9880d681SAndroid Build Coastguard Worker     // offsets in load/store instructions.
171*9880d681SAndroid Build Coastguard Worker     BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::COPY),
172*9880d681SAndroid Build Coastguard Worker             WebAssembly::FP32)
173*9880d681SAndroid Build Coastguard Worker         .addReg(WebAssembly::SP32);
174*9880d681SAndroid Build Coastguard Worker   }
175*9880d681SAndroid Build Coastguard Worker   if (StackSize && needsSPWriteback(MF, *MFI)) {
176*9880d681SAndroid Build Coastguard Worker     writeSPToMemory(WebAssembly::SP32, MF, MBB, InsertPt, InsertPt, DL);
177*9880d681SAndroid Build Coastguard Worker   }
178*9880d681SAndroid Build Coastguard Worker }
179*9880d681SAndroid Build Coastguard Worker 
emitEpilogue(MachineFunction & MF,MachineBasicBlock & MBB) const180*9880d681SAndroid Build Coastguard Worker void WebAssemblyFrameLowering::emitEpilogue(MachineFunction &MF,
181*9880d681SAndroid Build Coastguard Worker                                             MachineBasicBlock &MBB) const {
182*9880d681SAndroid Build Coastguard Worker   auto *MFI = MF.getFrameInfo();
183*9880d681SAndroid Build Coastguard Worker   uint64_t StackSize = MFI->getStackSize();
184*9880d681SAndroid Build Coastguard Worker   if (!needsSP(MF, *MFI) || !needsSPWriteback(MF, *MFI)) return;
185*9880d681SAndroid Build Coastguard Worker   const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
186*9880d681SAndroid Build Coastguard Worker   auto &MRI = MF.getRegInfo();
187*9880d681SAndroid Build Coastguard Worker   auto InsertPt = MBB.getFirstTerminator();
188*9880d681SAndroid Build Coastguard Worker   DebugLoc DL;
189*9880d681SAndroid Build Coastguard Worker 
190*9880d681SAndroid Build Coastguard Worker   if (InsertPt != MBB.end())
191*9880d681SAndroid Build Coastguard Worker     DL = InsertPt->getDebugLoc();
192*9880d681SAndroid Build Coastguard Worker 
193*9880d681SAndroid Build Coastguard Worker   // Restore the stack pointer. If we had fixed-size locals, add the offset
194*9880d681SAndroid Build Coastguard Worker   // subtracted in the prolog.
195*9880d681SAndroid Build Coastguard Worker   unsigned SPReg = 0;
196*9880d681SAndroid Build Coastguard Worker   MachineBasicBlock::iterator InsertAddr = InsertPt;
197*9880d681SAndroid Build Coastguard Worker   if (StackSize) {
198*9880d681SAndroid Build Coastguard Worker     const TargetRegisterClass *PtrRC =
199*9880d681SAndroid Build Coastguard Worker         MRI.getTargetRegisterInfo()->getPointerRegClass(MF);
200*9880d681SAndroid Build Coastguard Worker     unsigned OffsetReg = MRI.createVirtualRegister(PtrRC);
201*9880d681SAndroid Build Coastguard Worker     InsertAddr =
202*9880d681SAndroid Build Coastguard Worker         BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), OffsetReg)
203*9880d681SAndroid Build Coastguard Worker             .addImm(StackSize);
204*9880d681SAndroid Build Coastguard Worker     // In the epilog we don't need to write the result back to the SP32 physreg
205*9880d681SAndroid Build Coastguard Worker     // because it won't be used again. We can use a stackified register instead.
206*9880d681SAndroid Build Coastguard Worker     SPReg = MRI.createVirtualRegister(PtrRC);
207*9880d681SAndroid Build Coastguard Worker     BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::ADD_I32), SPReg)
208*9880d681SAndroid Build Coastguard Worker         .addReg(hasFP(MF) ? WebAssembly::FP32 : WebAssembly::SP32)
209*9880d681SAndroid Build Coastguard Worker         .addReg(OffsetReg);
210*9880d681SAndroid Build Coastguard Worker   } else {
211*9880d681SAndroid Build Coastguard Worker     SPReg = hasFP(MF) ? WebAssembly::FP32 : WebAssembly::SP32;
212*9880d681SAndroid Build Coastguard Worker   }
213*9880d681SAndroid Build Coastguard Worker 
214*9880d681SAndroid Build Coastguard Worker   writeSPToMemory(SPReg, MF, MBB, InsertAddr, InsertPt, DL);
215*9880d681SAndroid Build Coastguard Worker }
216