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 /// \brief 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 "WebAssembly.h" 18 #include "WebAssemblyMachineFunctionInfo.h" 19 #include "WebAssemblyRegisterInfo.h" 20 #include "WebAssemblySubtarget.h" 21 #include "InstPrinter/WebAssemblyInstPrinter.h" 22 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" 23 24 #include "llvm/ADT/SmallString.h" 25 #include "llvm/CodeGen/AsmPrinter.h" 26 #include "llvm/CodeGen/MachineInstr.h" 27 #include "llvm/IR/DataLayout.h" 28 #include "llvm/IR/DebugInfo.h" 29 #include "llvm/MC/MCStreamer.h" 30 #include "llvm/Support/Debug.h" 31 #include "llvm/Support/TargetRegistry.h" 32 #include "llvm/Support/raw_ostream.h" 33 34 using namespace llvm; 35 36 #define DEBUG_TYPE "asm-printer" 37 38 namespace { 39 40 class WebAssemblyAsmPrinter final : public AsmPrinter { 41 const WebAssemblyInstrInfo *TII; 42 43 public: 44 WebAssemblyAsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer) 45 : AsmPrinter(TM, std::move(Streamer)), TII(nullptr) {} 46 47 private: 48 const char *getPassName() const override { 49 return "WebAssembly Assembly Printer"; 50 } 51 52 //===------------------------------------------------------------------===// 53 // MachineFunctionPass Implementation. 54 //===------------------------------------------------------------------===// 55 56 void getAnalysisUsage(AnalysisUsage &AU) const override { 57 AsmPrinter::getAnalysisUsage(AU); 58 } 59 60 bool runOnMachineFunction(MachineFunction &MF) override { 61 TII = static_cast<const WebAssemblyInstrInfo *>( 62 MF.getSubtarget().getInstrInfo()); 63 return AsmPrinter::runOnMachineFunction(MF); 64 } 65 66 //===------------------------------------------------------------------===// 67 // AsmPrinter Implementation. 68 //===------------------------------------------------------------------===// 69 70 void EmitInstruction(const MachineInstr *MI) override; 71 }; 72 73 } // end anonymous namespace 74 75 //===----------------------------------------------------------------------===// 76 77 // Untyped, lower-case version of the opcode's name matching the names 78 // WebAssembly opcodes are expected to have. The tablegen names are uppercase 79 // and suffixed with their type (after an underscore). 80 static SmallString<32> Name(const WebAssemblyInstrInfo *TII, 81 const MachineInstr *MI) { 82 std::string N(StringRef(TII->getName(MI->getOpcode())).lower()); 83 std::string::size_type End = N.find('_'); 84 End = std::string::npos == End ? N.length() : End; 85 return SmallString<32>(&N[0], &N[End]); 86 } 87 88 void WebAssemblyAsmPrinter::EmitInstruction(const MachineInstr *MI) { 89 SmallString<128> Str; 90 raw_svector_ostream OS(Str); 91 92 unsigned NumDefs = MI->getDesc().getNumDefs(); 93 assert(NumDefs <= 1 && 94 "Instructions with multiple result values not implemented"); 95 96 if (NumDefs != 0) { 97 const MachineOperand &MO = MI->getOperand(0); 98 unsigned Reg = MO.getReg(); 99 OS << "(setlocal @" << TargetRegisterInfo::virtReg2Index(Reg) << ' '; 100 } 101 102 OS << '(' << Name(TII, MI); 103 for (const MachineOperand &MO : MI->uses()) 104 switch (MO.getType()) { 105 default: 106 llvm_unreachable("unexpected machine operand type"); 107 case MachineOperand::MO_Register: { 108 if (MO.isImplicit()) 109 continue; 110 unsigned Reg = MO.getReg(); 111 OS << " @" << TargetRegisterInfo::virtReg2Index(Reg); 112 } break; 113 case MachineOperand::MO_Immediate: { 114 OS << ' ' << MO.getImm(); 115 } break; 116 case MachineOperand::MO_FPImmediate: { 117 static const size_t BufBytes = 128; 118 char buf[BufBytes]; 119 APFloat FP = MO.getFPImm()->getValueAPF(); 120 if (FP.isNaN()) 121 assert((FP.bitwiseIsEqual(APFloat::getQNaN(FP.getSemantics())) || 122 FP.bitwiseIsEqual( 123 APFloat::getQNaN(FP.getSemantics(), /*Negative=*/true))) && 124 "convertToHexString handles neither SNaN nor NaN payloads"); 125 // Use C99's hexadecimal floating-point representation. 126 auto Written = 127 FP.convertToHexString(buf, /*hexDigits=*/0, /*upperCase=*/false, 128 APFloat::rmNearestTiesToEven); 129 (void)Written; 130 assert(Written != 0); 131 assert(Written < BufBytes); 132 OS << ' ' << buf; 133 } break; 134 } 135 OS << ')'; 136 137 if (NumDefs != 0) 138 OS << ')'; 139 140 OS << '\n'; 141 142 OutStreamer->EmitRawText(OS.str()); 143 } 144 145 // Force static initialization. 146 extern "C" void LLVMInitializeWebAssemblyAsmPrinter() { 147 RegisterAsmPrinter<WebAssemblyAsmPrinter> X(TheWebAssemblyTarget32); 148 RegisterAsmPrinter<WebAssemblyAsmPrinter> Y(TheWebAssemblyTarget64); 149 } 150