1 //===-- WebAssemblyAsmPrinter.cpp - WebAssembly LLVM assembly writer ------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
11 /// \brief This file contains a printer that converts from our internal
12 /// representation of machine-dependent LLVM code to the WebAssembly assembly
15 //===----------------------------------------------------------------------===//
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"
24 #include "llvm/ADT/SmallString.h"
25 #include "llvm/ADT/StringExtras.h"
26 #include "llvm/CodeGen/AsmPrinter.h"
27 #include "llvm/CodeGen/MachineConstantPool.h"
28 #include "llvm/CodeGen/MachineInstr.h"
29 #include "llvm/IR/DataLayout.h"
30 #include "llvm/IR/DebugInfo.h"
31 #include "llvm/MC/MCStreamer.h"
32 #include "llvm/MC/MCSymbol.h"
33 #include "llvm/Support/Debug.h"
34 #include "llvm/Support/TargetRegistry.h"
35 #include "llvm/Support/raw_ostream.h"
39 #define DEBUG_TYPE "asm-printer"
43 class WebAssemblyAsmPrinter final : public AsmPrinter {
44 const WebAssemblyInstrInfo *TII;
48 WebAssemblyAsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer)
49 : AsmPrinter(TM, std::move(Streamer)), TII(nullptr) {}
52 const char *getPassName() const override {
53 return "WebAssembly Assembly Printer";
56 //===------------------------------------------------------------------===//
57 // MachineFunctionPass Implementation.
58 //===------------------------------------------------------------------===//
60 void getAnalysisUsage(AnalysisUsage &AU) const override {
61 AsmPrinter::getAnalysisUsage(AU);
64 bool runOnMachineFunction(MachineFunction &MF) override {
65 const auto &Subtarget = MF.getSubtarget<WebAssemblySubtarget>();
66 TII = Subtarget.getInstrInfo();
67 NumArgs = MF.getInfo<WebAssemblyFunctionInfo>()->getNumArguments();
68 return AsmPrinter::runOnMachineFunction(MF);
71 //===------------------------------------------------------------------===//
72 // AsmPrinter Implementation.
73 //===------------------------------------------------------------------===//
75 void EmitJumpTableInfo() override;
76 void EmitConstantPool() override;
77 void EmitFunctionBodyStart() override;
79 void EmitInstruction(const MachineInstr *MI) override;
81 static std::string toString(const APFloat &APF);
82 const char *toString(Type *Ty) const;
83 std::string regToString(unsigned RegNo);
84 std::string argToString(unsigned ArgNo);
87 } // end anonymous namespace
89 //===----------------------------------------------------------------------===//
91 //===----------------------------------------------------------------------===//
93 // Untyped, lower-case version of the opcode's name matching the names
94 // WebAssembly opcodes are expected to have. The tablegen names are uppercase
95 // and suffixed with their type (after an underscore).
96 static SmallString<32> OpcodeName(const WebAssemblyInstrInfo *TII,
97 const MachineInstr *MI) {
98 std::string N(StringRef(TII->getName(MI->getOpcode())).lower());
99 std::string::size_type End = N.rfind('_');
100 End = std::string::npos == End ? N.length() : End;
101 return SmallString<32>(&N[0], &N[End]);
104 static std::string toSymbol(StringRef S) { return ("$" + S).str(); }
106 std::string WebAssemblyAsmPrinter::toString(const APFloat &FP) {
107 static const size_t BufBytes = 128;
110 assert((FP.bitwiseIsEqual(APFloat::getQNaN(FP.getSemantics())) ||
112 APFloat::getQNaN(FP.getSemantics(), /*Negative=*/true))) &&
113 "convertToHexString handles neither SNaN nor NaN payloads");
114 // Use C99's hexadecimal floating-point representation.
115 auto Written = FP.convertToHexString(
116 buf, /*hexDigits=*/0, /*upperCase=*/false, APFloat::rmNearestTiesToEven);
118 assert(Written != 0);
119 assert(Written < BufBytes);
123 std::string WebAssemblyAsmPrinter::regToString(unsigned RegNo) {
124 if (TargetRegisterInfo::isPhysicalRegister(RegNo))
125 return WebAssemblyInstPrinter::getRegisterName(RegNo);
127 // WebAssembly arguments and local variables are in the same index space, and
128 // there are no explicit varargs, so we just add the number of arguments to
129 // the virtual register number to get the local variable number.
130 return '@' + utostr(TargetRegisterInfo::virtReg2Index(RegNo) + NumArgs);
133 std::string WebAssemblyAsmPrinter::argToString(unsigned ArgNo) {
134 // Same as above, but we don't need to add NumArgs here.
135 return '@' + utostr(ArgNo);
138 const char *WebAssemblyAsmPrinter::toString(Type *Ty) const {
139 switch (Ty->getTypeID()) {
142 // Treat all pointers as the underlying integer into linear memory.
143 case Type::PointerTyID:
144 switch (getPointerSize()) {
150 llvm_unreachable("unsupported pointer size");
153 case Type::FloatTyID:
155 case Type::DoubleTyID:
157 case Type::IntegerTyID:
158 switch (Ty->getIntegerBitWidth()) {
171 DEBUG(dbgs() << "Invalid type "; Ty->print(dbgs()); dbgs() << '\n');
172 llvm_unreachable("invalid type");
176 //===----------------------------------------------------------------------===//
177 // WebAssemblyAsmPrinter Implementation.
178 //===----------------------------------------------------------------------===//
180 void WebAssemblyAsmPrinter::EmitConstantPool() {
181 assert(MF->getConstantPool()->getConstants().empty() &&
182 "WebAssembly disables constant pools");
185 void WebAssemblyAsmPrinter::EmitJumpTableInfo() {
186 // Nothing to do; jump tables are incorporated into the instruction stream.
189 void WebAssemblyAsmPrinter::EmitFunctionBodyStart() {
190 const Function *F = MF->getFunction();
191 Type *Rt = F->getReturnType();
193 if (!Rt->isVoidTy() || !F->arg_empty()) {
194 SmallString<128> Str;
195 raw_svector_ostream OS(Str);
197 for (const Argument &A : F->args()) {
198 OS << (First ? "" : "\n") << "\t"
200 << toString(A.getType());
203 if (!Rt->isVoidTy()) {
204 OS << (First ? "" : "\n") << "\t"
209 OutStreamer->EmitRawText(OS.str());
212 AsmPrinter::EmitFunctionBodyStart();
215 void WebAssemblyAsmPrinter::EmitInstruction(const MachineInstr *MI) {
216 DEBUG(dbgs() << "EmitInstruction: " << *MI << '\n');
217 SmallString<128> Str;
218 raw_svector_ostream OS(Str);
220 unsigned NumDefs = MI->getDesc().getNumDefs();
221 assert(NumDefs <= 1 &&
222 "Instructions with multiple result values not implemented");
226 switch (MI->getOpcode()) {
227 case TargetOpcode::COPY:
228 OS << regToString(MI->getOperand(1).getReg());
230 case WebAssembly::GLOBAL:
232 OS << "i32.const " << toSymbol(MI->getOperand(1).getGlobal()->getName());
234 case WebAssembly::ARGUMENT_I32:
235 case WebAssembly::ARGUMENT_I64:
236 case WebAssembly::ARGUMENT_F32:
237 case WebAssembly::ARGUMENT_F64:
238 OS << argToString(MI->getOperand(1).getImm());
240 case WebAssembly::Immediate_I32:
241 OS << "i32.const " << MI->getOperand(1).getImm();
243 case WebAssembly::Immediate_I64:
244 OS << "i64.const " << MI->getOperand(1).getImm();
246 case WebAssembly::Immediate_F32:
247 OS << "f32.const " << toString(MI->getOperand(1).getFPImm()->getValueAPF());
249 case WebAssembly::Immediate_F64:
250 OS << "f64.const " << toString(MI->getOperand(1).getFPImm()->getValueAPF());
253 OS << OpcodeName(TII, MI);
254 bool NeedComma = false;
255 for (const MachineOperand &MO : MI->uses()) {
256 if (MO.isReg() && MO.isImplicit())
262 switch (MO.getType()) {
264 llvm_unreachable("unexpected machine operand type");
265 case MachineOperand::MO_Register:
266 OS << regToString(MO.getReg());
268 case MachineOperand::MO_Immediate:
271 case MachineOperand::MO_FPImmediate:
272 OS << toString(MO.getFPImm()->getValueAPF());
274 case MachineOperand::MO_GlobalAddress:
275 OS << toSymbol(MO.getGlobal()->getName());
277 case MachineOperand::MO_MachineBasicBlock:
278 OS << toSymbol(MO.getMBB()->getSymbol()->getName());
286 OutStreamer->EmitRawText(OS.str());
289 SmallString<128> Str;
290 raw_svector_ostream OS(Str);
291 OS << "\t" "set_local "
292 << regToString(MI->getOperand(0).getReg()) << ", "
294 OutStreamer->EmitRawText(OS.str());
298 // Force static initialization.
299 extern "C" void LLVMInitializeWebAssemblyAsmPrinter() {
300 RegisterAsmPrinter<WebAssemblyAsmPrinter> X(TheWebAssemblyTarget32);
301 RegisterAsmPrinter<WebAssemblyAsmPrinter> Y(TheWebAssemblyTarget64);