blob: c6c473cb3a20603407a457e3faa9c1248f33ae19 [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();
Derek Schuff27501e22016-02-10 19:51:04 +000049 return MFI->hasVarSizedObjects() || MFI->hasStackMap() ||
50 MFI->hasPatchPoint() || RegInfo->needsStackRealignment(MF);
Dan Gohman10e730a2015-06-29 23:51:55 +000051}
52
53/// Under normal circumstances, when a frame pointer is not required, we reserve
54/// argument space for call sites in the function immediately on entry to the
55/// current function. This eliminates the need for add/sub sp brackets around
56/// call sites. Returns true if the call frame is included as part of the stack
57/// frame.
58bool WebAssemblyFrameLowering::hasReservedCallFrame(
59 const MachineFunction &MF) const {
60 return !MF.getFrameInfo()->hasVarSizedObjects();
61}
62
Derek Schuff8bb5f292015-12-16 23:21:30 +000063void WebAssemblyFrameLowering::eliminateCallFramePseudoInstr(
64 MachineFunction &MF, MachineBasicBlock &MBB,
65 MachineBasicBlock::iterator I) const {
Derek Schuff27501e22016-02-10 19:51:04 +000066 // TODO: can we avoid using call frame pseudos altogether?
67 assert(!I->getOperand(0).getImm() &&
68 "Stack should not be adjusted around calls");
Derek Schuff8bb5f292015-12-16 23:21:30 +000069 MBB.erase(I);
70}
71
72void WebAssemblyFrameLowering::emitPrologue(MachineFunction &MF,
73 MachineBasicBlock &MBB) const {
74 // TODO: Do ".setMIFlag(MachineInstr::FrameSetup)" on emitted instructions
75 auto *MFI = MF.getFrameInfo();
76 assert(MFI->getCalleeSavedInfo().empty() &&
77 "WebAssembly should not have callee-saved registers");
Derek Schuff27501e22016-02-10 19:51:04 +000078 assert(!MFI->isFrameAddressTaken());
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)
102 .addImm(0) // offset
Derek Schuff6ea637a2016-01-29 18:37:49 +0000103 .addReg(SPReg) // addr
JF Bastien3ca3ea62016-01-30 11:19:26 +0000104 .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);
113 BuildMI(MBB, InsertPt, DL,
114 TII->get(WebAssembly::SUB_I32),
115 WebAssembly::SP32)
116 .addReg(SPReg)
117 .addReg(OffsetReg);
118 }
119 if (hasFP(MF)) {
120 // Unlike most conventional targets (where FP points to the saved FP),
121 // FP points to the bottom of the fixed-size locals, so we can use positive
122 // offsets in load/store instructions.
123 BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::COPY_LOCAL_I32),
124 WebAssembly::FP32)
125 .addReg(WebAssembly::SP32);
126 }
127 if (StackSize) {
128 assert(OffsetReg);
129 // The SP32 register now has the new stacktop. Also write it back to memory.
130 BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), OffsetReg)
131 .addExternalSymbol(SPSymbol);
132 auto *MMO = new MachineMemOperand(MachinePointerInfo(),
133 MachineMemOperand::MOStore, 4, 4);
134 BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::STORE_I32), WebAssembly::SP32)
135 .addImm(0)
136 .addReg(OffsetReg)
137 .addImm(2) // p2align
138 .addReg(WebAssembly::SP32)
139 .addMemOperand(MMO);
140 }
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);
163 BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::ADD_I32), WebAssembly::SP32)
164 .addReg(hasFP(MF) ? WebAssembly::FP32 : WebAssembly::SP32)
165 .addReg(OffsetReg);
166 }
167
Derek Schuff9769deb2015-12-11 23:49:46 +0000168 auto *SPSymbol = MF.createExternalSymbolName("__stack_pointer");
Derek Schuff9769deb2015-12-11 23:49:46 +0000169 // Re-use OffsetReg to hold the address of the stacktop
170 BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), OffsetReg)
171 .addExternalSymbol(SPSymbol);
172 auto *MMO = new MachineMemOperand(MachinePointerInfo(),
173 MachineMemOperand::MOStore, 4, 4);
174 BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::STORE_I32), WebAssembly::SP32)
175 .addImm(0)
176 .addReg(OffsetReg)
Dan Gohmanbb372242016-01-26 03:39:31 +0000177 .addImm(2) // p2align
Derek Schuff6ea637a2016-01-29 18:37:49 +0000178 .addReg((!StackSize && hasFP(MF)) ? WebAssembly::FP32 : WebAssembly::SP32)
Derek Schuff9769deb2015-12-11 23:49:46 +0000179 .addMemOperand(MMO);
Dan Gohman10e730a2015-06-29 23:51:55 +0000180}