WebAssembly: fix the syntax for comparisons
[oota-llvm.git] / lib / Target / WebAssembly / WebAssemblyAsmPrinter.cpp
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/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"
36
37 using namespace llvm;
38
39 #define DEBUG_TYPE "asm-printer"
40
41 namespace {
42
43 class WebAssemblyAsmPrinter final : public AsmPrinter {
44   const WebAssemblyInstrInfo *TII;
45   const MachineRegisterInfo *MRI;
46   unsigned NumArgs;
47
48 public:
49   WebAssemblyAsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer)
50       : AsmPrinter(TM, std::move(Streamer)), TII(nullptr), MRI(nullptr) {}
51
52 private:
53   const char *getPassName() const override {
54     return "WebAssembly Assembly Printer";
55   }
56
57   //===------------------------------------------------------------------===//
58   // MachineFunctionPass Implementation.
59   //===------------------------------------------------------------------===//
60
61   void getAnalysisUsage(AnalysisUsage &AU) const override {
62     AsmPrinter::getAnalysisUsage(AU);
63   }
64
65   bool runOnMachineFunction(MachineFunction &MF) override {
66     const auto &Subtarget = MF.getSubtarget<WebAssemblySubtarget>();
67     TII = Subtarget.getInstrInfo();
68     MRI = &MF.getRegInfo();
69     NumArgs = MF.getInfo<WebAssemblyFunctionInfo>()->getNumArguments();
70     return AsmPrinter::runOnMachineFunction(MF);
71   }
72
73   //===------------------------------------------------------------------===//
74   // AsmPrinter Implementation.
75   //===------------------------------------------------------------------===//
76
77   void EmitJumpTableInfo() override;
78   void EmitConstantPool() override;
79   void EmitFunctionBodyStart() override;
80
81   void EmitInstruction(const MachineInstr *MI) override;
82
83   std::string getRegTypeName(unsigned RegNo) const;
84   static std::string toString(const APFloat &APF);
85   const char *toString(Type *Ty) const;
86   std::string regToString(const MachineOperand &MO);
87   std::string argToString(const MachineOperand &MO);
88 };
89
90 } // end anonymous namespace
91
92 //===----------------------------------------------------------------------===//
93 // Helpers.
94 //===----------------------------------------------------------------------===//
95
96 // Operand type (if any), followed by the lower-case version of the opcode's
97 // name matching the names WebAssembly opcodes are expected to have. The
98 // tablegen names are uppercase and suffixed with their type (after an
99 // underscore).
100 static std::string OpcodeName(const WebAssemblyInstrInfo *TII,
101                               const MachineInstr *MI) {
102   std::string N(StringRef(TII->getName(MI->getOpcode())).lower());
103   std::string::size_type Len = N.length();
104   std::string::size_type Under = N.rfind('_');
105   bool HasType = std::string::npos != Under;
106   std::string::size_type NameEnd = HasType ? Under : Len;
107   std::string Name(&N[0], &N[NameEnd]);
108   return HasType ? (std::string(&N[NameEnd + 1], &N[Len]) + '.' + Name) : Name;
109 }
110
111 static std::string toSymbol(StringRef S) { return ("$" + S).str(); }
112
113 std::string WebAssemblyAsmPrinter::getRegTypeName(unsigned RegNo) const {
114   const TargetRegisterClass *TRC = MRI->getRegClass(RegNo);
115   for (MVT T : {MVT::i32, MVT::i64, MVT::f32, MVT::f64})
116     if (TRC->hasType(T))
117       return EVT(T).getEVTString();
118   DEBUG(errs() << "Unknown type for register number: " << RegNo);
119   llvm_unreachable("Unknown register type");
120   return "?";
121 }
122
123 std::string WebAssemblyAsmPrinter::toString(const APFloat &FP) {
124   static const size_t BufBytes = 128;
125   char buf[BufBytes];
126   if (FP.isNaN())
127     assert((FP.bitwiseIsEqual(APFloat::getQNaN(FP.getSemantics())) ||
128             FP.bitwiseIsEqual(
129                 APFloat::getQNaN(FP.getSemantics(), /*Negative=*/true))) &&
130            "convertToHexString handles neither SNaN nor NaN payloads");
131   // Use C99's hexadecimal floating-point representation.
132   auto Written = FP.convertToHexString(
133       buf, /*hexDigits=*/0, /*upperCase=*/false, APFloat::rmNearestTiesToEven);
134   (void)Written;
135   assert(Written != 0);
136   assert(Written < BufBytes);
137   return buf;
138 }
139
140 std::string WebAssemblyAsmPrinter::regToString(const MachineOperand &MO) {
141   unsigned RegNo = MO.getReg();
142   if (TargetRegisterInfo::isPhysicalRegister(RegNo))
143     return WebAssemblyInstPrinter::getRegisterName(RegNo);
144
145   // WebAssembly arguments and local variables are in the same index space, and
146   // there are no explicit varargs, so we just add the number of arguments to
147   // the virtual register number to get the local variable number.
148   return utostr(TargetRegisterInfo::virtReg2Index(RegNo) + NumArgs);
149 }
150
151 std::string WebAssemblyAsmPrinter::argToString(const MachineOperand &MO) {
152   unsigned ArgNo = MO.getImm();
153   // Same as above, but we don't need to add NumArgs here.
154   return utostr(ArgNo);
155 }
156
157 const char *WebAssemblyAsmPrinter::toString(Type *Ty) const {
158   switch (Ty->getTypeID()) {
159   default:
160     break;
161   // Treat all pointers as the underlying integer into linear memory.
162   case Type::PointerTyID:
163     switch (getPointerSize()) {
164     case 4:
165       return "i32";
166     case 8:
167       return "i64";
168     default:
169       llvm_unreachable("unsupported pointer size");
170     }
171     break;
172   case Type::FloatTyID:
173     return "f32";
174   case Type::DoubleTyID:
175     return "f64";
176   case Type::IntegerTyID:
177     switch (Ty->getIntegerBitWidth()) {
178     case 8:
179       return "i8";
180     case 16:
181       return "i16";
182     case 32:
183       return "i32";
184     case 64:
185       return "i64";
186     default:
187       break;
188     }
189   }
190   DEBUG(dbgs() << "Invalid type "; Ty->print(dbgs()); dbgs() << '\n');
191   llvm_unreachable("invalid type");
192   return "<invalid>";
193 }
194
195 //===----------------------------------------------------------------------===//
196 // WebAssemblyAsmPrinter Implementation.
197 //===----------------------------------------------------------------------===//
198
199 void WebAssemblyAsmPrinter::EmitConstantPool() {
200   assert(MF->getConstantPool()->getConstants().empty() &&
201          "WebAssembly disables constant pools");
202 }
203
204 void WebAssemblyAsmPrinter::EmitJumpTableInfo() {
205   // Nothing to do; jump tables are incorporated into the instruction stream.
206 }
207
208 void WebAssemblyAsmPrinter::EmitFunctionBodyStart() {
209   const Function *F = MF->getFunction();
210   Type *Rt = F->getReturnType();
211   SmallString<128> Str;
212   raw_svector_ostream OS(Str);
213   bool First = true;
214
215   if (!Rt->isVoidTy() || !F->arg_empty()) {
216     for (const Argument &A : F->args()) {
217       OS << (First ? "" : "\n") << "\t.param " << toString(A.getType());
218       First = false;
219     }
220     if (!Rt->isVoidTy()) {
221       OS << (First ? "" : "\n") << "\t.result " << toString(Rt);
222       First = false;
223     }
224   }
225
226   bool FirstVReg = true;
227   for (unsigned Idx = 0, IdxE = MRI->getNumVirtRegs(); Idx != IdxE; ++Idx) {
228     unsigned VReg = TargetRegisterInfo::index2VirtReg(Idx);
229     if (!MRI->use_empty(VReg)) {
230       if (FirstVReg) {
231         OS << (First ? "" : "\n") << "\t.local ";
232         First = false;
233       }
234       OS << (FirstVReg ? "" : ", ") << getRegTypeName(VReg);
235       FirstVReg = false;
236     }
237   }
238
239   if (!First)
240     OutStreamer->EmitRawText(OS.str());
241   AsmPrinter::EmitFunctionBodyStart();
242 }
243
244 void WebAssemblyAsmPrinter::EmitInstruction(const MachineInstr *MI) {
245   DEBUG(dbgs() << "EmitInstruction: " << *MI << '\n');
246   SmallString<128> Str;
247   raw_svector_ostream OS(Str);
248
249   unsigned NumDefs = MI->getDesc().getNumDefs();
250   assert(NumDefs <= 1 &&
251          "Instructions with multiple result values not implemented");
252
253   OS << '\t';
254
255   switch (MI->getOpcode()) {
256   case TargetOpcode::COPY:
257     OS << "get_local " << regToString(MI->getOperand(1));
258     break;
259   case WebAssembly::GLOBAL:
260     // TODO: wasm64
261     OS << "i32.const " << toSymbol(MI->getOperand(1).getGlobal()->getName());
262     break;
263   case WebAssembly::ARGUMENT_I32:
264   case WebAssembly::ARGUMENT_I64:
265   case WebAssembly::ARGUMENT_F32:
266   case WebAssembly::ARGUMENT_F64:
267     OS << "get_local " << argToString(MI->getOperand(1));
268     break;
269   case WebAssembly::Immediate_I32:
270     OS << "i32.const " << MI->getOperand(1).getImm();
271     break;
272   case WebAssembly::Immediate_I64:
273     OS << "i64.const " << MI->getOperand(1).getImm();
274     break;
275   case WebAssembly::Immediate_F32:
276     OS << "f32.const " << toString(MI->getOperand(1).getFPImm()->getValueAPF());
277     break;
278   case WebAssembly::Immediate_F64:
279     OS << "f64.const " << toString(MI->getOperand(1).getFPImm()->getValueAPF());
280     break;
281   default: {
282     OS << OpcodeName(TII, MI);
283     bool NeedComma = false;
284     for (const MachineOperand &MO : MI->uses()) {
285       if (MO.isReg() && MO.isImplicit())
286         continue;
287       if (NeedComma)
288         OS << ',';
289       NeedComma = true;
290       OS << ' ';
291       switch (MO.getType()) {
292       default:
293         llvm_unreachable("unexpected machine operand type");
294       case MachineOperand::MO_Register:
295         OS << "(get_local " << regToString(MO) << ')';
296         break;
297       case MachineOperand::MO_Immediate:
298         OS << MO.getImm();
299         break;
300       case MachineOperand::MO_FPImmediate:
301         OS << toString(MO.getFPImm()->getValueAPF());
302         break;
303       case MachineOperand::MO_GlobalAddress:
304         OS << toSymbol(MO.getGlobal()->getName());
305         break;
306       case MachineOperand::MO_MachineBasicBlock:
307         OS << toSymbol(MO.getMBB()->getSymbol()->getName());
308         break;
309       }
310     }
311     break;
312   }
313   }
314
315   OutStreamer->EmitRawText(OS.str());
316
317   if (NumDefs != 0) {
318     SmallString<128> Str;
319     raw_svector_ostream OS(Str);
320     const MachineOperand &Operand = MI->getOperand(0);
321     OS << "\tset_local " << regToString(Operand) << ", pop";
322     OutStreamer->EmitRawText(OS.str());
323   }
324 }
325
326 // Force static initialization.
327 extern "C" void LLVMInitializeWebAssemblyAsmPrinter() {
328   RegisterAsmPrinter<WebAssemblyAsmPrinter> X(TheWebAssemblyTarget32);
329   RegisterAsmPrinter<WebAssemblyAsmPrinter> Y(TheWebAssemblyTarget64);
330 }