Home | History | Annotate | Download | only in InstPrinter
      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 /// \brief 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/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 #include "llvm/Target/TargetRegisterInfo.h"
     29 using namespace llvm;
     30 
     31 #define DEBUG_TYPE "asm-printer"
     32 
     33 #include "WebAssemblyGenAsmWriter.inc"
     34 
     35 WebAssemblyInstPrinter::WebAssemblyInstPrinter(const MCAsmInfo &MAI,
     36                                                const MCInstrInfo &MII,
     37                                                const MCRegisterInfo &MRI)
     38     : MCInstPrinter(MAI, MII, MRI), ControlFlowCounter(0) {}
     39 
     40 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   OS << "$" << RegNo;
     45 }
     46 
     47 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   printInstruction(MI, OS);
     52 
     53   // Print any additional variadic operands.
     54   const MCInstrDesc &Desc = MII.get(MI->getOpcode());
     55   if (Desc.isVariadic())
     56     for (auto i = Desc.getNumOperands(), e = MI->getNumOperands(); i < e; ++i) {
     57       if (i != 0)
     58         OS << ", ";
     59       printOperand(MI, i, OS);
     60     }
     61 
     62   // Print any added annotation.
     63   printAnnotation(OS, Annot);
     64 
     65   if (CommentStream) {
     66     // Observe any effects on the control flow stack, for use in annotating
     67     // control flow label references.
     68     switch (MI->getOpcode()) {
     69     default:
     70       break;
     71     case WebAssembly::LOOP: {
     72       // Grab the TopLabel value first so that labels print in numeric order.
     73       uint64_t TopLabel = ControlFlowCounter++;
     74       ControlFlowStack.push_back(std::make_pair(ControlFlowCounter++, false));
     75       printAnnotation(OS, "label" + utostr(TopLabel) + ':');
     76       ControlFlowStack.push_back(std::make_pair(TopLabel, true));
     77       break;
     78     }
     79     case WebAssembly::BLOCK:
     80       ControlFlowStack.push_back(std::make_pair(ControlFlowCounter++, false));
     81       break;
     82     case WebAssembly::END_LOOP:
     83       ControlFlowStack.pop_back();
     84       printAnnotation(
     85           OS, "label" + utostr(ControlFlowStack.pop_back_val().first) + ':');
     86       break;
     87     case WebAssembly::END_BLOCK:
     88       printAnnotation(
     89           OS, "label" + utostr(ControlFlowStack.pop_back_val().first) + ':');
     90       break;
     91     }
     92 
     93     // Annotate any control flow label references.
     94     unsigned NumFixedOperands = Desc.NumOperands;
     95     SmallSet<uint64_t, 8> Printed;
     96     for (unsigned i = 0, e = MI->getNumOperands(); i < e; ++i) {
     97       const MCOperandInfo &Info = Desc.OpInfo[i];
     98       if (!(i < NumFixedOperands
     99                 ? (Info.OperandType == WebAssembly::OPERAND_BASIC_BLOCK)
    100                 : (Desc.TSFlags & WebAssemblyII::VariableOpImmediateIsLabel)))
    101         continue;
    102       uint64_t Depth = MI->getOperand(i).getImm();
    103       if (!Printed.insert(Depth).second)
    104         continue;
    105       const auto &Pair = ControlFlowStack.rbegin()[Depth];
    106       printAnnotation(OS, utostr(Depth) + ": " + (Pair.second ? "up" : "down") +
    107                               " to label" + utostr(Pair.first));
    108     }
    109   }
    110 }
    111 
    112 static std::string toString(const APFloat &FP) {
    113   // Print NaNs with custom payloads specially.
    114   if (FP.isNaN() &&
    115       !FP.bitwiseIsEqual(APFloat::getQNaN(FP.getSemantics())) &&
    116       !FP.bitwiseIsEqual(APFloat::getQNaN(FP.getSemantics(), /*Negative=*/true))) {
    117     APInt AI = FP.bitcastToAPInt();
    118     return
    119         std::string(AI.isNegative() ? "-" : "") + "nan:0x" +
    120         utohexstr(AI.getZExtValue() &
    121                   (AI.getBitWidth() == 32 ? INT64_C(0x007fffff) :
    122                                             INT64_C(0x000fffffffffffff)),
    123                   /*LowerCase=*/true);
    124   }
    125 
    126   // Use C99's hexadecimal floating-point representation.
    127   static const size_t BufBytes = 128;
    128   char buf[BufBytes];
    129   auto Written = FP.convertToHexString(
    130       buf, /*hexDigits=*/0, /*upperCase=*/false, APFloat::rmNearestTiesToEven);
    131   (void)Written;
    132   assert(Written != 0);
    133   assert(Written < BufBytes);
    134   return buf;
    135 }
    136 
    137 void WebAssemblyInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
    138                                           raw_ostream &O) {
    139   const MCOperand &Op = MI->getOperand(OpNo);
    140   if (Op.isReg()) {
    141     assert((OpNo < MII.get(MI->getOpcode()).getNumOperands() ||
    142             MII.get(MI->getOpcode()).TSFlags == 0) &&
    143            "WebAssembly variable_ops register ops don't use TSFlags");
    144     unsigned WAReg = Op.getReg();
    145     if (int(WAReg) >= 0)
    146       printRegName(O, WAReg);
    147     else if (OpNo >= MII.get(MI->getOpcode()).getNumDefs())
    148       O << "$pop" << WebAssemblyFunctionInfo::getWARegStackId(WAReg);
    149     else if (WAReg != WebAssemblyFunctionInfo::UnusedReg)
    150       O << "$push" << WebAssemblyFunctionInfo::getWARegStackId(WAReg);
    151     else
    152       O << "$drop";
    153     // Add a '=' suffix if this is a def.
    154     if (OpNo < MII.get(MI->getOpcode()).getNumDefs())
    155       O << '=';
    156   } else if (Op.isImm()) {
    157     assert((OpNo < MII.get(MI->getOpcode()).getNumOperands() ||
    158             (MII.get(MI->getOpcode()).TSFlags &
    159              WebAssemblyII::VariableOpIsImmediate)) &&
    160            "WebAssemblyII::VariableOpIsImmediate should be set for "
    161            "variable_ops immediate ops");
    162     // TODO: (MII.get(MI->getOpcode()).TSFlags &
    163     //        WebAssemblyII::VariableOpImmediateIsLabel)
    164     // can tell us whether this is an immediate referencing a label in the
    165     // control flow stack, and it may be nice to pretty-print.
    166     O << Op.getImm();
    167   } else if (Op.isFPImm()) {
    168     const MCInstrDesc &Desc = MII.get(MI->getOpcode());
    169     assert(OpNo < Desc.getNumOperands() &&
    170            "Unexpected floating-point immediate as a non-fixed operand");
    171     assert(Desc.TSFlags == 0 &&
    172            "WebAssembly variable_ops floating point ops don't use TSFlags");
    173     const MCOperandInfo &Info = Desc.OpInfo[OpNo];
    174     if (Info.OperandType == WebAssembly::OPERAND_FP32IMM) {
    175       // TODO: MC converts all floating point immediate operands to double.
    176       // This is fine for numeric values, but may cause NaNs to change bits.
    177       O << toString(APFloat(float(Op.getFPImm())));
    178     } else {
    179       assert(Info.OperandType == WebAssembly::OPERAND_FP64IMM);
    180       O << toString(APFloat(Op.getFPImm()));
    181     }
    182   } else {
    183     assert((OpNo < MII.get(MI->getOpcode()).getNumOperands() ||
    184             (MII.get(MI->getOpcode()).TSFlags &
    185              WebAssemblyII::VariableOpIsImmediate)) &&
    186            "WebAssemblyII::VariableOpIsImmediate should be set for "
    187            "variable_ops expr ops");
    188     assert(Op.isExpr() && "unknown operand kind in printOperand");
    189     Op.getExpr()->print(O, &MAI);
    190   }
    191 }
    192 
    193 void
    194 WebAssemblyInstPrinter::printWebAssemblyP2AlignOperand(const MCInst *MI,
    195                                                        unsigned OpNo,
    196                                                        raw_ostream &O) {
    197   int64_t Imm = MI->getOperand(OpNo).getImm();
    198   if (Imm == WebAssembly::GetDefaultP2Align(MI->getOpcode()))
    199     return;
    200   O << ":p2align=" << Imm;
    201 }
    202 
    203 const char *llvm::WebAssembly::TypeToString(MVT Ty) {
    204   switch (Ty.SimpleTy) {
    205   case MVT::i32:
    206     return "i32";
    207   case MVT::i64:
    208     return "i64";
    209   case MVT::f32:
    210     return "f32";
    211   case MVT::f64:
    212     return "f64";
    213   default:
    214     llvm_unreachable("unsupported type");
    215   }
    216 }
    217