Coverage Report

Created: 2019-05-12 12:24

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp
Line
Count
Source (jump to first uncovered line)
1
//=- WebAssemblyInstPrinter.cpp - WebAssembly assembly instruction printing -=//
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
/// Print MCInst instructions to wasm format.
11
///
12
//===----------------------------------------------------------------------===//
13
14
#include "InstPrinter/WebAssemblyInstPrinter.h"
15
#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
16
#include "WebAssembly.h"
17
#include "WebAssemblyMachineFunctionInfo.h"
18
#include "llvm/ADT/SmallSet.h"
19
#include "llvm/ADT/StringExtras.h"
20
#include "llvm/CodeGen/TargetRegisterInfo.h"
21
#include "llvm/MC/MCExpr.h"
22
#include "llvm/MC/MCInst.h"
23
#include "llvm/MC/MCInstrInfo.h"
24
#include "llvm/MC/MCSubtargetInfo.h"
25
#include "llvm/MC/MCSymbol.h"
26
#include "llvm/Support/ErrorHandling.h"
27
#include "llvm/Support/FormattedStream.h"
28
using namespace llvm;
29
30
#define DEBUG_TYPE "asm-printer"
31
32
#include "WebAssemblyGenAsmWriter.inc"
33
34
WebAssemblyInstPrinter::WebAssemblyInstPrinter(const MCAsmInfo &MAI,
35
                                               const MCInstrInfo &MII,
36
                                               const MCRegisterInfo &MRI)
37
114
    : MCInstPrinter(MAI, MII, MRI) {}
38
39
void WebAssemblyInstPrinter::printRegName(raw_ostream &OS,
40
7.81k
                                          unsigned RegNo) const {
41
7.81k
  assert(RegNo != WebAssemblyFunctionInfo::UnusedReg);
42
7.81k
  // Note that there's an implicit local.get/local.set here!
43
7.81k
  OS << "$" << RegNo;
44
7.81k
}
45
46
void WebAssemblyInstPrinter::printInst(const MCInst *MI, raw_ostream &OS,
47
                                       StringRef Annot,
48
19.1k
                                       const MCSubtargetInfo &STI) {
49
19.1k
  // Print the instruction (this uses the AsmStrings from the .td files).
50
19.1k
  printInstruction(MI, OS);
51
19.1k
52
19.1k
  // Print any additional variadic operands.
53
19.1k
  const MCInstrDesc &Desc = MII.get(MI->getOpcode());
54
19.1k
  if (Desc.isVariadic())
55
1.02k
    
for (auto I = Desc.getNumOperands(), E = MI->getNumOperands(); 371
I < E;
++I652
) {
56
652
      // FIXME: For CALL_INDIRECT_VOID, don't print a leading comma, because
57
652
      // we have an extra flags operand which is not currently printed, for
58
652
      // compatiblity reasons.
59
652
      if (I != 0 && ((MI->getOpcode() != WebAssembly::CALL_INDIRECT_VOID &&
60
652
                      
MI->getOpcode() != WebAssembly::CALL_INDIRECT_VOID_S645
) ||
61
652
                     
I != Desc.getNumOperands()7
))
62
648
        OS << ", ";
63
652
      printOperand(MI, I, OS);
64
652
    }
65
19.1k
66
19.1k
  // Print any added annotation.
67
19.1k
  printAnnotation(OS, Annot);
68
19.1k
69
19.1k
  if (CommentStream) {
70
1.22k
    // Observe any effects on the control flow stack, for use in annotating
71
1.22k
    // control flow label references.
72
1.22k
    unsigned Opc = MI->getOpcode();
73
1.22k
    switch (Opc) {
74
1.22k
    default:
75
958
      break;
76
1.22k
77
1.22k
    case WebAssembly::LOOP:
78
11
    case WebAssembly::LOOP_S:
79
11
      printAnnotation(OS, "label" + utostr(ControlFlowCounter) + ':');
80
11
      ControlFlowStack.push_back(std::make_pair(ControlFlowCounter++, true));
81
11
      break;
82
11
83
60
    case WebAssembly::BLOCK:
84
60
    case WebAssembly::BLOCK_S:
85
60
      ControlFlowStack.push_back(std::make_pair(ControlFlowCounter++, false));
86
60
      break;
87
60
88
60
    case WebAssembly::TRY:
89
43
    case WebAssembly::TRY_S:
90
43
      ControlFlowStack.push_back(std::make_pair(ControlFlowCounter++, false));
91
43
      EHPadStack.push_back(EHPadStackCounter++);
92
43
      LastSeenEHInst = TRY;
93
43
      break;
94
43
95
43
    case WebAssembly::END_LOOP:
96
10
    case WebAssembly::END_LOOP_S:
97
10
      if (ControlFlowStack.empty()) {
98
0
        printAnnotation(OS, "End marker mismatch!");
99
10
      } else {
100
10
        ControlFlowStack.pop_back();
101
10
      }
102
10
      break;
103
10
104
59
    case WebAssembly::END_BLOCK:
105
59
    case WebAssembly::END_BLOCK_S:
106
59
      if (ControlFlowStack.empty()) {
107
0
        printAnnotation(OS, "End marker mismatch!");
108
59
      } else {
109
59
        printAnnotation(
110
59
            OS, "label" + utostr(ControlFlowStack.pop_back_val().first) + ':');
111
59
      }
112
59
      break;
113
59
114
59
    case WebAssembly::END_TRY:
115
42
    case WebAssembly::END_TRY_S:
116
42
      if (ControlFlowStack.empty()) {
117
0
        printAnnotation(OS, "End marker mismatch!");
118
42
      } else {
119
42
        printAnnotation(
120
42
            OS, "label" + utostr(ControlFlowStack.pop_back_val().first) + ':');
121
42
        LastSeenEHInst = END_TRY;
122
42
      }
123
42
      break;
124
42
125
42
    case WebAssembly::CATCH:
126
42
    case WebAssembly::CATCH_S:
127
42
      if (EHPadStack.empty()) {
128
0
        printAnnotation(OS, "try-catch mismatch!");
129
42
      } else {
130
42
        printAnnotation(OS, "catch" + utostr(EHPadStack.pop_back_val()) + ':');
131
42
      }
132
42
      break;
133
1.22k
    }
134
1.22k
135
1.22k
    // Annotate any control flow label references.
136
1.22k
137
1.22k
    // rethrow instruction does not take any depth argument and rethrows to the
138
1.22k
    // nearest enclosing catch scope, if any. If there's no enclosing catch
139
1.22k
    // scope, it throws up to the caller.
140
1.22k
    if (Opc == WebAssembly::RETHROW || 
Opc == WebAssembly::RETHROW_S1.19k
) {
141
35
      if (EHPadStack.empty()) {
142
27
        printAnnotation(OS, "to caller");
143
27
      } else {
144
8
        printAnnotation(OS, "down to catch" + utostr(EHPadStack.back()));
145
8
      }
146
35
147
1.19k
    } else {
148
1.19k
      unsigned NumFixedOperands = Desc.NumOperands;
149
1.19k
      SmallSet<uint64_t, 8> Printed;
150
2.54k
      for (unsigned I = 0, E = MI->getNumOperands(); I < E; 
++I1.35k
) {
151
1.35k
        // See if this operand denotes a basic block target.
152
1.35k
        if (I < NumFixedOperands) {
153
1.32k
          // A non-variable_ops operand, check its type.
154
1.32k
          if (Desc.OpInfo[I].OperandType != WebAssembly::OPERAND_BASIC_BLOCK)
155
1.23k
            continue;
156
24
        } else {
157
24
          // A variable_ops operand, which currently can be immediates (used in
158
24
          // br_table) which are basic block targets, or for call instructions
159
24
          // when using -wasm-keep-registers (in which case they are registers,
160
24
          // and should not be processed).
161
24
          if (!MI->getOperand(I).isImm())
162
22
            continue;
163
93
        }
164
93
        uint64_t Depth = MI->getOperand(I).getImm();
165
93
        if (!Printed.insert(Depth).second)
166
0
          continue;
167
93
        if (Depth >= ControlFlowStack.size()) {
168
0
          printAnnotation(OS, "Invalid depth argument!");
169
93
        } else {
170
93
          const auto &Pair = ControlFlowStack.rbegin()[Depth];
171
93
          printAnnotation(OS, utostr(Depth) + ": " +
172
93
                                  (Pair.second ? 
"up"11
:
"down"82
) + " to label" +
173
93
                                  utostr(Pair.first));
174
93
        }
175
93
      }
176
1.19k
    }
177
1.22k
  }
178
19.1k
}
179
180
144
static std::string toString(const APFloat &FP) {
181
144
  // Print NaNs with custom payloads specially.
182
144
  if (FP.isNaN() && 
!FP.bitwiseIsEqual(APFloat::getQNaN(FP.getSemantics()))6
&&
183
144
      !FP.bitwiseIsEqual(
184
4
          APFloat::getQNaN(FP.getSemantics(), /*Negative=*/true))) {
185
2
    APInt AI = FP.bitcastToAPInt();
186
2
    return std::string(AI.isNegative() ? "-" : 
""0
) + "nan:0x" +
187
2
           utohexstr(AI.getZExtValue() &
188
2
                         (AI.getBitWidth() == 32 ? INT64_C(0x007fffff)
189
2
                                                 : INT64_C(0x000fffffffffffff)),
190
2
                     /*LowerCase=*/true);
191
2
  }
192
142
193
142
  // Use C99's hexadecimal floating-point representation.
194
142
  static const size_t BufBytes = 128;
195
142
  char Buf[BufBytes];
196
142
  auto Written = FP.convertToHexString(
197
142
      Buf, /*hexDigits=*/0, /*upperCase=*/false, APFloat::rmNearestTiesToEven);
198
142
  (void)Written;
199
142
  assert(Written != 0);
200
142
  assert(Written < BufBytes);
201
142
  return Buf;
202
142
}
203
204
void WebAssemblyInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
205
40.0k
                                          raw_ostream &O) {
206
40.0k
  const MCOperand &Op = MI->getOperand(OpNo);
207
40.0k
  if (Op.isReg()) {
208
30.2k
    unsigned WAReg = Op.getReg();
209
30.2k
    if (int(WAReg) >= 0)
210
7.81k
      printRegName(O, WAReg);
211
22.4k
    else if (OpNo >= MII.get(MI->getOpcode()).getNumDefs())
212
11.1k
      O << "$pop" << WebAssemblyFunctionInfo::getWARegStackId(WAReg);
213
11.2k
    else if (WAReg != WebAssemblyFunctionInfo::UnusedReg)
214
11.1k
      O << "$push" << WebAssemblyFunctionInfo::getWARegStackId(WAReg);
215
75
    else
216
75
      O << "$drop";
217
30.2k
    // Add a '=' suffix if this is a def.
218
30.2k
    if (OpNo < MII.get(MI->getOpcode()).getNumDefs())
219
11.7k
      O << '=';
220
30.2k
  } else 
if (9.85k
Op.isImm()9.85k
) {
221
8.81k
    O << Op.getImm();
222
8.81k
  } else 
if (1.03k
Op.isFPImm()1.03k
) {
223
144
    const MCInstrDesc &Desc = MII.get(MI->getOpcode());
224
144
    const MCOperandInfo &Info = Desc.OpInfo[OpNo];
225
144
    if (Info.OperandType == WebAssembly::OPERAND_F32IMM) {
226
70
      // TODO: MC converts all floating point immediate operands to double.
227
70
      // This is fine for numeric values, but may cause NaNs to change bits.
228
70
      O << ::toString(APFloat(float(Op.getFPImm())));
229
74
    } else {
230
74
      assert(Info.OperandType == WebAssembly::OPERAND_F64IMM);
231
74
      O << ::toString(APFloat(Op.getFPImm()));
232
74
    }
233
895
  } else {
234
895
    assert(Op.isExpr() && "unknown operand kind in printOperand");
235
895
    Op.getExpr()->print(O, &MAI);
236
895
  }
237
40.0k
}
238
239
void WebAssemblyInstPrinter::printBrList(const MCInst *MI, unsigned OpNo,
240
1
                                         raw_ostream &O) {
241
1
  O << "{";
242
6
  for (unsigned I = OpNo, E = MI->getNumOperands(); I != E; 
++I5
) {
243
5
    if (I != OpNo)
244
4
      O << ", ";
245
5
    O << MI->getOperand(I).getImm();
246
5
  }
247
1
  O << "}";
248
1
}
249
250
void WebAssemblyInstPrinter::printWebAssemblyP2AlignOperand(const MCInst *MI,
251
                                                            unsigned OpNo,
252
2.37k
                                                            raw_ostream &O) {
253
2.37k
  int64_t Imm = MI->getOperand(OpNo).getImm();
254
2.37k
  if (Imm == WebAssembly::GetDefaultP2Align(MI->getOpcode()))
255
2.35k
    return;
256
27
  O << ":p2align=" << Imm;
257
27
}
258
259
void WebAssemblyInstPrinter::printWebAssemblySignatureOperand(const MCInst *MI,
260
                                                              unsigned OpNo,
261
338
                                                              raw_ostream &O) {
262
338
  auto Imm = static_cast<unsigned>(MI->getOperand(OpNo).getImm());
263
338
  if (Imm != wasm::WASM_TYPE_NORESULT)
264
30
    O << WebAssembly::anyTypeToString(Imm);
265
338
}
266
267
// We have various enums representing a subset of these types, use this
268
// function to convert any of them to text.
269
6.29k
const char *llvm::WebAssembly::anyTypeToString(unsigned Ty) {
270
6.29k
  switch (Ty) {
271
6.29k
  case wasm::WASM_TYPE_I32:
272
3.44k
    return "i32";
273
6.29k
  case wasm::WASM_TYPE_I64:
274
744
    return "i64";
275
6.29k
  case wasm::WASM_TYPE_F32:
276
217
    return "f32";
277
6.29k
  case wasm::WASM_TYPE_F64:
278
563
    return "f64";
279
6.29k
  case wasm::WASM_TYPE_V128:
280
1.32k
    return "v128";
281
6.29k
  case wasm::WASM_TYPE_FUNCREF:
282
0
    return "funcref";
283
6.29k
  case wasm::WASM_TYPE_FUNC:
284
0
    return "func";
285
6.29k
  case wasm::WASM_TYPE_EXCEPT_REF:
286
1
    return "except_ref";
287
6.29k
  case wasm::WASM_TYPE_NORESULT:
288
0
    return "void";
289
6.29k
  default:
290
0
    return "invalid_type";
291
6.29k
  }
292
6.29k
}
293
294
6.25k
const char *llvm::WebAssembly::typeToString(wasm::ValType Ty) {
295
6.25k
  return anyTypeToString(static_cast<unsigned>(Ty));
296
6.25k
}