Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp
Line
Count
Source (jump to first uncovered line)
1
//===-- WebAssemblyFrameLowering.cpp - WebAssembly Frame Lowering ----------==//
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
11
/// TargetFrameLowering class.
12
///
13
/// On WebAssembly, there aren't a lot of things to do here. There are no
14
/// callee-saved registers to save, and no spill slots.
15
///
16
/// The stack grows downward.
17
///
18
//===----------------------------------------------------------------------===//
19
20
#include "WebAssemblyFrameLowering.h"
21
#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
22
#include "WebAssemblyInstrInfo.h"
23
#include "WebAssemblyMachineFunctionInfo.h"
24
#include "WebAssemblySubtarget.h"
25
#include "WebAssemblyTargetMachine.h"
26
#include "WebAssemblyUtilities.h"
27
#include "llvm/CodeGen/MachineFrameInfo.h"
28
#include "llvm/CodeGen/MachineFunction.h"
29
#include "llvm/CodeGen/MachineInstrBuilder.h"
30
#include "llvm/CodeGen/MachineModuleInfoImpls.h"
31
#include "llvm/CodeGen/MachineRegisterInfo.h"
32
#include "llvm/MC/MCAsmInfo.h"
33
#include "llvm/Support/Debug.h"
34
using namespace llvm;
35
36
#define DEBUG_TYPE "wasm-frame-info"
37
38
// TODO: wasm64
39
// TODO: Emit TargetOpcode::CFI_INSTRUCTION instructions
40
41
/// We need a base pointer in the case of having items on the stack that
42
/// require stricter alignment than the stack pointer itself.  Because we need
43
/// to shift the stack pointer by some unknown amount to force the alignment,
44
/// we need to record the value of the stack pointer on entry to the function.
45
14.4k
bool WebAssemblyFrameLowering::hasBP(const MachineFunction &MF) const {
46
14.4k
  const auto *RegInfo =
47
14.4k
      MF.getSubtarget<WebAssemblySubtarget>().getRegisterInfo();
48
14.4k
  return RegInfo->needsStackRealignment(MF);
49
14.4k
}
50
51
/// Return true if the specified function should have a dedicated frame pointer
52
/// register.
53
14.1k
bool WebAssemblyFrameLowering::hasFP(const MachineFunction &MF) const {
54
14.1k
  const MachineFrameInfo &MFI = MF.getFrameInfo();
55
14.1k
56
14.1k
  // When we have var-sized objects, we move the stack pointer by an unknown
57
14.1k
  // amount, and need to emit a frame pointer to restore the stack to where we
58
14.1k
  // were on function entry.
59
14.1k
  // If we already need a base pointer, we use that to fix up the stack pointer.
60
14.1k
  // If there are no fixed-size objects, we would have no use of a frame
61
14.1k
  // pointer, and thus should not emit one.
62
14.1k
  bool HasFixedSizedObjects = MFI.getStackSize() > 0;
63
14.1k
  bool NeedsFixedReference = !hasBP(MF) || 
HasFixedSizedObjects22
;
64
14.1k
65
14.1k
  return MFI.isFrameAddressTaken() ||
66
14.1k
         
(14.1k
MFI.hasVarSizedObjects()14.1k
&&
NeedsFixedReference44
) ||
67
14.1k
         
MFI.hasStackMap()14.1k
||
MFI.hasPatchPoint()14.1k
;
68
14.1k
}
69
70
/// Under normal circumstances, when a frame pointer is not required, we reserve
71
/// argument space for call sites in the function immediately on entry to the
72
/// current function. This eliminates the need for add/sub sp brackets around
73
/// call sites. Returns true if the call frame is included as part of the stack
74
/// frame.
75
bool WebAssemblyFrameLowering::hasReservedCallFrame(
76
26
    const MachineFunction &MF) const {
77
26
  return !MF.getFrameInfo().hasVarSizedObjects();
78
26
}
79
80
// Returns true if this function needs a local user-space stack pointer for its
81
// local frame (not for exception handling).
82
bool WebAssemblyFrameLowering::needsSPForLocalFrame(
83
9.26k
    const MachineFunction &MF) const {
84
9.26k
  auto &MFI = MF.getFrameInfo();
85
9.26k
  return MFI.getStackSize() || 
MFI.adjustsStack()8.61k
||
hasFP(MF)8.59k
;
86
9.26k
}
87
88
// In function with EH pads, we need to make a copy of the value of
89
// __stack_pointer global in SP32 register, in order to use it when restoring
90
// __stack_pointer after an exception is caught.
91
bool WebAssemblyFrameLowering::needsPrologForEH(
92
8.59k
    const MachineFunction &MF) const {
93
8.59k
  auto EHType = MF.getTarget().getMCAsmInfo()->getExceptionHandlingType();
94
8.59k
  return EHType == ExceptionHandling::Wasm &&
95
8.59k
         
MF.getFunction().hasPersonalityFn()126
&&
MF.getFrameInfo().hasCalls()116
;
96
8.59k
}
97
98
/// Returns true if this function needs a local user-space stack pointer.
99
/// Unlike a machine stack pointer, the wasm user stack pointer is a global
100
/// variable, so it is loaded into a register in the prolog.
101
8.88k
bool WebAssemblyFrameLowering::needsSP(const MachineFunction &MF) const {
102
8.88k
  return needsSPForLocalFrame(MF) || 
needsPrologForEH(MF)8.54k
;
103
8.88k
}
104
105
/// Returns true if the local user-space stack pointer needs to be written back
106
/// to __stack_pointer global by this function (this is not meaningful if
107
/// needsSP is false). If false, the stack red zone can be used and only a local
108
/// SP is needed.
109
bool WebAssemblyFrameLowering::needsSPWriteback(
110
378
    const MachineFunction &MF) const {
111
378
  auto &MFI = MF.getFrameInfo();
112
378
  assert(needsSP(MF));
113
378
  // When we don't need a local stack pointer for its local frame but only to
114
378
  // support EH, we don't need to write SP back in the epilog, because we don't
115
378
  // bump down the stack pointer in the prolog. We need to write SP back in the
116
378
  // epilog only if
117
378
  // 1. We need SP not only for EH support but also because we actually use
118
378
  // stack or we have a frame address taken.
119
378
  // 2. We cannot use the red zone.
120
378
  bool CanUseRedZone = MFI.getStackSize() <= RedZoneSize && 
!MFI.hasCalls()365
&&
121
378
                       
!MF.getFunction().hasFnAttribute(Attribute::NoRedZone)188
;
122
378
  return needsSPForLocalFrame(MF) && 
!CanUseRedZone341
;
123
378
}
124
125
void WebAssemblyFrameLowering::writeSPToGlobal(
126
    unsigned SrcReg, MachineFunction &MF, MachineBasicBlock &MBB,
127
233
    MachineBasicBlock::iterator &InsertStore, const DebugLoc &DL) const {
128
233
  const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
129
233
130
233
  const char *ES = "__stack_pointer";
131
233
  auto *SPSymbol = MF.createExternalSymbolName(ES);
132
233
  BuildMI(MBB, InsertStore, DL, TII->get(WebAssembly::GLOBAL_SET_I32))
133
233
      .addExternalSymbol(SPSymbol)
134
233
      .addReg(SrcReg);
135
233
}
136
137
MachineBasicBlock::iterator
138
WebAssemblyFrameLowering::eliminateCallFramePseudoInstr(
139
    MachineFunction &MF, MachineBasicBlock &MBB,
140
18
    MachineBasicBlock::iterator I) const {
141
18
  assert(!I->getOperand(0).getImm() && (hasFP(MF) || hasBP(MF)) &&
142
18
         "Call frame pseudos should only be used for dynamic stack adjustment");
143
18
  const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
144
18
  if (I->getOpcode() == TII->getCallFrameDestroyOpcode() &&
145
18
      
needsSPWriteback(MF)9
) {
146
8
    DebugLoc DL = I->getDebugLoc();
147
8
    writeSPToGlobal(WebAssembly::SP32, MF, MBB, I, DL);
148
8
  }
149
18
  return MBB.erase(I);
150
18
}
151
152
void WebAssemblyFrameLowering::emitPrologue(MachineFunction &MF,
153
4.45k
                                            MachineBasicBlock &MBB) const {
154
4.45k
  // TODO: Do ".setMIFlag(MachineInstr::FrameSetup)" on emitted instructions
155
4.45k
  auto &MFI = MF.getFrameInfo();
156
4.45k
  assert(MFI.getCalleeSavedInfo().empty() &&
157
4.45k
         "WebAssembly should not have callee-saved registers");
158
4.45k
159
4.45k
  if (!needsSP(MF))
160
4.24k
    return;
161
210
  uint64_t StackSize = MFI.getStackSize();
162
210
163
210
  const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
164
210
  auto &MRI = MF.getRegInfo();
165
210
166
210
  auto InsertPt = MBB.begin();
167
661
  while (InsertPt != MBB.end() &&
168
661
         WebAssembly::isArgument(InsertPt->getOpcode()))
169
451
    ++InsertPt;
170
210
  DebugLoc DL;
171
210
172
210
  const TargetRegisterClass *PtrRC =
173
210
      MRI.getTargetRegisterInfo()->getPointerRegClass(MF);
174
210
  unsigned SPReg = WebAssembly::SP32;
175
210
  if (StackSize)
176
165
    SPReg = MRI.createVirtualRegister(PtrRC);
177
210
178
210
  const char *ES = "__stack_pointer";
179
210
  auto *SPSymbol = MF.createExternalSymbolName(ES);
180
210
  BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::GLOBAL_GET_I32), SPReg)
181
210
      .addExternalSymbol(SPSymbol);
182
210
183
210
  bool HasBP = hasBP(MF);
184
210
  if (HasBP) {
185
5
    auto FI = MF.getInfo<WebAssemblyFunctionInfo>();
186
5
    unsigned BasePtr = MRI.createVirtualRegister(PtrRC);
187
5
    FI->setBasePointerVreg(BasePtr);
188
5
    BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::COPY), BasePtr)
189
5
        .addReg(SPReg);
190
5
  }
191
210
  if (StackSize) {
192
165
    // Subtract the frame size
193
165
    unsigned OffsetReg = MRI.createVirtualRegister(PtrRC);
194
165
    BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), OffsetReg)
195
165
        .addImm(StackSize);
196
165
    BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::SUB_I32),
197
165
            WebAssembly::SP32)
198
165
        .addReg(SPReg)
199
165
        .addReg(OffsetReg);
200
165
  }
201
210
  if (HasBP) {
202
5
    unsigned BitmaskReg = MRI.createVirtualRegister(PtrRC);
203
5
    unsigned Alignment = MFI.getMaxAlignment();
204
5
    assert((1u << countTrailingZeros(Alignment)) == Alignment &&
205
5
           "Alignment must be a power of 2");
206
5
    BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), BitmaskReg)
207
5
        .addImm((int)~(Alignment - 1));
208
5
    BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::AND_I32),
209
5
            WebAssembly::SP32)
210
5
        .addReg(WebAssembly::SP32)
211
5
        .addReg(BitmaskReg);
212
5
  }
213
210
  if (hasFP(MF)) {
214
10
    // Unlike most conventional targets (where FP points to the saved FP),
215
10
    // FP points to the bottom of the fixed-size locals, so we can use positive
216
10
    // offsets in load/store instructions.
217
10
    BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::COPY), WebAssembly::FP32)
218
10
        .addReg(WebAssembly::SP32);
219
10
  }
220
210
  if (StackSize && 
needsSPWriteback(MF)165
) {
221
76
    writeSPToGlobal(WebAssembly::SP32, MF, MBB, InsertPt, DL);
222
76
  }
223
210
}
224
225
void WebAssemblyFrameLowering::emitEpilogue(MachineFunction &MF,
226
4.43k
                                            MachineBasicBlock &MBB) const {
227
4.43k
  uint64_t StackSize = MF.getFrameInfo().getStackSize();
228
4.43k
  if (!needsSP(MF) || 
!needsSPWriteback(MF)204
)
229
4.35k
    return;
230
79
  const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
231
79
  auto &MRI = MF.getRegInfo();
232
79
  auto InsertPt = MBB.getFirstTerminator();
233
79
  DebugLoc DL;
234
79
235
79
  if (InsertPt != MBB.end())
236
79
    DL = InsertPt->getDebugLoc();
237
79
238
79
  // Restore the stack pointer. If we had fixed-size locals, add the offset
239
79
  // subtracted in the prolog.
240
79
  unsigned SPReg = 0;
241
79
  if (hasBP(MF)) {
242
5
    auto FI = MF.getInfo<WebAssemblyFunctionInfo>();
243
5
    SPReg = FI->getBasePointerVreg();
244
74
  } else if (StackSize) {
245
68
    const TargetRegisterClass *PtrRC =
246
68
        MRI.getTargetRegisterInfo()->getPointerRegClass(MF);
247
68
    unsigned OffsetReg = MRI.createVirtualRegister(PtrRC);
248
68
    BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), OffsetReg)
249
68
        .addImm(StackSize);
250
68
    // In the epilog we don't need to write the result back to the SP32 physreg
251
68
    // because it won't be used again. We can use a stackified register instead.
252
68
    SPReg = MRI.createVirtualRegister(PtrRC);
253
68
    BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::ADD_I32), SPReg)
254
68
        .addReg(hasFP(MF) ? 
WebAssembly::FP321
:
WebAssembly::SP3267
)
255
68
        .addReg(OffsetReg);
256
68
  } else {
257
6
    SPReg = hasFP(MF) ? WebAssembly::FP32 : 
WebAssembly::SP320
;
258
6
  }
259
79
260
79
  writeSPToGlobal(SPReg, MF, MBB, InsertPt, DL);
261
79
}