LCOV - code coverage report
Current view: top level - lib/Target/WebAssembly/InstPrinter - WebAssemblyInstPrinter.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 98 116 84.5 %
Date: 2018-10-20 13:21:21 Functions: 8 8 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //=- WebAssemblyInstPrinter.cpp - WebAssembly assembly instruction printing -=//
       2             : //
       3             : //                     The LLVM Compiler Infrastructure
       4             : //
       5             : // This file is distributed under the University of Illinois Open Source
       6             : // License. See LICENSE.TXT for details.
       7             : //
       8             : //===----------------------------------------------------------------------===//
       9             : ///
      10             : /// \file
      11             : /// Print MCInst instructions to wasm format.
      12             : ///
      13             : //===----------------------------------------------------------------------===//
      14             : 
      15             : #include "InstPrinter/WebAssemblyInstPrinter.h"
      16             : #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
      17             : #include "WebAssembly.h"
      18             : #include "WebAssemblyMachineFunctionInfo.h"
      19             : #include "llvm/ADT/SmallSet.h"
      20             : #include "llvm/ADT/StringExtras.h"
      21             : #include "llvm/CodeGen/TargetRegisterInfo.h"
      22             : #include "llvm/MC/MCExpr.h"
      23             : #include "llvm/MC/MCInst.h"
      24             : #include "llvm/MC/MCInstrInfo.h"
      25             : #include "llvm/MC/MCSubtargetInfo.h"
      26             : #include "llvm/MC/MCSymbol.h"
      27             : #include "llvm/Support/ErrorHandling.h"
      28             : #include "llvm/Support/FormattedStream.h"
      29             : using namespace llvm;
      30             : 
      31             : #define DEBUG_TYPE "asm-printer"
      32             : 
      33             : #include "WebAssemblyGenAsmWriter.inc"
      34             : 
      35         158 : WebAssemblyInstPrinter::WebAssemblyInstPrinter(const MCAsmInfo &MAI,
      36             :                                                const MCInstrInfo &MII,
      37         158 :                                                const MCRegisterInfo &MRI)
      38         316 :     : MCInstPrinter(MAI, MII, MRI), ControlFlowCounter(0) {}
      39             : 
      40        9648 : void WebAssemblyInstPrinter::printRegName(raw_ostream &OS,
      41             :                                           unsigned RegNo) const {
      42             :   assert(RegNo != WebAssemblyFunctionInfo::UnusedReg);
      43             :   // Note that there's an implicit get_local/set_local here!
      44        9648 :   OS << "$" << RegNo;
      45        9648 : }
      46             : 
      47       23991 : void WebAssemblyInstPrinter::printInst(const MCInst *MI, raw_ostream &OS,
      48             :                                        StringRef Annot,
      49             :                                        const MCSubtargetInfo &STI) {
      50             :   // Print the instruction (this uses the AsmStrings from the .td files).
      51       23991 :   printInstruction(MI, OS);
      52             : 
      53             :   // Print any additional variadic operands.
      54       23991 :   const MCInstrDesc &Desc = MII.get(MI->getOpcode());
      55       47982 :   if (Desc.isVariadic())
      56        1134 :     for (auto i = Desc.getNumOperands(), e = MI->getNumOperands(); i < e; ++i) {
      57             :       // FIXME: For CALL_INDIRECT_VOID, don't print a leading comma, because
      58             :       // we have an extra flags operand which is not currently printed, for
      59             :       // compatiblity reasons.
      60         727 :       if (i != 0 && ((MI->getOpcode() != WebAssembly::CALL_INDIRECT_VOID &&
      61           9 :                       MI->getOpcode() != WebAssembly::CALL_INDIRECT_VOID_S) ||
      62           9 :                      i != Desc.getNumOperands()))
      63         721 :         OS << ", ";
      64         727 :       printOperand(MI, i, OS);
      65             :     }
      66             : 
      67             :   // Print any added annotation.
      68       23991 :   printAnnotation(OS, Annot);
      69             : 
      70       23991 :   if (CommentStream) {
      71             :     // Observe any effects on the control flow stack, for use in annotating
      72             :     // control flow label references.
      73        1957 :     switch (MI->getOpcode()) {
      74             :     default:
      75             :       break;
      76           6 :     case WebAssembly::LOOP:
      77             :     case WebAssembly::LOOP_S: {
      78           6 :       printAnnotation(OS, "label" + utostr(ControlFlowCounter) + ':');
      79           6 :       ControlFlowStack.push_back(std::make_pair(ControlFlowCounter++, true));
      80           6 :       break;
      81             :     }
      82          10 :     case WebAssembly::BLOCK:
      83             :     case WebAssembly::BLOCK_S:
      84          10 :       ControlFlowStack.push_back(std::make_pair(ControlFlowCounter++, false));
      85          10 :       break;
      86           6 :     case WebAssembly::END_LOOP:
      87             :     case WebAssembly::END_LOOP_S:
      88             :       // Have to guard against an empty stack, in case of mismatched pairs
      89             :       // in assembly parsing.
      90           6 :       if (!ControlFlowStack.empty())
      91             :         ControlFlowStack.pop_back();
      92             :       break;
      93           9 :     case WebAssembly::END_BLOCK:
      94             :     case WebAssembly::END_BLOCK_S:
      95           9 :       if (!ControlFlowStack.empty())
      96           9 :         printAnnotation(
      97          18 :             OS, "label" + utostr(ControlFlowStack.pop_back_val().first) + ':');
      98             :       break;
      99             :     }
     100             : 
     101             :     // Annotate any control flow label references.
     102        1957 :     unsigned NumFixedOperands = Desc.NumOperands;
     103        1957 :     SmallSet<uint64_t, 8> Printed;
     104        3652 :     for (unsigned i = 0, e = MI->getNumOperands(); i < e; ++i) {
     105        3390 :       if (!(i < NumFixedOperands
     106        1680 :                 ? (Desc.OpInfo[i].OperandType ==
     107             :                    WebAssembly::OPERAND_BASIC_BLOCK)
     108          15 :                 : (Desc.TSFlags & WebAssemblyII::VariableOpImmediateIsLabel)))
     109        1676 :         continue;
     110          19 :       uint64_t Depth = MI->getOperand(i).getImm();
     111          19 :       if (!Printed.insert(Depth).second)
     112             :         continue;
     113          19 :       const auto &Pair = ControlFlowStack.rbegin()[Depth];
     114          68 :       printAnnotation(OS, utostr(Depth) + ": " + (Pair.second ? "up" : "down") +
     115          76 :                               " to label" + utostr(Pair.first));
     116             :     }
     117             :   }
     118       23991 : }
     119             : 
     120         212 : static std::string toString(const APFloat &FP) {
     121             :   // Print NaNs with custom payloads specially.
     122         438 :   if (FP.isNaN() && !FP.bitwiseIsEqual(APFloat::getQNaN(FP.getSemantics())) &&
     123           6 :       !FP.bitwiseIsEqual(
     124         224 :           APFloat::getQNaN(FP.getSemantics(), /*Negative=*/true))) {
     125           4 :     APInt AI = FP.bitcastToAPInt();
     126           8 :     return std::string(AI.isNegative() ? "-" : "") + "nan:0x" +
     127           8 :            utohexstr(AI.getZExtValue() &
     128           4 :                          (AI.getBitWidth() == 32 ? INT64_C(0x007fffff)
     129             :                                                  : INT64_C(0x000fffffffffffff)),
     130           4 :                      /*LowerCase=*/true);
     131             :   }
     132             : 
     133             :   // Use C99's hexadecimal floating-point representation.
     134             :   static const size_t BufBytes = 128;
     135             :   char buf[BufBytes];
     136         208 :   auto Written = FP.convertToHexString(
     137             :       buf, /*hexDigits=*/0, /*upperCase=*/false, APFloat::rmNearestTiesToEven);
     138             :   (void)Written;
     139             :   assert(Written != 0);
     140             :   assert(Written < BufBytes);
     141         208 :   return buf;
     142             : }
     143             : 
     144       46287 : void WebAssemblyInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
     145             :                                           raw_ostream &O) {
     146             :   const MCOperand &Op = MI->getOperand(OpNo);
     147       46287 :   if (Op.isReg()) {
     148             :     assert((OpNo < MII.get(MI->getOpcode()).getNumOperands() ||
     149             :             MII.get(MI->getOpcode()).TSFlags == 0) &&
     150             :            "WebAssembly variable_ops register ops don't use TSFlags");
     151       34940 :     unsigned WAReg = Op.getReg();
     152       34940 :     if (int(WAReg) >= 0)
     153        9648 :       printRegName(O, WAReg);
     154       75876 :     else if (OpNo >= MII.get(MI->getOpcode()).getNumDefs())
     155       12610 :       O << "$pop" << WebAssemblyFunctionInfo::getWARegStackId(WAReg);
     156       12682 :     else if (WAReg != WebAssemblyFunctionInfo::UnusedReg)
     157       12657 :       O << "$push" << WebAssemblyFunctionInfo::getWARegStackId(WAReg);
     158             :     else
     159          25 :       O << "$drop";
     160             :     // Add a '=' suffix if this is a def.
     161      104820 :     if (OpNo < MII.get(MI->getOpcode()).getNumDefs())
     162             :       O << '=';
     163       11347 :   } else if (Op.isImm()) {
     164             :     const MCInstrDesc &Desc = MII.get(MI->getOpcode());
     165             :     assert((OpNo < Desc.getNumOperands() ||
     166             :             (Desc.TSFlags & WebAssemblyII::VariableOpIsImmediate)) &&
     167             :            "WebAssemblyII::VariableOpIsImmediate should be set for "
     168             :            "variable_ops immediate ops");
     169             :     (void)Desc;
     170             :     // TODO: (MII.get(MI->getOpcode()).TSFlags &
     171             :     //        WebAssemblyII::VariableOpImmediateIsLabel)
     172             :     // can tell us whether this is an immediate referencing a label in the
     173             :     // control flow stack, and it may be nice to pretty-print.
     174       10250 :     O << Op.getImm();
     175        1097 :   } else if (Op.isFPImm()) {
     176         212 :     const MCInstrDesc &Desc = MII.get(MI->getOpcode());
     177             :     assert(OpNo < Desc.getNumOperands() &&
     178             :            "Unexpected floating-point immediate as a non-fixed operand");
     179             :     assert(Desc.TSFlags == 0 &&
     180             :            "WebAssembly variable_ops floating point ops don't use TSFlags");
     181         212 :     const MCOperandInfo &Info = Desc.OpInfo[OpNo];
     182         212 :     if (Info.OperandType == WebAssembly::OPERAND_F32IMM) {
     183             :       // TODO: MC converts all floating point immediate operands to double.
     184             :       // This is fine for numeric values, but may cause NaNs to change bits.
     185         206 :       O << ::toString(APFloat(float(Op.getFPImm())));
     186             :     } else {
     187             :       assert(Info.OperandType == WebAssembly::OPERAND_F64IMM);
     188         218 :       O << ::toString(APFloat(Op.getFPImm()));
     189             :     }
     190             :   } else {
     191             :     assert((OpNo < MII.get(MI->getOpcode()).getNumOperands() ||
     192             :             (MII.get(MI->getOpcode()).TSFlags &
     193             :              WebAssemblyII::VariableOpIsImmediate)) &&
     194             :            "WebAssemblyII::VariableOpIsImmediate should be set for "
     195             :            "variable_ops expr ops");
     196             :     assert(Op.isExpr() && "unknown operand kind in printOperand");
     197         885 :     Op.getExpr()->print(O, &MAI);
     198             :   }
     199       46287 : }
     200             : 
     201        3588 : void WebAssemblyInstPrinter::printWebAssemblyP2AlignOperand(const MCInst *MI,
     202             :                                                             unsigned OpNo,
     203             :                                                             raw_ostream &O) {
     204        3588 :   int64_t Imm = MI->getOperand(OpNo).getImm();
     205        3588 :   if (Imm == WebAssembly::GetDefaultP2Align(MI->getOpcode()))
     206             :     return;
     207         201 :   O << ":p2align=" << Imm;
     208             : }
     209             : 
     210         322 : void WebAssemblyInstPrinter::printWebAssemblySignatureOperand(const MCInst *MI,
     211             :                                                               unsigned OpNo,
     212             :                                                               raw_ostream &O) {
     213         322 :   int64_t Imm = MI->getOperand(OpNo).getImm();
     214         322 :   switch (WebAssembly::ExprType(Imm)) {
     215             :   case WebAssembly::ExprType::Void:
     216             :     break;
     217           6 :   case WebAssembly::ExprType::I32:
     218           6 :     O << "i32";
     219           6 :     break;
     220           0 :   case WebAssembly::ExprType::I64:
     221           0 :     O << "i64";
     222           0 :     break;
     223           0 :   case WebAssembly::ExprType::F32:
     224           0 :     O << "f32";
     225           0 :     break;
     226           0 :   case WebAssembly::ExprType::F64:
     227           0 :     O << "f64";
     228           0 :     break;
     229           0 :   case WebAssembly::ExprType::V128:
     230           0 :     O << "v128";
     231           0 :     break;
     232           0 :   case WebAssembly::ExprType::ExceptRef:
     233           0 :     O << "except_ref";
     234           0 :     break;
     235             :   }
     236         322 : }
     237             : 
     238        9459 : const char *llvm::WebAssembly::TypeToString(wasm::ValType Ty) {
     239        9459 :   switch (Ty) {
     240             :   case wasm::ValType::I32:
     241             :     return "i32";
     242         972 :   case wasm::ValType::I64:
     243         972 :     return "i64";
     244         532 :   case wasm::ValType::F32:
     245         532 :     return "f32";
     246         525 :   case wasm::ValType::F64:
     247         525 :     return "f64";
     248        2048 :   case wasm::ValType::V128:
     249        2048 :     return "v128";
     250           0 :   case wasm::ValType::EXCEPT_REF:
     251           0 :     return "except_ref";
     252             :   }
     253           0 :   llvm_unreachable("Unknown wasm::ValType");
     254             : }

Generated by: LCOV version 1.13