Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/lib/Target/WebAssembly/MCTargetDesc/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 "MCTargetDesc/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
236
    : MCInstPrinter(MAI, MII, MRI) {}
38
39
void WebAssemblyInstPrinter::printRegName(raw_ostream &OS,
40
16.7k
                                          unsigned RegNo) const {
41
16.7k
  assert(RegNo != WebAssemblyFunctionInfo::UnusedReg);
42
16.7k
  // Note that there's an implicit local.get/local.set here!
43
16.7k
  OS << "$" << RegNo;
44
16.7k
}
45
46
void WebAssemblyInstPrinter::printInst(const MCInst *MI, raw_ostream &OS,
47
                                       StringRef Annot,
48
46.7k
                                       const MCSubtargetInfo &STI) {
49
46.7k
  // Print the instruction (this uses the AsmStrings from the .td files).
50
46.7k
  printInstruction(MI, OS);
51
46.7k
52
46.7k
  // Print any additional variadic operands.
53
46.7k
  const MCInstrDesc &Desc = MII.get(MI->getOpcode());
54
46.7k
  if (Desc.isVariadic())
55
1.84k
    
for (auto I = Desc.getNumOperands(), E = MI->getNumOperands(); 766
I < E;
++I1.08k
) {
56
1.08k
      // FIXME: For CALL_INDIRECT_VOID, don't print a leading comma, because
57
1.08k
      // we have an extra flags operand which is not currently printed, for
58
1.08k
      // compatiblity reasons.
59
1.08k
      if (I != 0 && ((MI->getOpcode() != WebAssembly::CALL_INDIRECT_VOID &&
60
1.08k
                      
MI->getOpcode() != WebAssembly::CALL_INDIRECT_VOID_S1.06k
) ||
61
1.08k
                     
I != Desc.getNumOperands()19
))
62
1.06k
        OS << ", ";
63
1.08k
      printOperand(MI, I, OS);
64
1.08k
    }
65
46.7k
66
46.7k
  // Print any added annotation.
67
46.7k
  printAnnotation(OS, Annot);
68
46.7k
69
46.7k
  if (CommentStream) {
70
5.79k
    // Observe any effects on the control flow stack, for use in annotating
71
5.79k
    // control flow label references.
72
5.79k
    unsigned Opc = MI->getOpcode();
73
5.79k
    switch (Opc) {
74
5.79k
    default:
75
5.31k
      break;
76
5.79k
77
5.79k
    case WebAssembly::LOOP:
78
21
    case WebAssembly::LOOP_S:
79
21
      printAnnotation(OS, "label" + utostr(ControlFlowCounter) + ':');
80
21
      ControlFlowStack.push_back(std::make_pair(ControlFlowCounter++, true));
81
21
      break;
82
21
83
109
    case WebAssembly::BLOCK:
84
109
    case WebAssembly::BLOCK_S:
85
109
      ControlFlowStack.push_back(std::make_pair(ControlFlowCounter++, false));
86
109
      break;
87
109
88
109
    case WebAssembly::TRY:
89
76
    case WebAssembly::TRY_S:
90
76
      ControlFlowStack.push_back(std::make_pair(ControlFlowCounter++, false));
91
76
      EHPadStack.push_back(EHPadStackCounter++);
92
76
      LastSeenEHInst = TRY;
93
76
      break;
94
76
95
76
    case WebAssembly::END_LOOP:
96
20
    case WebAssembly::END_LOOP_S:
97
20
      if (ControlFlowStack.empty()) {
98
0
        printAnnotation(OS, "End marker mismatch!");
99
20
      } else {
100
20
        ControlFlowStack.pop_back();
101
20
      }
102
20
      break;
103
20
104
106
    case WebAssembly::END_BLOCK:
105
106
    case WebAssembly::END_BLOCK_S:
106
106
      if (ControlFlowStack.empty()) {
107
0
        printAnnotation(OS, "End marker mismatch!");
108
106
      } else {
109
106
        printAnnotation(
110
106
            OS, "label" + utostr(ControlFlowStack.pop_back_val().first) + ':');
111
106
      }
112
106
      break;
113
106
114
106
    case WebAssembly::END_TRY:
115
75
    case WebAssembly::END_TRY_S:
116
75
      if (ControlFlowStack.empty()) {
117
0
        printAnnotation(OS, "End marker mismatch!");
118
75
      } else {
119
75
        printAnnotation(
120
75
            OS, "label" + utostr(ControlFlowStack.pop_back_val().first) + ':');
121
75
        LastSeenEHInst = END_TRY;
122
75
      }
123
75
      break;
124
75
125
75
    case WebAssembly::CATCH:
126
75
    case WebAssembly::CATCH_S:
127
75
      if (EHPadStack.empty()) {
128
0
        printAnnotation(OS, "try-catch mismatch!");
129
75
      } else {
130
75
        printAnnotation(OS, "catch" + utostr(EHPadStack.pop_back_val()) + ':');
131
75
      }
132
75
      break;
133
5.79k
    }
134
5.79k
135
5.79k
    // Annotate any control flow label references.
136
5.79k
137
5.79k
    // rethrow instruction does not take any depth argument and rethrows to the
138
5.79k
    // nearest enclosing catch scope, if any. If there's no enclosing catch
139
5.79k
    // scope, it throws up to the caller.
140
5.79k
    if (Opc == WebAssembly::RETHROW || 
Opc == WebAssembly::RETHROW_S5.73k
) {
141
64
      if (EHPadStack.empty()) {
142
52
        printAnnotation(OS, "to caller");
143
52
      } else {
144
12
        printAnnotation(OS, "down to catch" + utostr(EHPadStack.back()));
145
12
      }
146
64
147
5.73k
    } else {
148
5.73k
      unsigned NumFixedOperands = Desc.NumOperands;
149
5.73k
      SmallSet<uint64_t, 8> Printed;
150
11.4k
      for (unsigned I = 0, E = MI->getNumOperands(); I < E; 
++I5.70k
) {
151
5.70k
        // See if this operand denotes a basic block target.
152
5.70k
        if (I < NumFixedOperands) {
153
5.63k
          // A non-variable_ops operand, check its type.
154
5.63k
          if (Desc.OpInfo[I].OperandType != WebAssembly::OPERAND_BASIC_BLOCK)
155
5.46k
            continue;
156
77
        } else {
157
77
          // A variable_ops operand, which currently can be immediates (used in
158
77
          // br_table) which are basic block targets, or for call instructions
159
77
          // when using -wasm-keep-registers (in which case they are registers,
160
77
          // and should not be processed).
161
77
          if (!MI->getOperand(I).isImm())
162
69
            continue;
163
170
        }
164
170
        uint64_t Depth = MI->getOperand(I).getImm();
165
170
        if (!Printed.insert(Depth).second)
166
0
          continue;
167
170
        if (Depth >= ControlFlowStack.size()) {
168
3
          printAnnotation(OS, "Invalid depth argument!");
169
167
        } else {
170
167
          const auto &Pair = ControlFlowStack.rbegin()[Depth];
171
167
          printAnnotation(OS, utostr(Depth) + ": " +
172
167
                                  (Pair.second ? 
"up"21
:
"down"146
) + " to label" +
173
167
                                  utostr(Pair.first));
174
167
        }
175
170
      }
176
5.73k
    }
177
5.79k
  }
178
46.7k
}
179
180
256
static std::string toString(const APFloat &FP) {
181
256
  // Print NaNs with custom payloads specially.
182
256
  if (FP.isNaN() && 
!FP.bitwiseIsEqual(APFloat::getQNaN(FP.getSemantics()))7
&&
183
256
      !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
254
193
254
  // Use C99's hexadecimal floating-point representation.
194
254
  static const size_t BufBytes = 128;
195
254
  char Buf[BufBytes];
196
254
  auto Written = FP.convertToHexString(
197
254
      Buf, /*HexDigits=*/0, /*UpperCase=*/false, APFloat::rmNearestTiesToEven);
198
254
  (void)Written;
199
254
  assert(Written != 0);
200
254
  assert(Written < BufBytes);
201
254
  return Buf;
202
254
}
203
204
void WebAssemblyInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
205
93.9k
                                          raw_ostream &O) {
206
93.9k
  const MCOperand &Op = MI->getOperand(OpNo);
207
93.9k
  if (Op.isReg()) {
208
69.9k
    unsigned WAReg = Op.getReg();
209
69.9k
    if (int(WAReg) >= 0)
210
16.7k
      printRegName(O, WAReg);
211
53.2k
    else if (OpNo >= MII.get(MI->getOpcode()).getNumDefs())
212
26.5k
      O << "$pop" << WebAssemblyFunctionInfo::getWARegStackId(WAReg);
213
26.7k
    else if (WAReg != WebAssemblyFunctionInfo::UnusedReg)
214
26.5k
      O << "$push" << WebAssemblyFunctionInfo::getWARegStackId(WAReg);
215
113
    else
216
113
      O << "$drop";
217
69.9k
    // Add a '=' suffix if this is a def.
218
69.9k
    if (OpNo < MII.get(MI->getOpcode()).getNumDefs())
219
27.5k
      O << '=';
220
69.9k
  } else 
if (23.9k
Op.isImm()23.9k
) {
221
22.0k
    O << Op.getImm();
222
22.0k
  } else 
if (1.93k
Op.isFPImm()1.93k
) {
223
256
    const MCInstrDesc &Desc = MII.get(MI->getOpcode());
224
256
    const MCOperandInfo &Info = Desc.OpInfo[OpNo];
225
256
    if (Info.OperandType == WebAssembly::OPERAND_F32IMM) {
226
131
      // TODO: MC converts all floating point immediate operands to double.
227
131
      // This is fine for numeric values, but may cause NaNs to change bits.
228
131
      O << ::toString(APFloat(float(Op.getFPImm())));
229
131
    } else {
230
125
      assert(Info.OperandType == WebAssembly::OPERAND_F64IMM);
231
125
      O << ::toString(APFloat(Op.getFPImm()));
232
125
    }
233
1.68k
  } else {
234
1.68k
    assert(Op.isExpr() && "unknown operand kind in printOperand");
235
1.68k
    Op.getExpr()->print(O, &MAI);
236
1.68k
  }
237
93.9k
}
238
239
void WebAssemblyInstPrinter::printBrList(const MCInst *MI, unsigned OpNo,
240
3
                                         raw_ostream &O) {
241
3
  O << "{";
242
14
  for (unsigned I = OpNo, E = MI->getNumOperands(); I != E; 
++I11
) {
243
11
    if (I != OpNo)
244
8
      O << ", ";
245
11
    O << MI->getOperand(I).getImm();
246
11
  }
247
3
  O << "}";
248
3
}
249
250
void WebAssemblyInstPrinter::printWebAssemblyP2AlignOperand(const MCInst *MI,
251
                                                            unsigned OpNo,
252
5.54k
                                                            raw_ostream &O) {
253
5.54k
  int64_t Imm = MI->getOperand(OpNo).getImm();
254
5.54k
  if (Imm == WebAssembly::GetDefaultP2Align(MI->getOpcode()))
255
5.47k
    return;
256
68
  O << ":p2align=" << Imm;
257
68
}
258
259
void WebAssemblyInstPrinter::printWebAssemblySignatureOperand(const MCInst *MI,
260
                                                              unsigned OpNo,
261
502
                                                              raw_ostream &O) {
262
502
  auto Imm = static_cast<unsigned>(MI->getOperand(OpNo).getImm());
263
502
  if (Imm != wasm::WASM_TYPE_NORESULT)
264
57
    O << WebAssembly::anyTypeToString(Imm);
265
502
}
266
267
// We have various enums representing a subset of these types, use this
268
// function to convert any of them to text.
269
15.4k
const char *llvm::WebAssembly::anyTypeToString(unsigned Ty) {
270
15.4k
  switch (Ty) {
271
15.4k
  case wasm::WASM_TYPE_I32:
272
8.63k
    return "i32";
273
15.4k
  case wasm::WASM_TYPE_I64:
274
1.37k
    return "i64";
275
15.4k
  case wasm::WASM_TYPE_F32:
276
977
    return "f32";
277
15.4k
  case wasm::WASM_TYPE_F64:
278
918
    return "f64";
279
15.4k
  case wasm::WASM_TYPE_V128:
280
3.50k
    return "v128";
281
15.4k
  case wasm::WASM_TYPE_FUNCREF:
282
0
    return "funcref";
283
15.4k
  case wasm::WASM_TYPE_FUNC:
284
0
    return "func";
285
15.4k
  case wasm::WASM_TYPE_EXNREF:
286
9
    return "exnref";
287
15.4k
  case wasm::WASM_TYPE_NORESULT:
288
0
    return "void";
289
15.4k
  default:
290
1
    return "invalid_type";
291
15.4k
  }
292
15.4k
}
293
294
15.3k
const char *llvm::WebAssembly::typeToString(wasm::ValType Ty) {
295
15.3k
  return anyTypeToString(static_cast<unsigned>(Ty));
296
15.3k
}