Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp
Line
Count
Source (jump to first uncovered line)
1
//- WebAssemblyISelDAGToDAG.cpp - A dag to dag inst selector for WebAssembly -//
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 defines an instruction selector for the WebAssembly target.
11
///
12
//===----------------------------------------------------------------------===//
13
14
#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
15
#include "WebAssembly.h"
16
#include "WebAssemblyTargetMachine.h"
17
#include "llvm/CodeGen/SelectionDAGISel.h"
18
#include "llvm/IR/DiagnosticInfo.h"
19
#include "llvm/IR/Function.h" // To access function attributes.
20
#include "llvm/Support/Debug.h"
21
#include "llvm/Support/KnownBits.h"
22
#include "llvm/Support/MathExtras.h"
23
#include "llvm/Support/raw_ostream.h"
24
using namespace llvm;
25
26
#define DEBUG_TYPE "wasm-isel"
27
28
//===--------------------------------------------------------------------===//
29
/// WebAssembly-specific code to select WebAssembly machine instructions for
30
/// SelectionDAG operations.
31
///
32
namespace {
33
class WebAssemblyDAGToDAGISel final : public SelectionDAGISel {
34
  /// Keep a pointer to the WebAssemblySubtarget around so that we can make the
35
  /// right decision when generating code for different targets.
36
  const WebAssemblySubtarget *Subtarget;
37
38
  bool ForCodeSize;
39
40
public:
41
  WebAssemblyDAGToDAGISel(WebAssemblyTargetMachine &TM,
42
                          CodeGenOpt::Level OptLevel)
43
426
      : SelectionDAGISel(TM, OptLevel), Subtarget(nullptr), ForCodeSize(false) {
44
426
  }
45
46
4.45k
  StringRef getPassName() const override {
47
4.45k
    return "WebAssembly Instruction Selection";
48
4.45k
  }
49
50
4.45k
  bool runOnMachineFunction(MachineFunction &MF) override {
51
4.45k
    LLVM_DEBUG(dbgs() << "********** ISelDAGToDAG **********\n"
52
4.45k
                         "********** Function: "
53
4.45k
                      << MF.getName() << '\n');
54
4.45k
55
4.45k
    ForCodeSize = MF.getFunction().hasOptSize();
56
4.45k
    Subtarget = &MF.getSubtarget<WebAssemblySubtarget>();
57
4.45k
    return SelectionDAGISel::runOnMachineFunction(MF);
58
4.45k
  }
59
60
  void Select(SDNode *Node) override;
61
62
  bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID,
63
                                    std::vector<SDValue> &OutOps) override;
64
65
// Include the pieces autogenerated from the target description.
66
#include "WebAssemblyGenDAGISel.inc"
67
68
private:
69
  // add select functions here...
70
};
71
} // end anonymous namespace
72
73
69.9k
void WebAssemblyDAGToDAGISel::Select(SDNode *Node) {
74
69.9k
  // If we have a custom node, we already have selected!
75
69.9k
  if (Node->isMachineOpcode()) {
76
2
    LLVM_DEBUG(errs() << "== "; Node->dump(CurDAG); errs() << "\n");
77
2
    Node->setNodeId(-1);
78
2
    return;
79
2
  }
80
69.9k
81
69.9k
  // Few custom selection stuff.
82
69.9k
  SDLoc DL(Node);
83
69.9k
  MachineFunction &MF = CurDAG->getMachineFunction();
84
69.9k
  switch (Node->getOpcode()) {
85
69.9k
  case ISD::ATOMIC_FENCE: {
86
10
    if (!MF.getSubtarget<WebAssemblySubtarget>().hasAtomics())
87
0
      break;
88
10
89
10
    uint64_t SyncScopeID =
90
10
        cast<ConstantSDNode>(Node->getOperand(2).getNode())->getZExtValue();
91
10
    switch (SyncScopeID) {
92
10
    case SyncScope::SingleThread: {
93
4
      // We lower a single-thread fence to a pseudo compiler barrier instruction
94
4
      // preventing instruction reordering. This will not be emitted in final
95
4
      // binary.
96
4
      MachineSDNode *Fence =
97
4
          CurDAG->getMachineNode(WebAssembly::COMPILER_FENCE,
98
4
                                 DL,                 // debug loc
99
4
                                 MVT::Other,         // outchain type
100
4
                                 Node->getOperand(0) // inchain
101
4
          );
102
4
      ReplaceNode(Node, Fence);
103
4
      CurDAG->RemoveDeadNode(Node);
104
4
      return;
105
10
    }
106
10
107
10
    case SyncScope::System: {
108
6
      // For non-emscripten systems, we have not decided on what we should
109
6
      // traslate fences to yet.
110
6
      if (!Subtarget->getTargetTriple().isOSEmscripten())
111
2
        report_fatal_error(
112
2
            "ATOMIC_FENCE is not yet supported in non-emscripten OSes");
113
4
114
4
      // Wasm does not have a fence instruction, but because all atomic
115
4
      // instructions in wasm are sequentially consistent, we translate a
116
4
      // fence to an idempotent atomic RMW instruction to a linear memory
117
4
      // address. All atomic instructions in wasm are sequentially consistent,
118
4
      // but this is to ensure a fence also prevents reordering of non-atomic
119
4
      // instructions in the VM. Even though LLVM IR's fence instruction does
120
4
      // not say anything about its relationship with non-atomic instructions,
121
4
      // we think this is more user-friendly.
122
4
      //
123
4
      // While any address can work, here we use a value stored in
124
4
      // __stack_pointer wasm global because there's high chance that area is
125
4
      // in cache.
126
4
      //
127
4
      // So the selected instructions will be in the form of:
128
4
      //   %addr = get_global $__stack_pointer
129
4
      //   %0 = i32.const 0
130
4
      //   i32.atomic.rmw.or %addr, %0
131
4
      SDValue StackPtrSym = CurDAG->getTargetExternalSymbol(
132
4
          "__stack_pointer", TLI->getPointerTy(CurDAG->getDataLayout()));
133
4
      MachineSDNode *GetGlobal =
134
4
          CurDAG->getMachineNode(WebAssembly::GLOBAL_GET_I32, // opcode
135
4
                                 DL,                          // debug loc
136
4
                                 MVT::i32,                    // result type
137
4
                                 StackPtrSym // __stack_pointer symbol
138
4
          );
139
4
140
4
      SDValue Zero = CurDAG->getTargetConstant(0, DL, MVT::i32);
141
4
      auto *MMO = MF.getMachineMemOperand(
142
4
          MachinePointerInfo::getUnknownStack(MF),
143
4
          // FIXME Volatile isn't really correct, but currently all LLVM
144
4
          // atomic instructions are treated as volatiles in the backend, so
145
4
          // we should be consistent.
146
4
          MachineMemOperand::MOVolatile | MachineMemOperand::MOLoad |
147
4
              MachineMemOperand::MOStore,
148
4
          4, 4, AAMDNodes(), nullptr, SyncScope::System,
149
4
          AtomicOrdering::SequentiallyConsistent);
150
4
      MachineSDNode *Const0 =
151
4
          CurDAG->getMachineNode(WebAssembly::CONST_I32, DL, MVT::i32, Zero);
152
4
      MachineSDNode *AtomicRMW = CurDAG->getMachineNode(
153
4
          WebAssembly::ATOMIC_RMW_OR_I32, // opcode
154
4
          DL,                             // debug loc
155
4
          MVT::i32,                       // result type
156
4
          MVT::Other,                     // outchain type
157
4
          {
158
4
              Zero,                  // alignment
159
4
              Zero,                  // offset
160
4
              SDValue(GetGlobal, 0), // __stack_pointer
161
4
              SDValue(Const0, 0),    // OR with 0 to make it idempotent
162
4
              Node->getOperand(0)    // inchain
163
4
          });
164
4
165
4
      CurDAG->setNodeMemRefs(AtomicRMW, {MMO});
166
4
      ReplaceUses(SDValue(Node, 0), SDValue(AtomicRMW, 1));
167
4
      CurDAG->RemoveDeadNode(Node);
168
4
      return;
169
4
    }
170
4
    default:
171
0
      llvm_unreachable("Unknown scope!");
172
0
    }
173
0
  }
174
0
175
22
  case ISD::GlobalTLSAddress: {
176
22
    const auto *GA = cast<GlobalAddressSDNode>(Node);
177
22
178
22
    if (!MF.getSubtarget<WebAssemblySubtarget>().hasBulkMemory())
179
0
      report_fatal_error("cannot use thread-local storage without bulk memory",
180
0
                         false);
181
22
182
22
    // Currently Emscripten does not support dynamic linking with threads.
183
22
    // Therefore, if we have thread-local storage, only the local-exec model
184
22
    // is possible.
185
22
    // TODO: remove this and implement proper TLS models once Emscripten
186
22
    // supports dynamic linking with threads.
187
22
    if (GA->getGlobal()->getThreadLocalMode() !=
188
22
            GlobalValue::LocalExecTLSModel &&
189
22
        
!Subtarget->getTargetTriple().isOSEmscripten()10
) {
190
2
      report_fatal_error("only -ftls-model=local-exec is supported for now on "
191
2
                         "non-Emscripten OSes: variable " +
192
2
                             GA->getGlobal()->getName(),
193
2
                         false);
194
2
    }
195
20
196
20
    MVT PtrVT = TLI->getPointerTy(CurDAG->getDataLayout());
197
20
    assert(PtrVT == MVT::i32 && "only wasm32 is supported for now");
198
20
199
20
    SDValue TLSBaseSym = CurDAG->getTargetExternalSymbol("__tls_base", PtrVT);
200
20
    SDValue TLSOffsetSym = CurDAG->getTargetGlobalAddress(
201
20
        GA->getGlobal(), DL, PtrVT, GA->getOffset(), 0);
202
20
203
20
    MachineSDNode *TLSBase = CurDAG->getMachineNode(WebAssembly::GLOBAL_GET_I32,
204
20
                                                    DL, MVT::i32, TLSBaseSym);
205
20
    MachineSDNode *TLSOffset = CurDAG->getMachineNode(
206
20
        WebAssembly::CONST_I32, DL, MVT::i32, TLSOffsetSym);
207
20
    MachineSDNode *TLSAddress =
208
20
        CurDAG->getMachineNode(WebAssembly::ADD_I32, DL, MVT::i32,
209
20
                               SDValue(TLSBase, 0), SDValue(TLSOffset, 0));
210
20
    ReplaceNode(Node, TLSAddress);
211
20
    return;
212
20
  }
213
20
214
62
  case ISD::INTRINSIC_WO_CHAIN: {
215
62
    unsigned IntNo = cast<ConstantSDNode>(Node->getOperand(0))->getZExtValue();
216
62
    switch (IntNo) {
217
62
    case Intrinsic::wasm_tls_size: {
218
6
      MVT PtrVT = TLI->getPointerTy(CurDAG->getDataLayout());
219
6
      assert(PtrVT == MVT::i32 && "only wasm32 is supported for now");
220
6
221
6
      MachineSDNode *TLSSize = CurDAG->getMachineNode(
222
6
          WebAssembly::GLOBAL_GET_I32, DL, PtrVT,
223
6
          CurDAG->getTargetExternalSymbol("__tls_size", MVT::i32));
224
6
      ReplaceNode(Node, TLSSize);
225
6
      return;
226
62
    }
227
62
    case Intrinsic::wasm_tls_align: {
228
4
      MVT PtrVT = TLI->getPointerTy(CurDAG->getDataLayout());
229
4
      assert(PtrVT == MVT::i32 && "only wasm32 is supported for now");
230
4
231
4
      MachineSDNode *TLSAlign = CurDAG->getMachineNode(
232
4
          WebAssembly::GLOBAL_GET_I32, DL, PtrVT,
233
4
          CurDAG->getTargetExternalSymbol("__tls_align", MVT::i32));
234
4
      ReplaceNode(Node, TLSAlign);
235
4
      return;
236
52
    }
237
52
    }
238
52
    break;
239
52
  }
240
86
  case ISD::INTRINSIC_W_CHAIN: {
241
86
    unsigned IntNo = cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue();
242
86
    switch (IntNo) {
243
86
    case Intrinsic::wasm_tls_base: {
244
6
      MVT PtrVT = TLI->getPointerTy(CurDAG->getDataLayout());
245
6
      assert(PtrVT == MVT::i32 && "only wasm32 is supported for now");
246
6
247
6
      MachineSDNode *TLSBase = CurDAG->getMachineNode(
248
6
          WebAssembly::GLOBAL_GET_I32, DL, MVT::i32, MVT::Other,
249
6
          CurDAG->getTargetExternalSymbol("__tls_base", PtrVT),
250
6
          Node->getOperand(0));
251
6
      ReplaceNode(Node, TLSBase);
252
6
      return;
253
80
    }
254
80
    }
255
80
    break;
256
80
  }
257
80
258
69.7k
  default:
259
69.7k
    break;
260
69.8k
  }
261
69.8k
262
69.8k
  // Select the default instruction.
263
69.8k
  SelectCode(Node);
264
69.8k
}
265
266
bool WebAssemblyDAGToDAGISel::SelectInlineAsmMemoryOperand(
267
0
    const SDValue &Op, unsigned ConstraintID, std::vector<SDValue> &OutOps) {
268
0
  switch (ConstraintID) {
269
0
  case InlineAsm::Constraint_i:
270
0
  case InlineAsm::Constraint_m:
271
0
    // We just support simple memory operands that just have a single address
272
0
    // operand and need no special handling.
273
0
    OutOps.push_back(Op);
274
0
    return false;
275
0
  default:
276
0
    break;
277
0
  }
278
0
279
0
  return true;
280
0
}
281
282
/// This pass converts a legalized DAG into a WebAssembly-specific DAG, ready
283
/// for instruction scheduling.
284
FunctionPass *llvm::createWebAssemblyISelDag(WebAssemblyTargetMachine &TM,
285
426
                                             CodeGenOpt::Level OptLevel) {
286
426
  return new WebAssemblyDAGToDAGISel(TM, OptLevel);
287
426
}