blob: 1c358b340bd36f89ca66d6c18cadd9238fa0ff27 [file] [log] [blame]
Dan Gohman10e730a2015-06-29 23:51:55 +00001//===-- WebAssemblyFrameLowering.cpp - WebAssembly Frame Lowering ----------==//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9///
10/// \file
11/// \brief This file contains the WebAssembly implementation of
12/// TargetFrameLowering class.
13///
14/// On WebAssembly, there aren't a lot of things to do here. There are no
15/// callee-saved registers to save, and no spill slots.
16///
17/// The stack grows downward.
18///
19//===----------------------------------------------------------------------===//
20
21#include "WebAssemblyFrameLowering.h"
22#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
23#include "WebAssemblyInstrInfo.h"
24#include "WebAssemblyMachineFunctionInfo.h"
25#include "WebAssemblySubtarget.h"
26#include "WebAssemblyTargetMachine.h"
27#include "llvm/CodeGen/MachineFrameInfo.h"
28#include "llvm/CodeGen/MachineFunction.h"
29#include "llvm/CodeGen/MachineInstrBuilder.h"
30#include "llvm/CodeGen/MachineModuleInfo.h"
31#include "llvm/CodeGen/MachineRegisterInfo.h"
32#include "llvm/Support/Debug.h"
33using namespace llvm;
34
JF Bastien03855df2015-07-01 23:41:25 +000035#define DEBUG_TYPE "wasm-frame-info"
Dan Gohman10e730a2015-06-29 23:51:55 +000036
37// TODO: Implement a red zone?
Derek Schuff9769deb2015-12-11 23:49:46 +000038// TODO: wasm64
39// TODO: Prolog/epilog should be stackified too. This pass runs after register
40// stackification, so we'll have to do it manually.
41// TODO: Emit TargetOpcode::CFI_INSTRUCTION instructions
Dan Gohman10e730a2015-06-29 23:51:55 +000042
43/// Return true if the specified function should have a dedicated frame pointer
44/// register.
45bool WebAssemblyFrameLowering::hasFP(const MachineFunction &MF) const {
JF Bastienb9073fb2015-07-22 21:28:15 +000046 const MachineFrameInfo *MFI = MF.getFrameInfo();
Dan Gohmane419a7c2015-08-24 16:46:31 +000047 const auto *RegInfo =
48 MF.getSubtarget<WebAssemblySubtarget>().getRegisterInfo();
Dan Gohman94c65662016-02-16 23:48:04 +000049 return MFI->isFrameAddressTaken() || MFI->hasVarSizedObjects() ||
50 MFI->hasStackMap() || MFI->hasPatchPoint() ||
51 RegInfo->needsStackRealignment(MF);
Dan Gohman10e730a2015-06-29 23:51:55 +000052}
53
54/// Under normal circumstances, when a frame pointer is not required, we reserve
55/// argument space for call sites in the function immediately on entry to the
56/// current function. This eliminates the need for add/sub sp brackets around
57/// call sites. Returns true if the call frame is included as part of the stack
58/// frame.
59bool WebAssemblyFrameLowering::hasReservedCallFrame(
60 const MachineFunction &MF) const {
61 return !MF.getFrameInfo()->hasVarSizedObjects();
62}
63
Derek Schuff8bb5f292015-12-16 23:21:30 +000064void WebAssemblyFrameLowering::eliminateCallFramePseudoInstr(
65 MachineFunction &MF, MachineBasicBlock &MBB,
66 MachineBasicBlock::iterator I) const {
Derek Schuff27501e22016-02-10 19:51:04 +000067 // TODO: can we avoid using call frame pseudos altogether?
68 assert(!I->getOperand(0).getImm() &&
69 "Stack should not be adjusted around calls");
Derek Schuff8bb5f292015-12-16 23:21:30 +000070 MBB.erase(I);
71}
72
73void WebAssemblyFrameLowering::emitPrologue(MachineFunction &MF,
74 MachineBasicBlock &MBB) const {
75 // TODO: Do ".setMIFlag(MachineInstr::FrameSetup)" on emitted instructions
76 auto *MFI = MF.getFrameInfo();
77 assert(MFI->getCalleeSavedInfo().empty() &&
78 "WebAssembly should not have callee-saved registers");
Derek Schuff6ea637a2016-01-29 18:37:49 +000079
Derek Schuff8bb5f292015-12-16 23:21:30 +000080 uint64_t StackSize = MFI->getStackSize();
Derek Schuff27501e22016-02-10 19:51:04 +000081 if (!StackSize && !MFI->adjustsStack() && !hasFP(MF)) return;
Derek Schuff8bb5f292015-12-16 23:21:30 +000082
Dan Gohman31966502016-01-19 14:53:19 +000083 const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
Derek Schuff6ea637a2016-01-29 18:37:49 +000084 auto &MRI = MF.getRegInfo();
Derek Schuff8bb5f292015-12-16 23:21:30 +000085
86 auto InsertPt = MBB.begin();
87 DebugLoc DL;
88
Derek Schuff6ea637a2016-01-29 18:37:49 +000089 unsigned SPReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
90 auto *SPSymbol = MF.createExternalSymbolName("__stack_pointer");
91 BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), SPReg)
92 .addExternalSymbol(SPSymbol);
93 // This MachinePointerInfo should reference __stack_pointer as well but
94 // doesn't because MachinePointerInfo() takes a GV which we don't have for
95 // __stack_pointer. TODO: check if PseudoSourceValue::ExternalSymbolCallEntry
96 // is appropriate instead. (likewise for EmitEpologue below)
97 auto *LoadMMO = new MachineMemOperand(MachinePointerInfo(),
98 MachineMemOperand::MOLoad, 4, 4);
99 // Load the SP value.
100 BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::LOAD_I32),
JF Bastien3ca3ea62016-01-30 11:19:26 +0000101 StackSize ? SPReg : (unsigned)WebAssembly::SP32)
Derek Schuff3f063292016-02-11 20:57:09 +0000102 .addImm(0) // offset
103 .addReg(SPReg) // addr
104 .addImm(2) // p2align
Derek Schuff6ea637a2016-01-29 18:37:49 +0000105 .addMemOperand(LoadMMO);
106
107 unsigned OffsetReg = 0;
108 if (StackSize) {
109 // Subtract the frame size
110 OffsetReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
111 BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), OffsetReg)
112 .addImm(StackSize);
Derek Schuff3f063292016-02-11 20:57:09 +0000113 BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::SUB_I32),
Derek Schuff6ea637a2016-01-29 18:37:49 +0000114 WebAssembly::SP32)
115 .addReg(SPReg)
116 .addReg(OffsetReg);
117 }
118 if (hasFP(MF)) {
119 // Unlike most conventional targets (where FP points to the saved FP),
120 // FP points to the bottom of the fixed-size locals, so we can use positive
121 // offsets in load/store instructions.
122 BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::COPY_LOCAL_I32),
123 WebAssembly::FP32)
124 .addReg(WebAssembly::SP32);
125 }
126 if (StackSize) {
127 assert(OffsetReg);
Derek Schuff3f063292016-02-11 20:57:09 +0000128 // The SP32 register now has the new stacktop. Also write it back to memory.
129 BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), OffsetReg)
130 .addExternalSymbol(SPSymbol);
131 auto *MMO = new MachineMemOperand(MachinePointerInfo(),
132 MachineMemOperand::MOStore, 4, 4);
133 BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::STORE_I32),
134 WebAssembly::SP32)
135 .addImm(0)
136 .addReg(OffsetReg)
137 .addImm(2) // p2align
138 .addReg(WebAssembly::SP32)
139 .addMemOperand(MMO);
Derek Schuff6ea637a2016-01-29 18:37:49 +0000140 }
Derek Schuff8bb5f292015-12-16 23:21:30 +0000141}
142
Derek Schuff9769deb2015-12-11 23:49:46 +0000143void WebAssemblyFrameLowering::emitEpilogue(MachineFunction &MF,
144 MachineBasicBlock &MBB) const {
Derek Schuff6ea637a2016-01-29 18:37:49 +0000145 auto *MFI = MF.getFrameInfo();
146 uint64_t StackSize = MFI->getStackSize();
Derek Schuff27501e22016-02-10 19:51:04 +0000147 if (!StackSize && !MFI->adjustsStack() && !hasFP(MF)) return;
Dan Gohman31966502016-01-19 14:53:19 +0000148 const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
Derek Schuff9769deb2015-12-11 23:49:46 +0000149 auto &MRI = MF.getRegInfo();
150 unsigned OffsetReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
151 auto InsertPt = MBB.getFirstTerminator();
152 DebugLoc DL;
153
154 if (InsertPt != MBB.end()) {
155 DL = InsertPt->getDebugLoc();
156 }
157
Derek Schuff6ea637a2016-01-29 18:37:49 +0000158 // Restore the stack pointer. If we had fixed-size locals, add the offset
159 // subtracted in the prolog.
160 if (StackSize) {
161 BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), OffsetReg)
162 .addImm(StackSize);
Derek Schuff3f063292016-02-11 20:57:09 +0000163 BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::ADD_I32),
164 WebAssembly::SP32)
Derek Schuff6ea637a2016-01-29 18:37:49 +0000165 .addReg(hasFP(MF) ? WebAssembly::FP32 : WebAssembly::SP32)
166 .addReg(OffsetReg);
167 }
168
Derek Schuff9769deb2015-12-11 23:49:46 +0000169 auto *SPSymbol = MF.createExternalSymbolName("__stack_pointer");
Derek Schuff9769deb2015-12-11 23:49:46 +0000170 // Re-use OffsetReg to hold the address of the stacktop
171 BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), OffsetReg)
172 .addExternalSymbol(SPSymbol);
173 auto *MMO = new MachineMemOperand(MachinePointerInfo(),
174 MachineMemOperand::MOStore, 4, 4);
Derek Schuff3f063292016-02-11 20:57:09 +0000175 BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::STORE_I32),
176 WebAssembly::SP32)
Derek Schuff9769deb2015-12-11 23:49:46 +0000177 .addImm(0)
178 .addReg(OffsetReg)
Derek Schuff3f063292016-02-11 20:57:09 +0000179 .addImm(2) // p2align
Derek Schuff6ea637a2016-01-29 18:37:49 +0000180 .addReg((!StackSize && hasFP(MF)) ? WebAssembly::FP32 : WebAssembly::SP32)
Derek Schuff9769deb2015-12-11 23:49:46 +0000181 .addMemOperand(MMO);
Dan Gohman10e730a2015-06-29 23:51:55 +0000182}