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/MachineConstantPool.h" 27 #include "llvm/CodeGen/MachineInstr.h" 28 #include "llvm/IR/DataLayout.h" 29 #include "llvm/IR/DebugInfo.h" 30 #include "llvm/MC/MCStreamer.h" 31 #include "llvm/MC/MCSymbol.h" 32 #include "llvm/Support/Debug.h" 33 #include "llvm/Support/TargetRegistry.h" 34 #include "llvm/Support/raw_ostream.h" 35 36 using namespace llvm; 37 38 #define DEBUG_TYPE "asm-printer" 39 40 namespace { 41 42 class WebAssemblyAsmPrinter final : public AsmPrinter { 43 const WebAssemblyInstrInfo *TII; 44 45 public: 46 WebAssemblyAsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer) 47 : AsmPrinter(TM, std::move(Streamer)), TII(nullptr) {} 48 49 private: 50 const char *getPassName() const override { 51 return "WebAssembly Assembly Printer"; 52 } 53 54 //===------------------------------------------------------------------===// 55 // MachineFunctionPass Implementation. 56 //===------------------------------------------------------------------===// 57 58 void getAnalysisUsage(AnalysisUsage &AU) const override { 59 AsmPrinter::getAnalysisUsage(AU); 60 } 61 62 bool runOnMachineFunction(MachineFunction &MF) override { 63 TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 64 return AsmPrinter::runOnMachineFunction(MF); 65 } 66 67 //===------------------------------------------------------------------===// 68 // AsmPrinter Implementation. 69 //===------------------------------------------------------------------===// 70 71 void EmitConstantPool() override; 72 void EmitFunctionEntryLabel() override; 73 void EmitFunctionBodyStart() override; 74 void EmitFunctionBodyEnd() override; 75 76 void EmitInstruction(const MachineInstr *MI) override; 77 }; 78 79 } // end anonymous namespace 80 81 //===----------------------------------------------------------------------===// 82 83 // Untyped, lower-case version of the opcode's name matching the names 84 // WebAssembly opcodes are expected to have. The tablegen names are uppercase 85 // and suffixed with their type (after an underscore). 86 static SmallString<32> Name(const WebAssemblyInstrInfo *TII, 87 const MachineInstr *MI) { 88 std::string N(StringRef(TII->getName(MI->getOpcode())).lower()); 89 std::string::size_type End = N.rfind('_'); 90 End = std::string::npos == End ? N.length() : End; 91 return SmallString<32>(&N[0], &N[End]); 92 } 93 94 static std::string toSymbol(StringRef S) { return ("$" + S).str(); } 95 96 static const char *toType(const Type *Ty) { 97 switch (Ty->getTypeID()) { 98 default: break; 99 case Type::FloatTyID: return "f32"; 100 case Type::DoubleTyID: return "f64"; 101 case Type::IntegerTyID: 102 switch (Ty->getIntegerBitWidth()) { 103 case 32: return "i32"; 104 case 64: return "i64"; 105 default: break; 106 } 107 } 108 DEBUG(dbgs() << "Invalid type "; Ty->print(dbgs()); dbgs() << '\n'); 109 llvm_unreachable("invalid type"); 110 return "<invalid>"; 111 } 112 113 void WebAssemblyAsmPrinter::EmitConstantPool() { 114 assert(MF->getConstantPool()->getConstants().empty() && 115 "WebAssembly disables constant pools"); 116 } 117 118 void WebAssemblyAsmPrinter::EmitFunctionEntryLabel() { 119 SmallString<128> Str; 120 raw_svector_ostream OS(Str); 121 122 CurrentFnSym->redefineIfPossible(); 123 124 // The function label could have already been emitted if two symbols end up 125 // conflicting due to asm renaming. Detect this and emit an error. 126 if (CurrentFnSym->isVariable()) 127 report_fatal_error("'" + Twine(CurrentFnSym->getName()) + 128 "' is a protected alias"); 129 if (CurrentFnSym->isDefined()) 130 report_fatal_error("'" + Twine(CurrentFnSym->getName()) + 131 "' label emitted multiple times to assembly file"); 132 133 OS << "(func " << toSymbol(CurrentFnSym->getName()); 134 OutStreamer->EmitRawText(OS.str()); 135 } 136 137 void WebAssemblyAsmPrinter::EmitFunctionBodyStart() { 138 SmallString<128> Str; 139 raw_svector_ostream OS(Str); 140 const Function *F = MF->getFunction(); 141 for (const Argument &A : F->args()) 142 OS << " (param " << toType(A.getType()) << ')'; 143 const Type *Rt = F->getReturnType(); 144 if (!Rt->isVoidTy()) 145 OS << " (result " << toType(Rt) << ')'; 146 OS << '\n'; 147 OutStreamer->EmitRawText(OS.str()); 148 } 149 150 void WebAssemblyAsmPrinter::EmitFunctionBodyEnd() { 151 SmallString<128> Str; 152 raw_svector_ostream OS(Str); 153 OS << ") ;; end func " << toSymbol(CurrentFnSym->getName()) << '\n'; 154 OutStreamer->EmitRawText(OS.str()); 155 } 156 157 void WebAssemblyAsmPrinter::EmitInstruction(const MachineInstr *MI) { 158 DEBUG(dbgs() << "EmitInstruction: " << *MI << '\n'); 159 SmallString<128> Str; 160 raw_svector_ostream OS(Str); 161 162 unsigned NumDefs = MI->getDesc().getNumDefs(); 163 assert(NumDefs <= 1 && 164 "Instructions with multiple result values not implemented"); 165 166 OS << '\t'; 167 168 if (NumDefs != 0) { 169 const MachineOperand &MO = MI->getOperand(0); 170 unsigned Reg = MO.getReg(); 171 OS << "(setlocal @" << TargetRegisterInfo::virtReg2Index(Reg) << ' '; 172 } 173 174 OS << '(' << Name(TII, MI); 175 for (const MachineOperand &MO : MI->uses()) 176 switch (MO.getType()) { 177 default: 178 llvm_unreachable("unexpected machine operand type"); 179 case MachineOperand::MO_Register: { 180 if (MO.isImplicit()) 181 continue; 182 unsigned Reg = MO.getReg(); 183 OS << " @" << TargetRegisterInfo::virtReg2Index(Reg); 184 } break; 185 case MachineOperand::MO_Immediate: { 186 OS << ' ' << MO.getImm(); 187 } break; 188 case MachineOperand::MO_FPImmediate: { 189 static const size_t BufBytes = 128; 190 char buf[BufBytes]; 191 APFloat FP = MO.getFPImm()->getValueAPF(); 192 if (FP.isNaN()) 193 assert((FP.bitwiseIsEqual(APFloat::getQNaN(FP.getSemantics())) || 194 FP.bitwiseIsEqual( 195 APFloat::getQNaN(FP.getSemantics(), /*Negative=*/true))) && 196 "convertToHexString handles neither SNaN nor NaN payloads"); 197 // Use C99's hexadecimal floating-point representation. 198 auto Written = 199 FP.convertToHexString(buf, /*hexDigits=*/0, /*upperCase=*/false, 200 APFloat::rmNearestTiesToEven); 201 (void)Written; 202 assert(Written != 0); 203 assert(Written < BufBytes); 204 OS << ' ' << buf; 205 } break; 206 case MachineOperand::MO_GlobalAddress: { 207 OS << ' ' << toSymbol(MO.getGlobal()->getName()); 208 } break; 209 } 210 OS << ')'; 211 212 if (NumDefs != 0) 213 OS << ')'; 214 215 OS << '\n'; 216 217 OutStreamer->EmitRawText(OS.str()); 218 } 219 220 // Force static initialization. 221 extern "C" void LLVMInitializeWebAssemblyAsmPrinter() { 222 RegisterAsmPrinter<WebAssemblyAsmPrinter> X(TheWebAssemblyTarget32); 223 RegisterAsmPrinter<WebAssemblyAsmPrinter> Y(TheWebAssemblyTarget64); 224 } 225