LCOV - code coverage report
Current view: top level - lib/Target/WebAssembly - WebAssemblyAsmPrinter.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 83 113 73.5 %
Date: 2018-10-20 13:21:21 Functions: 8 12 66.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //===-- WebAssemblyAsmPrinter.cpp - WebAssembly LLVM assembly writer ------===//
       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             : /// This file contains a printer that converts from our internal
      12             : /// representation of machine-dependent LLVM code to the WebAssembly assembly
      13             : /// language.
      14             : ///
      15             : //===----------------------------------------------------------------------===//
      16             : 
      17             : #include "WebAssemblyAsmPrinter.h"
      18             : #include "InstPrinter/WebAssemblyInstPrinter.h"
      19             : #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
      20             : #include "MCTargetDesc/WebAssemblyTargetStreamer.h"
      21             : #include "WebAssembly.h"
      22             : #include "WebAssemblyMCInstLower.h"
      23             : #include "WebAssemblyMachineFunctionInfo.h"
      24             : #include "WebAssemblyRegisterInfo.h"
      25             : #include "llvm/ADT/StringExtras.h"
      26             : #include "llvm/CodeGen/Analysis.h"
      27             : #include "llvm/CodeGen/AsmPrinter.h"
      28             : #include "llvm/CodeGen/MachineConstantPool.h"
      29             : #include "llvm/CodeGen/MachineInstr.h"
      30             : #include "llvm/CodeGen/MachineModuleInfoImpls.h"
      31             : #include "llvm/IR/DataLayout.h"
      32             : #include "llvm/IR/GlobalVariable.h"
      33             : #include "llvm/MC/MCContext.h"
      34             : #include "llvm/MC/MCSectionWasm.h"
      35             : #include "llvm/MC/MCStreamer.h"
      36             : #include "llvm/MC/MCSymbol.h"
      37             : #include "llvm/MC/MCSymbolWasm.h"
      38             : #include "llvm/Support/Debug.h"
      39             : #include "llvm/Support/TargetRegistry.h"
      40             : #include "llvm/Support/raw_ostream.h"
      41             : using namespace llvm;
      42             : 
      43             : #define DEBUG_TYPE "asm-printer"
      44             : 
      45             : //===----------------------------------------------------------------------===//
      46             : // Helpers.
      47             : //===----------------------------------------------------------------------===//
      48             : 
      49           0 : MVT WebAssemblyAsmPrinter::getRegType(unsigned RegNo) const {
      50           0 :   const TargetRegisterInfo *TRI = Subtarget->getRegisterInfo();
      51           0 :   const TargetRegisterClass *TRC = MRI->getRegClass(RegNo);
      52           0 :   for (MVT T : {MVT::i32, MVT::i64, MVT::f32, MVT::f64, MVT::v16i8, MVT::v8i16,
      53           0 :                 MVT::v4i32, MVT::v2i64, MVT::v4f32, MVT::v2f64})
      54           0 :     if (TRI->isTypeLegalForClass(*TRC, T))
      55           0 :       return T;
      56             :   LLVM_DEBUG(errs() << "Unknown type for register number: " << RegNo);
      57           0 :   llvm_unreachable("Unknown register type");
      58             :   return MVT::Other;
      59             : }
      60             : 
      61           0 : std::string WebAssemblyAsmPrinter::regToString(const MachineOperand &MO) {
      62           0 :   unsigned RegNo = MO.getReg();
      63             :   assert(TargetRegisterInfo::isVirtualRegister(RegNo) &&
      64             :          "Unlowered physical register encountered during assembly printing");
      65             :   assert(!MFI->isVRegStackified(RegNo));
      66           0 :   unsigned WAReg = MFI->getWAReg(RegNo);
      67             :   assert(WAReg != WebAssemblyFunctionInfo::UnusedReg);
      68           0 :   return '$' + utostr(WAReg);
      69             : }
      70             : 
      71           0 : WebAssemblyTargetStreamer *WebAssemblyAsmPrinter::getTargetStreamer() {
      72             :   MCTargetStreamer *TS = OutStreamer->getTargetStreamer();
      73           0 :   return static_cast<WebAssemblyTargetStreamer *>(TS);
      74             : }
      75             : 
      76             : //===----------------------------------------------------------------------===//
      77             : // WebAssemblyAsmPrinter Implementation.
      78             : //===----------------------------------------------------------------------===//
      79             : 
      80         301 : void WebAssemblyAsmPrinter::EmitEndOfAsmFile(Module &M) {
      81        3906 :   for (const auto &F : M) {
      82             :     // Emit function type info for all undefined functions
      83        7210 :     if (F.isDeclarationForLinker() && !F.isIntrinsic()) {
      84             :       SmallVector<MVT, 4> Results;
      85             :       SmallVector<MVT, 4> Params;
      86         556 :       ComputeSignatureVTs(F.getFunctionType(), F, TM, Params, Results);
      87         278 :       auto *Sym = cast<MCSymbolWasm>(getSymbol(&F));
      88         278 :       if (!Sym->getSignature()) {
      89          78 :         auto Signature = SignatureFromMVTs(Results, Params);
      90             :         Sym->setSignature(Signature.get());
      91             :         addSignature(std::move(Signature));
      92             :       }
      93             :       // FIXME: this was originally intended for post-linking and was only used
      94             :       // for imports that were only called indirectly (i.e. s2wasm could not
      95             :       // infer the type from a call). With object files it applies to all
      96             :       // imports. so fix the names and the tests, or rethink how import
      97             :       // delcarations work in asm files.
      98         278 :       getTargetStreamer()->emitIndirectFunctionType(Sym);
      99             : 
     100         556 :       if (TM.getTargetTriple().isOSBinFormatWasm() &&
     101         278 :           F.hasFnAttribute("wasm-import-module")) {
     102             :         StringRef Name =
     103           2 :             F.getFnAttribute("wasm-import-module").getValueAsString();
     104           2 :         getTargetStreamer()->emitImportModule(Sym, Name);
     105             :       }
     106             :     }
     107             :   }
     108         536 :   for (const auto &G : M.globals()) {
     109         235 :     if (!G.hasInitializer() && G.hasExternalLinkage()) {
     110          39 :       if (G.getValueType()->isSized()) {
     111          38 :         uint16_t Size = M.getDataLayout().getTypeAllocSize(G.getValueType());
     112          38 :         OutStreamer->emitELFSize(getSymbol(&G),
     113          38 :                                  MCConstantExpr::create(Size, OutContext));
     114             :       }
     115             :     }
     116             :   }
     117             : 
     118         301 :   if (const NamedMDNode *Named = M.getNamedMetadata("wasm.custom_sections")) {
     119          14 :     for (const Metadata *MD : Named->operands()) {
     120             :       const MDTuple *Tuple = dyn_cast<MDTuple>(MD);
     121          10 :       if (!Tuple || Tuple->getNumOperands() != 2)
     122           0 :         continue;
     123          10 :       const MDString *Name = dyn_cast<MDString>(Tuple->getOperand(0));
     124             :       const MDString *Contents = dyn_cast<MDString>(Tuple->getOperand(1));
     125          10 :       if (!Name || !Contents)
     126             :         continue;
     127             : 
     128          10 :       OutStreamer->PushSection();
     129          10 :       std::string SectionName = (".custom_section." + Name->getString()).str();
     130             :       MCSectionWasm *mySection =
     131          10 :           OutContext.getWasmSection(SectionName, SectionKind::getMetadata());
     132          10 :       OutStreamer->SwitchSection(mySection);
     133          10 :       OutStreamer->EmitBytes(Contents->getString());
     134          10 :       OutStreamer->PopSection();
     135             :     }
     136             :   }
     137         301 : }
     138             : 
     139        2982 : void WebAssemblyAsmPrinter::EmitConstantPool() {
     140             :   assert(MF->getConstantPool()->getConstants().empty() &&
     141             :          "WebAssembly disables constant pools");
     142        2982 : }
     143             : 
     144        2982 : void WebAssemblyAsmPrinter::EmitJumpTableInfo() {
     145             :   // Nothing to do; jump tables are incorporated into the instruction stream.
     146        2982 : }
     147             : 
     148        2982 : void WebAssemblyAsmPrinter::EmitFunctionBodyStart() {
     149        2982 :   const Function &F = MF->getFunction();
     150             :   SmallVector<MVT, 1> ResultVTs;
     151             :   SmallVector<MVT, 4> ParamVTs;
     152        5964 :   ComputeSignatureVTs(F.getFunctionType(), F, TM, ParamVTs, ResultVTs);
     153        2982 :   auto Signature = SignatureFromMVTs(ResultVTs, ParamVTs);
     154        2982 :   auto *WasmSym = cast<MCSymbolWasm>(CurrentFnSym);
     155             :   WasmSym->setSignature(Signature.get());
     156             :   addSignature(std::move(Signature));
     157             : 
     158             :   // FIXME: clean up how params and results are emitted (use signatures)
     159        5964 :   getTargetStreamer()->emitParam(CurrentFnSym, ParamVTs);
     160             : 
     161             :   // Emit the function index.
     162        5964 :   if (MDNode *Idx = F.getMetadata("wasm.index")) {
     163             :     assert(Idx->getNumOperands() == 1);
     164             : 
     165           2 :     getTargetStreamer()->emitIndIdx(AsmPrinter::lowerConstant(
     166           2 :         cast<ConstantAsMetadata>(Idx->getOperand(0))->getValue()));
     167             :   }
     168             : 
     169        5964 :   getTargetStreamer()->emitResult(CurrentFnSym, ResultVTs);
     170        5964 :   getTargetStreamer()->emitLocal(MFI->getLocals());
     171             : 
     172             :   AsmPrinter::EmitFunctionBodyStart();
     173        2982 : }
     174             : 
     175       31626 : void WebAssemblyAsmPrinter::EmitInstruction(const MachineInstr *MI) {
     176             :   LLVM_DEBUG(dbgs() << "EmitInstruction: " << *MI << '\n');
     177             : 
     178       63252 :   switch (MI->getOpcode()) {
     179             :   case WebAssembly::ARGUMENT_i32:
     180             :   case WebAssembly::ARGUMENT_i32_S:
     181             :   case WebAssembly::ARGUMENT_i64:
     182             :   case WebAssembly::ARGUMENT_i64_S:
     183             :   case WebAssembly::ARGUMENT_f32:
     184             :   case WebAssembly::ARGUMENT_f32_S:
     185             :   case WebAssembly::ARGUMENT_f64:
     186             :   case WebAssembly::ARGUMENT_f64_S:
     187             :   case WebAssembly::ARGUMENT_v16i8:
     188             :   case WebAssembly::ARGUMENT_v16i8_S:
     189             :   case WebAssembly::ARGUMENT_v8i16:
     190             :   case WebAssembly::ARGUMENT_v8i16_S:
     191             :   case WebAssembly::ARGUMENT_v4i32:
     192             :   case WebAssembly::ARGUMENT_v4i32_S:
     193             :   case WebAssembly::ARGUMENT_v2i64:
     194             :   case WebAssembly::ARGUMENT_v2i64_S:
     195             :   case WebAssembly::ARGUMENT_v4f32:
     196             :   case WebAssembly::ARGUMENT_v4f32_S:
     197             :   case WebAssembly::ARGUMENT_v2f64:
     198             :   case WebAssembly::ARGUMENT_v2f64_S:
     199             :     // These represent values which are live into the function entry, so there's
     200             :     // no instruction to emit.
     201             :     break;
     202         376 :   case WebAssembly::FALLTHROUGH_RETURN_I32:
     203             :   case WebAssembly::FALLTHROUGH_RETURN_I32_S:
     204             :   case WebAssembly::FALLTHROUGH_RETURN_I64:
     205             :   case WebAssembly::FALLTHROUGH_RETURN_I64_S:
     206             :   case WebAssembly::FALLTHROUGH_RETURN_F32:
     207             :   case WebAssembly::FALLTHROUGH_RETURN_F32_S:
     208             :   case WebAssembly::FALLTHROUGH_RETURN_F64:
     209             :   case WebAssembly::FALLTHROUGH_RETURN_F64_S:
     210             :   case WebAssembly::FALLTHROUGH_RETURN_v16i8:
     211             :   case WebAssembly::FALLTHROUGH_RETURN_v16i8_S:
     212             :   case WebAssembly::FALLTHROUGH_RETURN_v8i16:
     213             :   case WebAssembly::FALLTHROUGH_RETURN_v8i16_S:
     214             :   case WebAssembly::FALLTHROUGH_RETURN_v4i32:
     215             :   case WebAssembly::FALLTHROUGH_RETURN_v4i32_S:
     216             :   case WebAssembly::FALLTHROUGH_RETURN_v2i64:
     217             :   case WebAssembly::FALLTHROUGH_RETURN_v2i64_S:
     218             :   case WebAssembly::FALLTHROUGH_RETURN_v4f32:
     219             :   case WebAssembly::FALLTHROUGH_RETURN_v4f32_S:
     220             :   case WebAssembly::FALLTHROUGH_RETURN_v2f64:
     221             :   case WebAssembly::FALLTHROUGH_RETURN_v2f64_S: {
     222             :     // These instructions represent the implicit return at the end of a
     223             :     // function body. Always pops one value off the stack.
     224         376 :     if (isVerbose()) {
     225         172 :       OutStreamer->AddComment("fallthrough-return-value");
     226          86 :       OutStreamer->AddBlankLine();
     227             :     }
     228             :     break;
     229             :   }
     230         188 :   case WebAssembly::FALLTHROUGH_RETURN_VOID:
     231             :   case WebAssembly::FALLTHROUGH_RETURN_VOID_S:
     232             :     // This instruction represents the implicit return at the end of a
     233             :     // function body with no return value.
     234         188 :     if (isVerbose()) {
     235           8 :       OutStreamer->AddComment("fallthrough-return-void");
     236           4 :       OutStreamer->AddBlankLine();
     237             :     }
     238             :     break;
     239       24888 :   default: {
     240       24888 :     WebAssemblyMCInstLower MCInstLowering(OutContext, *this);
     241             :     MCInst TmpInst;
     242       24888 :     MCInstLowering.Lower(MI, TmpInst);
     243       49776 :     EmitToStreamer(*OutStreamer, TmpInst);
     244             :     break;
     245             :   }
     246             :   }
     247       31626 : }
     248             : 
     249         179 : const MCExpr *WebAssemblyAsmPrinter::lowerConstant(const Constant *CV) {
     250             :   if (const GlobalValue *GV = dyn_cast<GlobalValue>(CV))
     251         284 :     if (GV->getValueType()->isFunctionTy()) {
     252          78 :       return MCSymbolRefExpr::create(
     253          78 :           getSymbol(GV), MCSymbolRefExpr::VK_WebAssembly_FUNCTION, OutContext);
     254             :     }
     255         101 :   return AsmPrinter::lowerConstant(CV);
     256             : }
     257             : 
     258          14 : bool WebAssemblyAsmPrinter::PrintAsmOperand(const MachineInstr *MI,
     259             :                                             unsigned OpNo, unsigned AsmVariant,
     260             :                                             const char *ExtraCode,
     261             :                                             raw_ostream &OS) {
     262          14 :   if (AsmVariant != 0)
     263           0 :     report_fatal_error("There are no defined alternate asm variants");
     264             : 
     265             :   // First try the generic code, which knows about modifiers like 'c' and 'n'.
     266          14 :   if (!AsmPrinter::PrintAsmOperand(MI, OpNo, AsmVariant, ExtraCode, OS))
     267             :     return false;
     268             : 
     269          14 :   if (!ExtraCode) {
     270          14 :     const MachineOperand &MO = MI->getOperand(OpNo);
     271          14 :     switch (MO.getType()) {
     272          12 :     case MachineOperand::MO_Immediate:
     273          12 :       OS << MO.getImm();
     274          12 :       return false;
     275           0 :     case MachineOperand::MO_Register:
     276             :       // FIXME: only opcode that still contains registers, as required by
     277             :       // MachineInstr::getDebugVariable().
     278             :       assert(MI->getOpcode() == WebAssembly::INLINEASM);
     279           0 :       OS << regToString(MO);
     280           0 :       return false;
     281           2 :     case MachineOperand::MO_GlobalAddress:
     282           2 :       getSymbol(MO.getGlobal())->print(OS, MAI);
     283           4 :       printOffset(MO.getOffset(), OS);
     284           2 :       return false;
     285           0 :     case MachineOperand::MO_ExternalSymbol:
     286           0 :       GetExternalSymbolSymbol(MO.getSymbolName())->print(OS, MAI);
     287           0 :       printOffset(MO.getOffset(), OS);
     288           0 :       return false;
     289           0 :     case MachineOperand::MO_MachineBasicBlock:
     290           0 :       MO.getMBB()->getSymbol()->print(OS, MAI);
     291           0 :       return false;
     292             :     default:
     293             :       break;
     294             :     }
     295             :   }
     296             : 
     297             :   return true;
     298             : }
     299             : 
     300           0 : bool WebAssemblyAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
     301             :                                                   unsigned OpNo,
     302             :                                                   unsigned AsmVariant,
     303             :                                                   const char *ExtraCode,
     304             :                                                   raw_ostream &OS) {
     305           0 :   if (AsmVariant != 0)
     306           0 :     report_fatal_error("There are no defined alternate asm variants");
     307             : 
     308             :   // The current approach to inline asm is that "r" constraints are expressed
     309             :   // as local indices, rather than values on the operand stack. This simplifies
     310             :   // using "r" as it eliminates the need to push and pop the values in a
     311             :   // particular order, however it also makes it impossible to have an "m"
     312             :   // constraint. So we don't support it.
     313             : 
     314           0 :   return AsmPrinter::PrintAsmMemoryOperand(MI, OpNo, AsmVariant, ExtraCode, OS);
     315             : }
     316             : 
     317             : // Force static initialization.
     318       65841 : extern "C" void LLVMInitializeWebAssemblyAsmPrinter() {
     319       65841 :   RegisterAsmPrinter<WebAssemblyAsmPrinter> X(getTheWebAssemblyTarget32());
     320       65841 :   RegisterAsmPrinter<WebAssemblyAsmPrinter> Y(getTheWebAssemblyTarget64());
     321       65841 : }

Generated by: LCOV version 1.13