Coverage Report

Created: 2024-01-17 10:31

/src/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp
Line
Count
Source (jump to first uncovered line)
1
//===-- WebAssemblyInstrInfo.cpp - WebAssembly Instruction Information ----===//
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 the
11
/// TargetInstrInfo class.
12
///
13
//===----------------------------------------------------------------------===//
14
15
#include "WebAssemblyInstrInfo.h"
16
#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
17
#include "WebAssembly.h"
18
#include "WebAssemblyMachineFunctionInfo.h"
19
#include "WebAssemblySubtarget.h"
20
#include "WebAssemblyUtilities.h"
21
#include "llvm/CodeGen/MachineFrameInfo.h"
22
#include "llvm/CodeGen/MachineInstrBuilder.h"
23
#include "llvm/CodeGen/MachineMemOperand.h"
24
#include "llvm/CodeGen/MachineRegisterInfo.h"
25
using namespace llvm;
26
27
#define DEBUG_TYPE "wasm-instr-info"
28
29
#define GET_INSTRINFO_CTOR_DTOR
30
#include "WebAssemblyGenInstrInfo.inc"
31
32
// defines WebAssembly::getNamedOperandIdx
33
#define GET_INSTRINFO_NAMED_OPS
34
#include "WebAssemblyGenInstrInfo.inc"
35
36
WebAssemblyInstrInfo::WebAssemblyInstrInfo(const WebAssemblySubtarget &STI)
37
    : WebAssemblyGenInstrInfo(WebAssembly::ADJCALLSTACKDOWN,
38
                              WebAssembly::ADJCALLSTACKUP,
39
                              WebAssembly::CATCHRET),
40
2
      RI(STI.getTargetTriple()) {}
41
42
bool WebAssemblyInstrInfo::isReallyTriviallyReMaterializable(
43
11.3k
    const MachineInstr &MI) const {
44
11.3k
  switch (MI.getOpcode()) {
45
10.5k
  case WebAssembly::CONST_I32:
46
11.2k
  case WebAssembly::CONST_I64:
47
11.3k
  case WebAssembly::CONST_F32:
48
11.3k
  case WebAssembly::CONST_F64:
49
    // TargetInstrInfo::isReallyTriviallyReMaterializable misses these
50
    // because of the ARGUMENTS implicit def, so we manualy override it here.
51
11.3k
    return true;
52
0
  default:
53
0
    return TargetInstrInfo::isReallyTriviallyReMaterializable(MI);
54
11.3k
  }
55
11.3k
}
56
57
void WebAssemblyInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
58
                                       MachineBasicBlock::iterator I,
59
                                       const DebugLoc &DL, MCRegister DestReg,
60
1.66k
                                       MCRegister SrcReg, bool KillSrc) const {
61
  // This method is called by post-RA expansion, which expects only pregs to
62
  // exist. However we need to handle both here.
63
1.66k
  auto &MRI = MBB.getParent()->getRegInfo();
64
1.66k
  const TargetRegisterClass *RC =
65
1.66k
      Register::isVirtualRegister(DestReg)
66
1.66k
          ? MRI.getRegClass(DestReg)
67
1.66k
          : MRI.getTargetRegisterInfo()->getMinimalPhysRegClass(DestReg);
68
69
1.66k
  unsigned CopyOpcode = WebAssembly::getCopyOpcodeForRegClass(RC);
70
71
1.66k
  BuildMI(MBB, I, DL, get(CopyOpcode), DestReg)
72
1.66k
      .addReg(SrcReg, KillSrc ? RegState::Kill : 0);
73
1.66k
}
74
75
MachineInstr *WebAssemblyInstrInfo::commuteInstructionImpl(
76
17.6k
    MachineInstr &MI, bool NewMI, unsigned OpIdx1, unsigned OpIdx2) const {
77
  // If the operands are stackified, we can't reorder them.
78
17.6k
  WebAssemblyFunctionInfo &MFI =
79
17.6k
      *MI.getParent()->getParent()->getInfo<WebAssemblyFunctionInfo>();
80
17.6k
  if (MFI.isVRegStackified(MI.getOperand(OpIdx1).getReg()) ||
81
17.6k
      MFI.isVRegStackified(MI.getOperand(OpIdx2).getReg()))
82
0
    return nullptr;
83
84
  // Otherwise use the default implementation.
85
17.6k
  return TargetInstrInfo::commuteInstructionImpl(MI, NewMI, OpIdx1, OpIdx2);
86
17.6k
}
87
88
// Branch analysis.
89
bool WebAssemblyInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
90
                                         MachineBasicBlock *&TBB,
91
                                         MachineBasicBlock *&FBB,
92
                                         SmallVectorImpl<MachineOperand> &Cond,
93
74.4k
                                         bool /*AllowModify*/) const {
94
74.4k
  const auto &MFI = *MBB.getParent()->getInfo<WebAssemblyFunctionInfo>();
95
  // WebAssembly has control flow that doesn't have explicit branches or direct
96
  // fallthrough (e.g. try/catch), which can't be modeled by analyzeBranch. It
97
  // is created after CFGStackify.
98
74.4k
  if (MFI.isCFGStackified())
99
0
    return true;
100
101
74.4k
  bool HaveCond = false;
102
74.4k
  for (MachineInstr &MI : MBB.terminators()) {
103
59.1k
    switch (MI.getOpcode()) {
104
19.0k
    default:
105
      // Unhandled instruction; bail out.
106
19.0k
      return true;
107
20.2k
    case WebAssembly::BR_IF:
108
20.2k
      if (HaveCond)
109
0
        return true;
110
20.2k
      Cond.push_back(MachineOperand::CreateImm(true));
111
20.2k
      Cond.push_back(MI.getOperand(1));
112
20.2k
      TBB = MI.getOperand(0).getMBB();
113
20.2k
      HaveCond = true;
114
20.2k
      break;
115
4.10k
    case WebAssembly::BR_UNLESS:
116
4.10k
      if (HaveCond)
117
0
        return true;
118
4.10k
      Cond.push_back(MachineOperand::CreateImm(false));
119
4.10k
      Cond.push_back(MI.getOperand(1));
120
4.10k
      TBB = MI.getOperand(0).getMBB();
121
4.10k
      HaveCond = true;
122
4.10k
      break;
123
15.7k
    case WebAssembly::BR:
124
15.7k
      if (!HaveCond)
125
11.1k
        TBB = MI.getOperand(0).getMBB();
126
4.66k
      else
127
4.66k
        FBB = MI.getOperand(0).getMBB();
128
15.7k
      break;
129
59.1k
    }
130
40.1k
    if (MI.isBarrier())
131
15.7k
      break;
132
40.1k
  }
133
134
55.4k
  return false;
135
74.4k
}
136
137
unsigned WebAssemblyInstrInfo::removeBranch(MachineBasicBlock &MBB,
138
7.34k
                                            int *BytesRemoved) const {
139
7.34k
  assert(!BytesRemoved && "code size not handled");
140
141
0
  MachineBasicBlock::instr_iterator I = MBB.instr_end();
142
7.34k
  unsigned Count = 0;
143
144
16.6k
  while (I != MBB.instr_begin()) {
145
15.6k
    --I;
146
15.6k
    if (I->isDebugInstr())
147
0
      continue;
148
15.6k
    if (!I->isTerminator())
149
6.32k
      break;
150
    // Remove the branch.
151
9.34k
    I->eraseFromParent();
152
9.34k
    I = MBB.instr_end();
153
9.34k
    ++Count;
154
9.34k
  }
155
156
7.34k
  return Count;
157
7.34k
}
158
159
unsigned WebAssemblyInstrInfo::insertBranch(
160
    MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB,
161
6.14k
    ArrayRef<MachineOperand> Cond, const DebugLoc &DL, int *BytesAdded) const {
162
6.14k
  assert(!BytesAdded && "code size not handled");
163
164
6.14k
  if (Cond.empty()) {
165
1.50k
    if (!TBB)
166
0
      return 0;
167
168
1.50k
    BuildMI(&MBB, DL, get(WebAssembly::BR)).addMBB(TBB);
169
1.50k
    return 1;
170
1.50k
  }
171
172
4.63k
  assert(Cond.size() == 2 && "Expected a flag and a successor block");
173
174
4.63k
  if (Cond[0].getImm())
175
2.75k
    BuildMI(&MBB, DL, get(WebAssembly::BR_IF)).addMBB(TBB).add(Cond[1]);
176
1.88k
  else
177
1.88k
    BuildMI(&MBB, DL, get(WebAssembly::BR_UNLESS)).addMBB(TBB).add(Cond[1]);
178
4.63k
  if (!FBB)
179
4.60k
    return 1;
180
181
29
  BuildMI(&MBB, DL, get(WebAssembly::BR)).addMBB(FBB);
182
29
  return 2;
183
4.63k
}
184
185
bool WebAssemblyInstrInfo::reverseBranchCondition(
186
3.56k
    SmallVectorImpl<MachineOperand> &Cond) const {
187
3.56k
  assert(Cond.size() == 2 && "Expected a flag and a condition expression");
188
0
  Cond.front() = MachineOperand::CreateImm(!Cond.front().getImm());
189
3.56k
  return false;
190
3.56k
}
191
192
ArrayRef<std::pair<int, const char *>>
193
0
WebAssemblyInstrInfo::getSerializableTargetIndices() const {
194
0
  static const std::pair<int, const char *> TargetIndices[] = {
195
0
      {WebAssembly::TI_LOCAL, "wasm-local"},
196
0
      {WebAssembly::TI_GLOBAL_FIXED, "wasm-global-fixed"},
197
0
      {WebAssembly::TI_OPERAND_STACK, "wasm-operand-stack"},
198
0
      {WebAssembly::TI_GLOBAL_RELOC, "wasm-global-reloc"},
199
0
      {WebAssembly::TI_LOCAL_INDIRECT, "wasm-local-indirect"}};
200
0
  return ArrayRef(TargetIndices);
201
0
}
202
203
const MachineOperand &
204
0
WebAssemblyInstrInfo::getCalleeOperand(const MachineInstr &MI) const {
205
0
  return WebAssembly::getCalleeOp(MI);
206
0
}
207
208
// This returns true when the instruction defines a value of a TargetIndex
209
// operand that can be tracked by offsets. For Wasm, this returns true for only
210
// local.set/local.tees. This is currently used by LiveDebugValues analysis.
211
//
212
// These are not included:
213
// - In theory we need to add global.set here too, but we don't have global
214
//   indices at this point because they are relocatable and we address them by
215
//   names until linking, so we don't have 'offsets' (which are used to store
216
//   local/global indices) to deal with in LiveDebugValues. And we don't
217
//   associate debug info in values in globals anyway.
218
// - All other value-producing instructions, i.e. instructions with defs, can
219
//   define values in the Wasm stack, which is represented by TI_OPERAND_STACK
220
//   TargetIndex. But they don't have offset info within the instruction itself,
221
//   and debug info analysis for them is handled separately in
222
//   WebAssemblyDebugFixup pass, so we don't worry about them here.
223
bool WebAssemblyInstrInfo::isExplicitTargetIndexDef(const MachineInstr &MI,
224
                                                    int &Index,
225
9.06k
                                                    int64_t &Offset) const {
226
9.06k
  unsigned Opc = MI.getOpcode();
227
9.06k
  if (WebAssembly::isLocalSet(Opc) || WebAssembly::isLocalTee(Opc)) {
228
1.45k
    Index = WebAssembly::TI_LOCAL;
229
1.45k
    Offset = MI.explicit_uses().begin()->getImm();
230
1.45k
    return true;
231
1.45k
  }
232
7.60k
  return false;
233
9.06k
}