blob: 0e0cac4ee689b57fc6b19a6866ab769805545aca [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
Derek Schuff9769deb2015-12-11 23:49:46 +000039// TODO: Emit TargetOpcode::CFI_INSTRUCTION instructions
Dan Gohman10e730a2015-06-29 23:51:55 +000040
41/// Return true if the specified function should have a dedicated frame pointer
42/// register.
43bool WebAssemblyFrameLowering::hasFP(const MachineFunction &MF) const {
JF Bastienb9073fb2015-07-22 21:28:15 +000044 const MachineFrameInfo *MFI = MF.getFrameInfo();
Dan Gohmane419a7c2015-08-24 16:46:31 +000045 const auto *RegInfo =
46 MF.getSubtarget<WebAssemblySubtarget>().getRegisterInfo();
Dan Gohman94c65662016-02-16 23:48:04 +000047 return MFI->isFrameAddressTaken() || MFI->hasVarSizedObjects() ||
48 MFI->hasStackMap() || MFI->hasPatchPoint() ||
49 RegInfo->needsStackRealignment(MF);
Dan Gohman10e730a2015-06-29 23:51:55 +000050}
51
52/// Under normal circumstances, when a frame pointer is not required, we reserve
53/// argument space for call sites in the function immediately on entry to the
54/// current function. This eliminates the need for add/sub sp brackets around
55/// call sites. Returns true if the call frame is included as part of the stack
56/// frame.
57bool WebAssemblyFrameLowering::hasReservedCallFrame(
58 const MachineFunction &MF) const {
59 return !MF.getFrameInfo()->hasVarSizedObjects();
60}
61
Derek Schuff8bb5f292015-12-16 23:21:30 +000062void WebAssemblyFrameLowering::eliminateCallFramePseudoInstr(
63 MachineFunction &MF, MachineBasicBlock &MBB,
64 MachineBasicBlock::iterator I) const {
Derek Schuff27501e22016-02-10 19:51:04 +000065 // TODO: can we avoid using call frame pseudos altogether?
66 assert(!I->getOperand(0).getImm() &&
67 "Stack should not be adjusted around calls");
Derek Schuff8bb5f292015-12-16 23:21:30 +000068 MBB.erase(I);
69}
70
71void WebAssemblyFrameLowering::emitPrologue(MachineFunction &MF,
72 MachineBasicBlock &MBB) const {
73 // TODO: Do ".setMIFlag(MachineInstr::FrameSetup)" on emitted instructions
74 auto *MFI = MF.getFrameInfo();
75 assert(MFI->getCalleeSavedInfo().empty() &&
76 "WebAssembly should not have callee-saved registers");
Derek Schuffdc5f6aa2016-02-20 21:46:50 +000077 auto *WFI = MF.getInfo<WebAssemblyFunctionInfo>();
Derek Schuff6ea637a2016-01-29 18:37:49 +000078
Derek Schuff8bb5f292015-12-16 23:21:30 +000079 uint64_t StackSize = MFI->getStackSize();
Derek Schuff27501e22016-02-10 19:51:04 +000080 if (!StackSize && !MFI->adjustsStack() && !hasFP(MF)) return;
Derek Schuff8bb5f292015-12-16 23:21:30 +000081
Dan Gohman31966502016-01-19 14:53:19 +000082 const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
Derek Schuff6ea637a2016-01-29 18:37:49 +000083 auto &MRI = MF.getRegInfo();
Derek Schuff8bb5f292015-12-16 23:21:30 +000084
85 auto InsertPt = MBB.begin();
86 DebugLoc DL;
87
Derek Schuffdc5f6aa2016-02-20 21:46:50 +000088 unsigned SPAddr = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
Derek Schuff6ea637a2016-01-29 18:37:49 +000089 unsigned SPReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
90 auto *SPSymbol = MF.createExternalSymbolName("__stack_pointer");
Derek Schuffdc5f6aa2016-02-20 21:46:50 +000091 BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), SPAddr)
Derek Schuff6ea637a2016-01-29 18:37:49 +000092 .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 Schuffdc5f6aa2016-02-20 21:46:50 +0000102 .addImm(0) // offset
103 .addReg(SPAddr) // addr
104 .addImm(2) // p2align
Derek Schuff6ea637a2016-01-29 18:37:49 +0000105 .addMemOperand(LoadMMO);
Derek Schuffdc5f6aa2016-02-20 21:46:50 +0000106 WFI->stackifyVReg(SPAddr);
Derek Schuff6ea637a2016-01-29 18:37:49 +0000107
Derek Schuff6ea637a2016-01-29 18:37:49 +0000108 if (StackSize) {
109 // Subtract the frame size
Derek Schuffdc5f6aa2016-02-20 21:46:50 +0000110 unsigned OffsetReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
Derek Schuff6ea637a2016-01-29 18:37:49 +0000111 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);
Derek Schuffdc5f6aa2016-02-20 21:46:50 +0000117 WFI->stackifyVReg(OffsetReg);
118 WFI->stackifyVReg(SPReg);
Derek Schuff6ea637a2016-01-29 18:37:49 +0000119 }
120 if (hasFP(MF)) {
121 // Unlike most conventional targets (where FP points to the saved FP),
122 // FP points to the bottom of the fixed-size locals, so we can use positive
123 // offsets in load/store instructions.
124 BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::COPY_LOCAL_I32),
125 WebAssembly::FP32)
126 .addReg(WebAssembly::SP32);
127 }
128 if (StackSize) {
Derek Schuffdc5f6aa2016-02-20 21:46:50 +0000129 SPAddr = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
Derek Schuff3f063292016-02-11 20:57:09 +0000130 // The SP32 register now has the new stacktop. Also write it back to memory.
Derek Schuffdc5f6aa2016-02-20 21:46:50 +0000131 BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), SPAddr)
Derek Schuff3f063292016-02-11 20:57:09 +0000132 .addExternalSymbol(SPSymbol);
133 auto *MMO = new MachineMemOperand(MachinePointerInfo(),
134 MachineMemOperand::MOStore, 4, 4);
135 BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::STORE_I32),
136 WebAssembly::SP32)
137 .addImm(0)
Derek Schuffdc5f6aa2016-02-20 21:46:50 +0000138 .addReg(SPAddr)
Derek Schuff3f063292016-02-11 20:57:09 +0000139 .addImm(2) // p2align
140 .addReg(WebAssembly::SP32)
141 .addMemOperand(MMO);
Derek Schuffdc5f6aa2016-02-20 21:46:50 +0000142 WFI->stackifyVReg(SPAddr);
Derek Schuff6ea637a2016-01-29 18:37:49 +0000143 }
Derek Schuff8bb5f292015-12-16 23:21:30 +0000144}
145
Derek Schuff9769deb2015-12-11 23:49:46 +0000146void WebAssemblyFrameLowering::emitEpilogue(MachineFunction &MF,
147 MachineBasicBlock &MBB) const {
Derek Schuff6ea637a2016-01-29 18:37:49 +0000148 auto *MFI = MF.getFrameInfo();
149 uint64_t StackSize = MFI->getStackSize();
Derek Schuff27501e22016-02-10 19:51:04 +0000150 if (!StackSize && !MFI->adjustsStack() && !hasFP(MF)) return;
Derek Schuffdc5f6aa2016-02-20 21:46:50 +0000151 auto *WFI = MF.getInfo<WebAssemblyFunctionInfo>();
Dan Gohman31966502016-01-19 14:53:19 +0000152 const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
Derek Schuff9769deb2015-12-11 23:49:46 +0000153 auto &MRI = MF.getRegInfo();
Derek Schuff9769deb2015-12-11 23:49:46 +0000154 auto InsertPt = MBB.getFirstTerminator();
155 DebugLoc DL;
156
157 if (InsertPt != MBB.end()) {
158 DL = InsertPt->getDebugLoc();
159 }
160
Derek Schuff6ea637a2016-01-29 18:37:49 +0000161 // Restore the stack pointer. If we had fixed-size locals, add the offset
162 // subtracted in the prolog.
163 if (StackSize) {
Derek Schuffdc5f6aa2016-02-20 21:46:50 +0000164 unsigned OffsetReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
Derek Schuff6ea637a2016-01-29 18:37:49 +0000165 BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), OffsetReg)
166 .addImm(StackSize);
Derek Schuff3f063292016-02-11 20:57:09 +0000167 BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::ADD_I32),
168 WebAssembly::SP32)
Derek Schuff6ea637a2016-01-29 18:37:49 +0000169 .addReg(hasFP(MF) ? WebAssembly::FP32 : WebAssembly::SP32)
170 .addReg(OffsetReg);
Derek Schuffdc5f6aa2016-02-20 21:46:50 +0000171 WFI->stackifyVReg(OffsetReg);
Derek Schuff6ea637a2016-01-29 18:37:49 +0000172 }
173
Derek Schuff9769deb2015-12-11 23:49:46 +0000174 auto *SPSymbol = MF.createExternalSymbolName("__stack_pointer");
Derek Schuffdc5f6aa2016-02-20 21:46:50 +0000175 unsigned SPAddr = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
176 BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), SPAddr)
Derek Schuff9769deb2015-12-11 23:49:46 +0000177 .addExternalSymbol(SPSymbol);
178 auto *MMO = new MachineMemOperand(MachinePointerInfo(),
179 MachineMemOperand::MOStore, 4, 4);
Derek Schuff3f063292016-02-11 20:57:09 +0000180 BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::STORE_I32),
181 WebAssembly::SP32)
Derek Schuff9769deb2015-12-11 23:49:46 +0000182 .addImm(0)
Derek Schuffdc5f6aa2016-02-20 21:46:50 +0000183 .addReg(SPAddr)
Derek Schuff3f063292016-02-11 20:57:09 +0000184 .addImm(2) // p2align
Derek Schuff6ea637a2016-01-29 18:37:49 +0000185 .addReg((!StackSize && hasFP(MF)) ? WebAssembly::FP32 : WebAssembly::SP32)
Derek Schuff9769deb2015-12-11 23:49:46 +0000186 .addMemOperand(MMO);
Derek Schuffdc5f6aa2016-02-20 21:46:50 +0000187 WFI->stackifyVReg(SPAddr);
Dan Gohman10e730a2015-06-29 23:51:55 +0000188}