1b9073fb2SJF Bastien //===-- WebAssemblyAsmPrinter.cpp - WebAssembly LLVM assembly writer ------===// 2b9073fb2SJF Bastien // 3b9073fb2SJF Bastien // The LLVM Compiler Infrastructure 4b9073fb2SJF Bastien // 5b9073fb2SJF Bastien // This file is distributed under the University of Illinois Open Source 6b9073fb2SJF Bastien // License. See LICENSE.TXT for details. 7b9073fb2SJF Bastien // 8b9073fb2SJF Bastien //===----------------------------------------------------------------------===// 9b9073fb2SJF Bastien /// 10b9073fb2SJF Bastien /// \file 11b9073fb2SJF Bastien /// \brief This file contains a printer that converts from our internal 12b9073fb2SJF Bastien /// representation of machine-dependent LLVM code to the WebAssembly assembly 13b9073fb2SJF Bastien /// language. 14b9073fb2SJF Bastien /// 15b9073fb2SJF Bastien //===----------------------------------------------------------------------===// 16b9073fb2SJF Bastien 17b9073fb2SJF Bastien #include "WebAssembly.h" 18b9073fb2SJF Bastien #include "WebAssemblyMachineFunctionInfo.h" 19b9073fb2SJF Bastien #include "WebAssemblyRegisterInfo.h" 20b9073fb2SJF Bastien #include "WebAssemblySubtarget.h" 21b9073fb2SJF Bastien #include "InstPrinter/WebAssemblyInstPrinter.h" 22b9073fb2SJF Bastien #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" 23b9073fb2SJF Bastien 24b9073fb2SJF Bastien #include "llvm/ADT/SmallString.h" 25b9073fb2SJF Bastien #include "llvm/CodeGen/AsmPrinter.h" 26b9073fb2SJF Bastien #include "llvm/CodeGen/MachineInstr.h" 27b9073fb2SJF Bastien #include "llvm/IR/DataLayout.h" 28b9073fb2SJF Bastien #include "llvm/IR/DebugInfo.h" 29b9073fb2SJF Bastien #include "llvm/MC/MCStreamer.h" 30*b6091dfeSJF Bastien #include "llvm/MC/MCSymbol.h" 31b9073fb2SJF Bastien #include "llvm/Support/Debug.h" 32b9073fb2SJF Bastien #include "llvm/Support/TargetRegistry.h" 33b9073fb2SJF Bastien #include "llvm/Support/raw_ostream.h" 34b9073fb2SJF Bastien 35b9073fb2SJF Bastien using namespace llvm; 36b9073fb2SJF Bastien 37b9073fb2SJF Bastien #define DEBUG_TYPE "asm-printer" 38b9073fb2SJF Bastien 39b9073fb2SJF Bastien namespace { 40b9073fb2SJF Bastien 41b9073fb2SJF Bastien class WebAssemblyAsmPrinter final : public AsmPrinter { 42600aee98SJF Bastien const WebAssemblyInstrInfo *TII; 43600aee98SJF Bastien 44b9073fb2SJF Bastien public: 45b9073fb2SJF Bastien WebAssemblyAsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer) 46600aee98SJF Bastien : AsmPrinter(TM, std::move(Streamer)), TII(nullptr) {} 47b9073fb2SJF Bastien 48b9073fb2SJF Bastien private: 49b9073fb2SJF Bastien const char *getPassName() const override { 50b9073fb2SJF Bastien return "WebAssembly Assembly Printer"; 51b9073fb2SJF Bastien } 52b9073fb2SJF Bastien 53b9073fb2SJF Bastien //===------------------------------------------------------------------===// 54b9073fb2SJF Bastien // MachineFunctionPass Implementation. 55b9073fb2SJF Bastien //===------------------------------------------------------------------===// 56b9073fb2SJF Bastien 57b9073fb2SJF Bastien void getAnalysisUsage(AnalysisUsage &AU) const override { 58b9073fb2SJF Bastien AsmPrinter::getAnalysisUsage(AU); 59b9073fb2SJF Bastien } 60b9073fb2SJF Bastien 61600aee98SJF Bastien bool runOnMachineFunction(MachineFunction &MF) override { 62e419a7c3SDan Gohman TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 63600aee98SJF Bastien return AsmPrinter::runOnMachineFunction(MF); 64b9073fb2SJF Bastien } 65b9073fb2SJF Bastien 66b9073fb2SJF Bastien //===------------------------------------------------------------------===// 67b9073fb2SJF Bastien // AsmPrinter Implementation. 68b9073fb2SJF Bastien //===------------------------------------------------------------------===// 69b9073fb2SJF Bastien 70*b6091dfeSJF Bastien void EmitFunctionEntryLabel() override; 71*b6091dfeSJF Bastien void EmitFunctionBodyStart() override; 72*b6091dfeSJF Bastien void EmitFunctionBodyEnd() override; 73*b6091dfeSJF Bastien 74b9073fb2SJF Bastien void EmitInstruction(const MachineInstr *MI) override; 75b9073fb2SJF Bastien }; 76b9073fb2SJF Bastien 77b9073fb2SJF Bastien } // end anonymous namespace 78b9073fb2SJF Bastien 79b9073fb2SJF Bastien //===----------------------------------------------------------------------===// 80b9073fb2SJF Bastien 81315cc068SJF Bastien // Untyped, lower-case version of the opcode's name matching the names 82315cc068SJF Bastien // WebAssembly opcodes are expected to have. The tablegen names are uppercase 83315cc068SJF Bastien // and suffixed with their type (after an underscore). 84315cc068SJF Bastien static SmallString<32> Name(const WebAssemblyInstrInfo *TII, 85315cc068SJF Bastien const MachineInstr *MI) { 86315cc068SJF Bastien std::string N(StringRef(TII->getName(MI->getOpcode())).lower()); 8769c4c763SDan Gohman std::string::size_type End = N.rfind('_'); 88315cc068SJF Bastien End = std::string::npos == End ? N.length() : End; 89315cc068SJF Bastien return SmallString<32>(&N[0], &N[End]); 90315cc068SJF Bastien } 91315cc068SJF Bastien 92af111db8SJF Bastien static std::string toSymbol(StringRef S) { return ("$" + S).str(); } 93af111db8SJF Bastien 94*b6091dfeSJF Bastien static const char *toType(const Type *Ty) { 95*b6091dfeSJF Bastien switch (Ty->getTypeID()) { 96*b6091dfeSJF Bastien default: break; 97*b6091dfeSJF Bastien case Type::FloatTyID: return "f32"; 98*b6091dfeSJF Bastien case Type::DoubleTyID: return "f64"; 99*b6091dfeSJF Bastien case Type::IntegerTyID: 100*b6091dfeSJF Bastien switch (Ty->getIntegerBitWidth()) { 101*b6091dfeSJF Bastien case 32: return "i32"; 102*b6091dfeSJF Bastien case 64: return "i64"; 103*b6091dfeSJF Bastien default: break; 104*b6091dfeSJF Bastien } 105*b6091dfeSJF Bastien } 106*b6091dfeSJF Bastien DEBUG(dbgs() << "Invalid type "; Ty->print(dbgs()); dbgs() << '\n'); 107*b6091dfeSJF Bastien llvm_unreachable("invalid type"); 108*b6091dfeSJF Bastien return "<invalid>"; 109*b6091dfeSJF Bastien } 110*b6091dfeSJF Bastien 111*b6091dfeSJF Bastien void WebAssemblyAsmPrinter::EmitFunctionEntryLabel() { 112*b6091dfeSJF Bastien SmallString<128> Str; 113*b6091dfeSJF Bastien raw_svector_ostream OS(Str); 114*b6091dfeSJF Bastien 115*b6091dfeSJF Bastien CurrentFnSym->redefineIfPossible(); 116*b6091dfeSJF Bastien 117*b6091dfeSJF Bastien // The function label could have already been emitted if two symbols end up 118*b6091dfeSJF Bastien // conflicting due to asm renaming. Detect this and emit an error. 119*b6091dfeSJF Bastien if (CurrentFnSym->isVariable()) 120*b6091dfeSJF Bastien report_fatal_error("'" + Twine(CurrentFnSym->getName()) + 121*b6091dfeSJF Bastien "' is a protected alias"); 122*b6091dfeSJF Bastien if (CurrentFnSym->isDefined()) 123*b6091dfeSJF Bastien report_fatal_error("'" + Twine(CurrentFnSym->getName()) + 124*b6091dfeSJF Bastien "' label emitted multiple times to assembly file"); 125*b6091dfeSJF Bastien 126*b6091dfeSJF Bastien OS << "(func " << toSymbol(CurrentFnSym->getName()); 127*b6091dfeSJF Bastien OutStreamer->EmitRawText(OS.str()); 128*b6091dfeSJF Bastien } 129*b6091dfeSJF Bastien 130*b6091dfeSJF Bastien void WebAssemblyAsmPrinter::EmitFunctionBodyStart() { 131*b6091dfeSJF Bastien SmallString<128> Str; 132*b6091dfeSJF Bastien raw_svector_ostream OS(Str); 133*b6091dfeSJF Bastien const Function *F = MF->getFunction(); 134*b6091dfeSJF Bastien for (const Argument &A : F->args()) 135*b6091dfeSJF Bastien OS << " (param " << toType(A.getType()) << ')'; 136*b6091dfeSJF Bastien const Type *Rt = F->getReturnType(); 137*b6091dfeSJF Bastien if (!Rt->isVoidTy()) 138*b6091dfeSJF Bastien OS << " (result " << toType(Rt) << ')'; 139*b6091dfeSJF Bastien OS << '\n'; 140*b6091dfeSJF Bastien OutStreamer->EmitRawText(OS.str()); 141*b6091dfeSJF Bastien } 142*b6091dfeSJF Bastien 143*b6091dfeSJF Bastien void WebAssemblyAsmPrinter::EmitFunctionBodyEnd() { 144*b6091dfeSJF Bastien SmallString<128> Str; 145*b6091dfeSJF Bastien raw_svector_ostream OS(Str); 146*b6091dfeSJF Bastien OS << ") ;; end func " << toSymbol(CurrentFnSym->getName()) << '\n'; 147*b6091dfeSJF Bastien OutStreamer->EmitRawText(OS.str()); 148*b6091dfeSJF Bastien } 149*b6091dfeSJF Bastien 150b9073fb2SJF Bastien void WebAssemblyAsmPrinter::EmitInstruction(const MachineInstr *MI) { 151af111db8SJF Bastien DEBUG(dbgs() << "EmitInstruction: " << *MI << '\n'); 152b9073fb2SJF Bastien SmallString<128> Str; 153b9073fb2SJF Bastien raw_svector_ostream OS(Str); 154b9073fb2SJF Bastien 155600aee98SJF Bastien unsigned NumDefs = MI->getDesc().getNumDefs(); 156600aee98SJF Bastien assert(NumDefs <= 1 && 157600aee98SJF Bastien "Instructions with multiple result values not implemented"); 158600aee98SJF Bastien 15912e1997eSDan Gohman OS << '\t'; 16012e1997eSDan Gohman 161600aee98SJF Bastien if (NumDefs != 0) { 162600aee98SJF Bastien const MachineOperand &MO = MI->getOperand(0); 163600aee98SJF Bastien unsigned Reg = MO.getReg(); 164600aee98SJF Bastien OS << "(setlocal @" << TargetRegisterInfo::virtReg2Index(Reg) << ' '; 165600aee98SJF Bastien } 166600aee98SJF Bastien 1674a642256SJF Bastien OS << '(' << Name(TII, MI); 1684a642256SJF Bastien for (const MachineOperand &MO : MI->uses()) 1694a642256SJF Bastien switch (MO.getType()) { 170b9073fb2SJF Bastien default: 1714a642256SJF Bastien llvm_unreachable("unexpected machine operand type"); 1724a642256SJF Bastien case MachineOperand::MO_Register: { 1734a642256SJF Bastien if (MO.isImplicit()) 174600aee98SJF Bastien continue; 175600aee98SJF Bastien unsigned Reg = MO.getReg(); 176600aee98SJF Bastien OS << " @" << TargetRegisterInfo::virtReg2Index(Reg); 1774a642256SJF Bastien } break; 1784a642256SJF Bastien case MachineOperand::MO_Immediate: { 1794a642256SJF Bastien OS << ' ' << MO.getImm(); 1804a642256SJF Bastien } break; 1814a642256SJF Bastien case MachineOperand::MO_FPImmediate: { 1824a642256SJF Bastien static const size_t BufBytes = 128; 1834a642256SJF Bastien char buf[BufBytes]; 1844a642256SJF Bastien APFloat FP = MO.getFPImm()->getValueAPF(); 185e73ce682SJF Bastien if (FP.isNaN()) 186e73ce682SJF Bastien assert((FP.bitwiseIsEqual(APFloat::getQNaN(FP.getSemantics())) || 187e73ce682SJF Bastien FP.bitwiseIsEqual( 188e73ce682SJF Bastien APFloat::getQNaN(FP.getSemantics(), /*Negative=*/true))) && 189e73ce682SJF Bastien "convertToHexString handles neither SNaN nor NaN payloads"); 1904a642256SJF Bastien // Use C99's hexadecimal floating-point representation. 1914a642256SJF Bastien auto Written = 1924a642256SJF Bastien FP.convertToHexString(buf, /*hexDigits=*/0, /*upperCase=*/false, 1934a642256SJF Bastien APFloat::rmNearestTiesToEven); 19411bf0da0SJF Bastien (void)Written; 1954a642256SJF Bastien assert(Written != 0); 1964a642256SJF Bastien assert(Written < BufBytes); 1974a642256SJF Bastien OS << ' ' << buf; 1984a642256SJF Bastien } break; 199af111db8SJF Bastien case MachineOperand::MO_GlobalAddress: { 200af111db8SJF Bastien OS << ' ' << toSymbol(MO.getGlobal()->getName()); 201af111db8SJF Bastien } break; 202600aee98SJF Bastien } 203600aee98SJF Bastien OS << ')'; 204600aee98SJF Bastien 205600aee98SJF Bastien if (NumDefs != 0) 206600aee98SJF Bastien OS << ')'; 207600aee98SJF Bastien 208600aee98SJF Bastien OS << '\n'; 209600aee98SJF Bastien 210b9073fb2SJF Bastien OutStreamer->EmitRawText(OS.str()); 211b9073fb2SJF Bastien } 212b9073fb2SJF Bastien 213b9073fb2SJF Bastien // Force static initialization. 214b9073fb2SJF Bastien extern "C" void LLVMInitializeWebAssemblyAsmPrinter() { 215b9073fb2SJF Bastien RegisterAsmPrinter<WebAssemblyAsmPrinter> X(TheWebAssemblyTarget32); 216b9073fb2SJF Bastien RegisterAsmPrinter<WebAssemblyAsmPrinter> Y(TheWebAssemblyTarget64); 217b9073fb2SJF Bastien } 218