1 //==-- WebAssemblyTargetStreamer.cpp - WebAssembly Target Streamer Methods --=//
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 defines WebAssembly-specific target streamer classes.
12 /// These are for implementing support for target-specific assembly directives.
13 ///
14 //===----------------------------------------------------------------------===//
15 
16 #include "WebAssemblyTargetStreamer.h"
17 #include "InstPrinter/WebAssemblyInstPrinter.h"
18 #include "WebAssemblyMCTargetDesc.h"
19 #include "llvm/MC/MCContext.h"
20 #include "llvm/MC/MCSectionELF.h"
21 #include "llvm/MC/MCSectionWasm.h"
22 #include "llvm/MC/MCSubtargetInfo.h"
23 #include "llvm/MC/MCSymbolELF.h"
24 #include "llvm/MC/MCSymbolWasm.h"
25 #include "llvm/Support/Casting.h"
26 #include "llvm/Support/ErrorHandling.h"
27 #include "llvm/Support/FormattedStream.h"
28 #include "llvm/Support/Wasm.h"
29 using namespace llvm;
30 
31 WebAssemblyTargetStreamer::WebAssemblyTargetStreamer(MCStreamer &S)
32     : MCTargetStreamer(S) {}
33 
34 WebAssemblyTargetAsmStreamer::WebAssemblyTargetAsmStreamer(
35     MCStreamer &S, formatted_raw_ostream &OS)
36     : WebAssemblyTargetStreamer(S), OS(OS) {}
37 
38 WebAssemblyTargetELFStreamer::WebAssemblyTargetELFStreamer(MCStreamer &S)
39     : WebAssemblyTargetStreamer(S) {}
40 
41 WebAssemblyTargetWasmStreamer::WebAssemblyTargetWasmStreamer(MCStreamer &S)
42     : WebAssemblyTargetStreamer(S) {}
43 
44 static void PrintTypes(formatted_raw_ostream &OS, ArrayRef<MVT> Types) {
45   bool First = true;
46   for (MVT Type : Types) {
47     if (First)
48       First = false;
49     else
50       OS << ", ";
51     OS << WebAssembly::TypeToString(Type);
52   }
53   OS << '\n';
54 }
55 
56 void WebAssemblyTargetAsmStreamer::emitParam(MCSymbol *Symbol,
57                                              ArrayRef<MVT> Types) {
58   if (!Types.empty()) {
59     OS << "\t.param  \t";
60 
61     // FIXME: Currently this applies to the "current" function; it may
62     // be cleaner to specify an explicit symbol as part of the directive.
63 
64     PrintTypes(OS, Types);
65   }
66 }
67 
68 void WebAssemblyTargetAsmStreamer::emitResult(MCSymbol *Symbol,
69                                               ArrayRef<MVT> Types) {
70   if (!Types.empty()) {
71     OS << "\t.result \t";
72 
73     // FIXME: Currently this applies to the "current" function; it may
74     // be cleaner to specify an explicit symbol as part of the directive.
75 
76     PrintTypes(OS, Types);
77   }
78 }
79 
80 void WebAssemblyTargetAsmStreamer::emitLocal(ArrayRef<MVT> Types) {
81   if (!Types.empty()) {
82     OS << "\t.local  \t";
83     PrintTypes(OS, Types);
84   }
85 }
86 
87 void WebAssemblyTargetAsmStreamer::emitGlobal(ArrayRef<MVT> Types) {
88   if (!Types.empty()) {
89     OS << "\t.globalvar  \t";
90     PrintTypes(OS, Types);
91   }
92 }
93 
94 void WebAssemblyTargetAsmStreamer::emitEndFunc() { OS << "\t.endfunc\n"; }
95 
96 void WebAssemblyTargetAsmStreamer::emitIndirectFunctionType(
97     StringRef name, SmallVectorImpl<MVT> &Params, SmallVectorImpl<MVT> &Results) {
98   OS << "\t.functype\t" << name;
99   if (Results.empty())
100     OS << ", void";
101   else {
102     assert(Results.size() == 1);
103     OS << ", " << WebAssembly::TypeToString(Results.front());
104   }
105   for (auto Ty : Params)
106     OS << ", " << WebAssembly::TypeToString(Ty);
107   OS << '\n';
108 }
109 
110 void WebAssemblyTargetAsmStreamer::emitGlobalImport(StringRef name) {
111   OS << "\t.import_global\t" << name << '\n';
112 }
113 
114 void WebAssemblyTargetAsmStreamer::emitIndIdx(const MCExpr *Value) {
115   OS << "\t.indidx  \t" << *Value << '\n';
116 }
117 
118 void WebAssemblyTargetELFStreamer::emitParam(MCSymbol *Symbol,
119                                              ArrayRef<MVT> Types) {
120   // Nothing to emit; params are declared as part of the function signature.
121 }
122 
123 void WebAssemblyTargetELFStreamer::emitResult(MCSymbol *Symbol,
124                                               ArrayRef<MVT> Types) {
125   // Nothing to emit; results are declared as part of the function signature.
126 }
127 
128 void WebAssemblyTargetELFStreamer::emitLocal(ArrayRef<MVT> Types) {
129   Streamer.EmitULEB128IntValue(Types.size());
130   for (MVT Type : Types)
131     Streamer.EmitIntValue(int64_t(WebAssembly::toValType(Type)), 1);
132 }
133 
134 void WebAssemblyTargetELFStreamer::emitGlobal(ArrayRef<MVT> Types) {
135   llvm_unreachable(".globalvar encoding not yet implemented");
136 }
137 
138 void WebAssemblyTargetELFStreamer::emitEndFunc() {
139   Streamer.EmitIntValue(WebAssembly::End, 1);
140 }
141 
142 void WebAssemblyTargetELFStreamer::emitIndIdx(const MCExpr *Value) {
143   llvm_unreachable(".indidx encoding not yet implemented");
144 }
145 
146 void WebAssemblyTargetELFStreamer::emitIndirectFunctionType(
147     StringRef name, SmallVectorImpl<MVT> &Params, SmallVectorImpl<MVT> &Results) {
148   // Nothing to emit here. TODO: Re-design how linking works and re-evaluate
149   // whether it's necessary for .o files to declare indirect function types.
150 }
151 
152 void WebAssemblyTargetELFStreamer::emitGlobalImport(StringRef name) {
153 }
154 
155 static unsigned MVT2WasmType(MVT Ty) {
156   switch (Ty.SimpleTy) {
157   case MVT::i32: return wasm::WASM_TYPE_I32;
158   case MVT::i64: return wasm::WASM_TYPE_I64;
159   case MVT::f32: return wasm::WASM_TYPE_F32;
160   case MVT::f64: return wasm::WASM_TYPE_F64;
161   default: llvm_unreachable("unsupported type");
162   }
163 }
164 
165 void WebAssemblyTargetWasmStreamer::emitParam(MCSymbol *Symbol,
166                                               ArrayRef<MVT> Types) {
167   SmallVector<unsigned, 4> Params;
168   for (MVT Ty : Types)
169     Params.push_back(MVT2WasmType(Ty));
170 
171   cast<MCSymbolWasm>(Symbol)->setParams(std::move(Params));
172 }
173 
174 void WebAssemblyTargetWasmStreamer::emitResult(MCSymbol *Symbol,
175                                                ArrayRef<MVT> Types) {
176   SmallVector<unsigned, 4> Returns;
177   for (MVT Ty : Types)
178     Returns.push_back(MVT2WasmType(Ty));
179 
180   cast<MCSymbolWasm>(Symbol)->setReturns(std::move(Returns));
181 }
182 
183 void WebAssemblyTargetWasmStreamer::emitLocal(ArrayRef<MVT> Types) {
184   SmallVector<std::pair<MVT, uint32_t>, 4> Grouped;
185   for (MVT Type : Types) {
186     if (Grouped.empty() || Grouped.back().first != Type)
187       Grouped.push_back(std::make_pair(Type, 1));
188     else
189       ++Grouped.back().second;
190   }
191 
192   Streamer.EmitULEB128IntValue(Grouped.size());
193   for (auto Pair : Grouped) {
194     Streamer.EmitULEB128IntValue(Pair.second);
195     Streamer.EmitULEB128IntValue(uint64_t(WebAssembly::toValType(Pair.first)));
196   }
197 }
198 
199 void WebAssemblyTargetWasmStreamer::emitGlobal(ArrayRef<MVT> Types) {
200   // Encode the globals use by the funciton into the special .global_variables
201   // section. This will later be decoded and turned into contents for the
202   // Globals Section.
203   Streamer.PushSection();
204   Streamer.SwitchSection(Streamer.getContext()
205                                  .getWasmSection(".global_variables", 0, 0));
206   for (MVT Ty : Types)
207     Streamer.EmitIntValue(uint64_t(WebAssembly::toValType(Ty)), 1);
208   Streamer.PopSection();
209 }
210 
211 void WebAssemblyTargetWasmStreamer::emitEndFunc() {
212   llvm_unreachable(".end_func is not needed for direct wasm output");
213 }
214 
215 void WebAssemblyTargetWasmStreamer::emitIndIdx(const MCExpr *Value) {
216   llvm_unreachable(".indidx encoding not yet implemented");
217 }
218 
219 void WebAssemblyTargetWasmStreamer::emitIndirectFunctionType(
220     StringRef name, SmallVectorImpl<MVT> &Params, SmallVectorImpl<MVT> &Results) {
221   // Nothing to emit here. TODO: Re-design how linking works and re-evaluate
222   // whether it's necessary for .o files to declare indirect function types.
223 }
224 
225 void WebAssemblyTargetWasmStreamer::emitGlobalImport(StringRef name) {
226 }
227