[WebAssembly] Check in an initial CFG Stackifier pass
[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/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   bool hasAddr64;
44   const WebAssemblyInstrInfo *TII;
45
46 public:
47   WebAssemblyAsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer)
48       : AsmPrinter(TM, std::move(Streamer)), TII(nullptr) {}
49
50 private:
51   const char *getPassName() const override {
52     return "WebAssembly Assembly Printer";
53   }
54
55   //===------------------------------------------------------------------===//
56   // MachineFunctionPass Implementation.
57   //===------------------------------------------------------------------===//
58
59   void getAnalysisUsage(AnalysisUsage &AU) const override {
60     AsmPrinter::getAnalysisUsage(AU);
61   }
62
63   bool runOnMachineFunction(MachineFunction &MF) override {
64     const auto &Subtarget = MF.getSubtarget<WebAssemblySubtarget>();
65     hasAddr64 = Subtarget.hasAddr64();
66     TII = Subtarget.getInstrInfo();
67     return AsmPrinter::runOnMachineFunction(MF);
68   }
69
70   //===------------------------------------------------------------------===//
71   // AsmPrinter Implementation.
72   //===------------------------------------------------------------------===//
73
74   void EmitGlobalVariable(const GlobalVariable *GV) override;
75
76   void EmitJumpTableInfo() override;
77   void EmitConstantPool() override;
78   void EmitFunctionEntryLabel() override;
79   void EmitFunctionBodyStart() override;
80   void EmitFunctionBodyEnd() override;
81
82   void EmitInstruction(const MachineInstr *MI) override;
83 };
84
85 } // end anonymous namespace
86
87 //===----------------------------------------------------------------------===//
88 // Helpers.
89 //===----------------------------------------------------------------------===//
90
91 // Untyped, lower-case version of the opcode's name matching the names
92 // WebAssembly opcodes are expected to have. The tablegen names are uppercase
93 // and suffixed with their type (after an underscore).
94 static SmallString<32> OpcodeName(const WebAssemblyInstrInfo *TII,
95                                   const MachineInstr *MI) {
96   std::string N(StringRef(TII->getName(MI->getOpcode())).lower());
97   std::string::size_type End = N.rfind('_');
98   End = std::string::npos == End ? N.length() : End;
99   return SmallString<32>(&N[0], &N[End]);
100 }
101
102 static std::string toSymbol(StringRef S) { return ("$" + S).str(); }
103
104 static std::string toString(const APFloat &FP) {
105   static const size_t BufBytes = 128;
106   char buf[BufBytes];
107   if (FP.isNaN())
108     assert((FP.bitwiseIsEqual(APFloat::getQNaN(FP.getSemantics())) ||
109             FP.bitwiseIsEqual(
110                 APFloat::getQNaN(FP.getSemantics(), /*Negative=*/true))) &&
111            "convertToHexString handles neither SNaN nor NaN payloads");
112   // Use C99's hexadecimal floating-point representation.
113   auto Written = FP.convertToHexString(
114       buf, /*hexDigits=*/0, /*upperCase=*/false, APFloat::rmNearestTiesToEven);
115   (void)Written;
116   assert(Written != 0);
117   assert(Written < BufBytes);
118   return buf;
119 }
120
121 static const char *toString(const Type *Ty, bool hasAddr64) {
122   switch (Ty->getTypeID()) {
123   default: break;
124   // Treat all pointers as the underlying integer into linear memory.
125   case Type::PointerTyID: return hasAddr64 ? "i64" : "i32";
126   case Type::FloatTyID:  return "f32";
127   case Type::DoubleTyID: return "f64";
128   case Type::IntegerTyID:
129     switch (Ty->getIntegerBitWidth()) {
130     case 8: return "i8";
131     case 16: return "i16";
132     case 32: return "i32";
133     case 64: return "i64";
134     default: break;
135     }
136   }
137   DEBUG(dbgs() << "Invalid type "; Ty->print(dbgs()); dbgs() << '\n');
138   llvm_unreachable("invalid type");
139   return "<invalid>";
140 }
141
142
143 //===----------------------------------------------------------------------===//
144 // WebAssemblyAsmPrinter Implementation.
145 //===----------------------------------------------------------------------===//
146
147 void WebAssemblyAsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) {
148   SmallString<128> Str;
149   raw_svector_ostream OS(Str);
150   StringRef Name = GV->getName();
151   DEBUG(dbgs() << "Global " << Name << '\n');
152
153   if (!GV->hasInitializer()) {
154     DEBUG(dbgs() << "  Skipping declaration.\n");
155     return;
156   }
157
158   // Check to see if this is a special global used by LLVM.
159   static const char *Ignored[] = {"llvm.used", "llvm.metadata"};
160   for (const char *I : Ignored)
161     if (Name == I)
162       return;
163   // FIXME: Handle the following globals.
164   static const char *Unhandled[] = {"llvm.global_ctors", "llvm.global_dtors"};
165   for (const char *U : Unhandled)
166     if (Name == U)
167       report_fatal_error("Unhandled global");
168   if (Name.startswith("llvm."))
169     report_fatal_error("Unknown LLVM-internal global");
170
171   if (GV->isThreadLocal())
172     report_fatal_error("TLS isn't yet supported by WebAssembly");
173
174   const DataLayout &DL = getDataLayout();
175   const Constant *Init = GV->getInitializer();
176   if (isa<UndefValue>(Init))
177     Init = Constant::getNullValue(Init->getType());
178   unsigned Align = DL.getPrefTypeAlignment(Init->getType());
179
180   switch (GV->getLinkage()) {
181   case GlobalValue::InternalLinkage:
182   case GlobalValue::PrivateLinkage:
183     break;
184   case GlobalValue::AppendingLinkage:
185   case GlobalValue::LinkOnceAnyLinkage:
186   case GlobalValue::LinkOnceODRLinkage:
187   case GlobalValue::WeakAnyLinkage:
188   case GlobalValue::WeakODRLinkage:
189   case GlobalValue::ExternalLinkage:
190   case GlobalValue::CommonLinkage:
191     report_fatal_error("Linkage types other than internal and private aren't "
192                        "supported by WebAssembly yet");
193   default:
194     llvm_unreachable("Unknown linkage type");
195     return;
196   }
197
198   OS << "(global " << toSymbol(Name) << ' '
199      << toString(Init->getType(), hasAddr64) << ' ';
200   if (const auto *C = dyn_cast<ConstantInt>(Init)) {
201     assert(C->getBitWidth() <= 64 && "Printing wider types unimplemented");
202     OS << C->getZExtValue();
203   } else if (const auto *C = dyn_cast<ConstantFP>(Init)) {
204     OS << toString(C->getValueAPF());
205   } else {
206     assert(false && "Only integer and floating-point constants are supported");
207   }
208   OS << ") ;; align " << Align;
209   OutStreamer->EmitRawText(OS.str());
210 }
211
212 void WebAssemblyAsmPrinter::EmitConstantPool() {
213   assert(MF->getConstantPool()->getConstants().empty() &&
214          "WebAssembly disables constant pools");
215 }
216
217 void WebAssemblyAsmPrinter::EmitJumpTableInfo() {
218   // Nothing to do; jump tables are incorporated into the instruction stream.
219 }
220
221 void WebAssemblyAsmPrinter::EmitFunctionEntryLabel() {
222   SmallString<128> Str;
223   raw_svector_ostream OS(Str);
224
225   CurrentFnSym->redefineIfPossible();
226
227   // The function label could have already been emitted if two symbols end up
228   // conflicting due to asm renaming.  Detect this and emit an error.
229   if (CurrentFnSym->isVariable())
230     report_fatal_error("'" + Twine(CurrentFnSym->getName()) +
231                        "' is a protected alias");
232   if (CurrentFnSym->isDefined())
233     report_fatal_error("'" + Twine(CurrentFnSym->getName()) +
234                        "' label emitted multiple times to assembly file");
235
236   OS << "(func " << toSymbol(CurrentFnSym->getName());
237   OutStreamer->EmitRawText(OS.str());
238 }
239
240 void WebAssemblyAsmPrinter::EmitFunctionBodyStart() {
241   SmallString<128> Str;
242   raw_svector_ostream OS(Str);
243   const Function *F = MF->getFunction();
244   const Type *Rt = F->getReturnType();
245   if (!Rt->isVoidTy() || !F->arg_empty()) {
246     for (const Argument &A : F->args())
247       OS << " (param " << toString(A.getType(), hasAddr64) << ')';
248     if (!Rt->isVoidTy())
249       OS << " (result " << toString(Rt, hasAddr64) << ')';
250     OutStreamer->EmitRawText(OS.str());
251   }
252 }
253
254 void WebAssemblyAsmPrinter::EmitFunctionBodyEnd() {
255   SmallString<128> Str;
256   raw_svector_ostream OS(Str);
257   OS << ") ;; end func " << toSymbol(CurrentFnSym->getName());
258   OutStreamer->EmitRawText(OS.str());
259 }
260
261 void WebAssemblyAsmPrinter::EmitInstruction(const MachineInstr *MI) {
262   DEBUG(dbgs() << "EmitInstruction: " << *MI << '\n');
263   SmallString<128> Str;
264   raw_svector_ostream OS(Str);
265
266   unsigned NumDefs = MI->getDesc().getNumDefs();
267   assert(NumDefs <= 1 &&
268          "Instructions with multiple result values not implemented");
269
270   OS << '\t';
271
272   if (NumDefs != 0) {
273     const MachineOperand &MO = MI->getOperand(0);
274     unsigned Reg = MO.getReg();
275     OS << "(setlocal @" << TargetRegisterInfo::virtReg2Index(Reg) << ' ';
276   }
277
278   if (MI->getOpcode() == WebAssembly::COPY) {
279     OS << '@' << TargetRegisterInfo::virtReg2Index(MI->getOperand(1).getReg());
280   } else {
281     OS << '(' << OpcodeName(TII, MI);
282     for (const MachineOperand &MO : MI->uses())
283       switch (MO.getType()) {
284       default:
285         llvm_unreachable("unexpected machine operand type");
286       case MachineOperand::MO_Register: {
287         if (MO.isImplicit())
288           continue;
289         unsigned Reg = MO.getReg();
290         OS << " @" << TargetRegisterInfo::virtReg2Index(Reg);
291       } break;
292       case MachineOperand::MO_Immediate: {
293         OS << ' ' << MO.getImm();
294       } break;
295       case MachineOperand::MO_FPImmediate: {
296         OS << ' ' << toString(MO.getFPImm()->getValueAPF());
297       } break;
298       case MachineOperand::MO_GlobalAddress: {
299         OS << ' ' << toSymbol(MO.getGlobal()->getName());
300       } break;
301       case MachineOperand::MO_MachineBasicBlock: {
302         OS << ' ' << toSymbol(MO.getMBB()->getSymbol()->getName());
303       } break;
304       }
305     OS << ')';
306   }
307
308   if (NumDefs != 0)
309     OS << ')';
310
311   OutStreamer->EmitRawText(OS.str());
312 }
313
314 // Force static initialization.
315 extern "C" void LLVMInitializeWebAssemblyAsmPrinter() {
316   RegisterAsmPrinter<WebAssemblyAsmPrinter> X(TheWebAssemblyTarget32);
317   RegisterAsmPrinter<WebAssemblyAsmPrinter> Y(TheWebAssemblyTarget64);
318 }