Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/lib/Target/WebAssembly/WebAssemblyMemIntrinsicResults.cpp
Line
Count
Source (jump to first uncovered line)
1
//== WebAssemblyMemIntrinsicResults.cpp - Optimize memory intrinsic results ==//
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 implements an optimization pass using memory intrinsic results.
11
///
12
/// Calls to memory intrinsics (memcpy, memmove, memset) return the destination
13
/// address. They are in the form of
14
///   %dst_new = call @memcpy %dst, %src, %len
15
/// where %dst and %dst_new registers contain the same value.
16
///
17
/// This is to enable an optimization wherein uses of the %dst register used in
18
/// the parameter can be replaced by uses of the %dst_new register used in the
19
/// result, making the %dst register more likely to be single-use, thus more
20
/// likely to be useful to register stackifying, and potentially also exposing
21
/// the call instruction itself to register stackifying. These both can reduce
22
/// local.get/local.set traffic.
23
///
24
/// The LLVM intrinsics for these return void so they can't use the returned
25
/// attribute and consequently aren't handled by the OptimizeReturned pass.
26
///
27
//===----------------------------------------------------------------------===//
28
29
#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
30
#include "WebAssembly.h"
31
#include "WebAssemblyMachineFunctionInfo.h"
32
#include "WebAssemblySubtarget.h"
33
#include "llvm/Analysis/TargetLibraryInfo.h"
34
#include "llvm/CodeGen/LiveIntervals.h"
35
#include "llvm/CodeGen/MachineBlockFrequencyInfo.h"
36
#include "llvm/CodeGen/MachineDominators.h"
37
#include "llvm/CodeGen/MachineRegisterInfo.h"
38
#include "llvm/CodeGen/Passes.h"
39
#include "llvm/Support/Debug.h"
40
#include "llvm/Support/raw_ostream.h"
41
using namespace llvm;
42
43
#define DEBUG_TYPE "wasm-mem-intrinsic-results"
44
45
namespace {
46
class WebAssemblyMemIntrinsicResults final : public MachineFunctionPass {
47
public:
48
  static char ID; // Pass identification, replacement for typeid
49
413
  WebAssemblyMemIntrinsicResults() : MachineFunctionPass(ID) {}
50
51
4.72k
  StringRef getPassName() const override {
52
4.72k
    return "WebAssembly Memory Intrinsic Results";
53
4.72k
  }
54
55
413
  void getAnalysisUsage(AnalysisUsage &AU) const override {
56
413
    AU.setPreservesCFG();
57
413
    AU.addRequired<MachineBlockFrequencyInfo>();
58
413
    AU.addPreserved<MachineBlockFrequencyInfo>();
59
413
    AU.addRequired<MachineDominatorTree>();
60
413
    AU.addPreserved<MachineDominatorTree>();
61
413
    AU.addRequired<LiveIntervals>();
62
413
    AU.addPreserved<SlotIndexes>();
63
413
    AU.addPreserved<LiveIntervals>();
64
413
    AU.addRequired<TargetLibraryInfoWrapperPass>();
65
413
    MachineFunctionPass::getAnalysisUsage(AU);
66
413
  }
67
68
  bool runOnMachineFunction(MachineFunction &MF) override;
69
70
private:
71
};
72
} // end anonymous namespace
73
74
char WebAssemblyMemIntrinsicResults::ID = 0;
75
INITIALIZE_PASS(WebAssemblyMemIntrinsicResults, DEBUG_TYPE,
76
                "Optimize memory intrinsic result values for WebAssembly",
77
                false, false)
78
79
413
FunctionPass *llvm::createWebAssemblyMemIntrinsicResults() {
80
413
  return new WebAssemblyMemIntrinsicResults();
81
413
}
82
83
// Replace uses of FromReg with ToReg if they are dominated by MI.
84
static bool replaceDominatedUses(MachineBasicBlock &MBB, MachineInstr &MI,
85
                                 unsigned FromReg, unsigned ToReg,
86
                                 const MachineRegisterInfo &MRI,
87
                                 MachineDominatorTree &MDT,
88
24
                                 LiveIntervals &LIS) {
89
24
  bool Changed = false;
90
24
91
24
  LiveInterval *FromLI = &LIS.getInterval(FromReg);
92
24
  LiveInterval *ToLI = &LIS.getInterval(ToReg);
93
24
94
24
  SlotIndex FromIdx = LIS.getInstructionIndex(MI).getRegSlot();
95
24
  VNInfo *FromVNI = FromLI->getVNInfoAt(FromIdx);
96
24
97
24
  SmallVector<SlotIndex, 4> Indices;
98
24
99
24
  for (auto I = MRI.use_nodbg_begin(FromReg), E = MRI.use_nodbg_end();
100
66
       I != E;) {
101
42
    MachineOperand &O = *I++;
102
42
    MachineInstr *Where = O.getParent();
103
42
104
42
    // Check that MI dominates the instruction in the normal way.
105
42
    if (&MI == Where || 
!MDT.dominates(&MI, Where)18
)
106
30
      continue;
107
12
108
12
    // If this use gets a different value, skip it.
109
12
    SlotIndex WhereIdx = LIS.getInstructionIndex(*Where);
110
12
    VNInfo *WhereVNI = FromLI->getVNInfoAt(WhereIdx);
111
12
    if (WhereVNI && WhereVNI != FromVNI)
112
0
      continue;
113
12
114
12
    // Make sure ToReg isn't clobbered before it gets there.
115
12
    VNInfo *ToVNI = ToLI->getVNInfoAt(WhereIdx);
116
12
    if (ToVNI && 
ToVNI != FromVNI0
)
117
0
      continue;
118
12
119
12
    Changed = true;
120
12
    LLVM_DEBUG(dbgs() << "Setting operand " << O << " in " << *Where << " from "
121
12
                      << MI << "\n");
122
12
    O.setReg(ToReg);
123
12
124
12
    // If the store's def was previously dead, it is no longer.
125
12
    if (!O.isUndef()) {
126
12
      MI.getOperand(0).setIsDead(false);
127
12
128
12
      Indices.push_back(WhereIdx.getRegSlot());
129
12
    }
130
12
  }
131
24
132
24
  if (Changed) {
133
10
    // Extend ToReg's liveness.
134
10
    LIS.extendToIndices(*ToLI, Indices);
135
10
136
10
    // Shrink FromReg's liveness.
137
10
    LIS.shrinkToUses(FromLI);
138
10
139
10
    // If we replaced all dominated uses, FromReg is now killed at MI.
140
10
    if (!FromLI->liveAt(FromIdx.getDeadSlot()))
141
10
      MI.addRegisterKilled(FromReg, MBB.getParent()
142
10
                                        ->getSubtarget<WebAssemblySubtarget>()
143
10
                                        .getRegisterInfo());
144
10
  }
145
24
146
24
  return Changed;
147
24
}
148
149
static bool optimizeCall(MachineBasicBlock &MBB, MachineInstr &MI,
150
                         const MachineRegisterInfo &MRI,
151
                         MachineDominatorTree &MDT, LiveIntervals &LIS,
152
                         const WebAssemblyTargetLowering &TLI,
153
269
                         const TargetLibraryInfo &LibInfo) {
154
269
  MachineOperand &Op1 = MI.getOperand(1);
155
269
  if (!Op1.isSymbol())
156
233
    return false;
157
36
158
36
  StringRef Name(Op1.getSymbolName());
159
36
  bool CallReturnsInput = Name == TLI.getLibcallName(RTLIB::MEMCPY) ||
160
36
                          
Name == TLI.getLibcallName(RTLIB::MEMMOVE)26
||
161
36
                          
Name == TLI.getLibcallName(RTLIB::MEMSET)21
;
162
36
  if (!CallReturnsInput)
163
12
    return false;
164
24
165
24
  LibFunc Func;
166
24
  if (!LibInfo.getLibFunc(Name, Func))
167
0
    return false;
168
24
169
24
  unsigned FromReg = MI.getOperand(2).getReg();
170
24
  unsigned ToReg = MI.getOperand(0).getReg();
171
24
  if (MRI.getRegClass(FromReg) != MRI.getRegClass(ToReg))
172
0
    report_fatal_error("Memory Intrinsic results: call to builtin function "
173
0
                       "with wrong signature, from/to mismatch");
174
24
  return replaceDominatedUses(MBB, MI, FromReg, ToReg, MRI, MDT, LIS);
175
24
}
176
177
4.31k
bool WebAssemblyMemIntrinsicResults::runOnMachineFunction(MachineFunction &MF) {
178
4.31k
  LLVM_DEBUG({
179
4.31k
    dbgs() << "********** Memory Intrinsic Results **********\n"
180
4.31k
           << "********** Function: " << MF.getName() << '\n';
181
4.31k
  });
182
4.31k
183
4.31k
  MachineRegisterInfo &MRI = MF.getRegInfo();
184
4.31k
  auto &MDT = getAnalysis<MachineDominatorTree>();
185
4.31k
  const WebAssemblyTargetLowering &TLI =
186
4.31k
      *MF.getSubtarget<WebAssemblySubtarget>().getTargetLowering();
187
4.31k
  const auto &LibInfo = getAnalysis<TargetLibraryInfoWrapperPass>().getTLI();
188
4.31k
  auto &LIS = getAnalysis<LiveIntervals>();
189
4.31k
  bool Changed = false;
190
4.31k
191
4.31k
  // We don't preserve SSA form.
192
4.31k
  MRI.leaveSSA();
193
4.31k
194
4.31k
  assert(MRI.tracksLiveness() &&
195
4.31k
         "MemIntrinsicResults expects liveness tracking");
196
4.31k
197
4.95k
  for (auto &MBB : MF) {
198
4.95k
    LLVM_DEBUG(dbgs() << "Basic Block: " << MBB.getName() << '\n');
199
4.95k
    for (auto &MI : MBB)
200
43.9k
      switch (MI.getOpcode()) {
201
43.9k
      default:
202
43.7k
        break;
203
43.9k
      case WebAssembly::CALL_i32:
204
269
      case WebAssembly::CALL_i64:
205
269
        Changed |= optimizeCall(MBB, MI, MRI, MDT, LIS, TLI, LibInfo);
206
269
        break;
207
43.9k
      }
208
4.95k
  }
209
4.31k
210
4.31k
  return Changed;
211
4.31k
}