1 // Copyright 2019 Wouter van Oortmerssen. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #ifndef WASM_BINARY_WRITER_TEST_H
16 #define WASM_BINARY_WRITER_TEST_H
17
18 #include "wasm_binary_writer.h"
19
20 using namespace std::string_view_literals;
21
22 namespace WASM {
23
24 // This is a simple test of the instruction encoding. The function returns a binary that
25 // when written to a file should pass e.g. wasm-validate.
SimpleBinaryWriterTest()26 std::vector<uint8_t> SimpleBinaryWriterTest() {
27 std::vector<uint8_t> vec;
28 BinaryWriter bw(vec);
29 // Write a (function) type section, to be referred to by functions below.
30 // For any of these sections, if you write them out of order, or don't match
31 // begin/end, you'll get an assert.
32 // As with everything, to refer to things in wasm, use a 0 based index.
33 bw.BeginSection(WASM::Section::Type);
34 // A list of arguments followed by a list of return values.
35 // You don't have to use the return value, but it may make referring to this
36 // type easier.
37 auto type_ii_i = bw.AddType({ WASM::I32, WASM::I32 }, { WASM::I32 }); // 0
38 auto type_i_v = bw.AddType({ WASM::I32 }, {}); // 1
39 bw.EndSection(WASM::Section::Type);
40
41 // Import some functions, from the runtime compiled in other modules.
42 // For our example that will just be the printing function.
43 // Note: we assume this function has been declared with: extern "C"
44 // You can link against C++ functions as well if you don't mind dealing
45 // with name mangling.
46 bw.BeginSection(WASM::Section::Import);
47 auto import_print = bw.AddImportLinkFunction("print", type_i_v); // 0
48 bw.EndSection(WASM::Section::Import);
49
50 // Declare all the functions we will generate. Note this is just the type,
51 // the body of the code will follow below.
52 bw.BeginSection(WASM::Section::Function);
53 bw.AddFunction(type_ii_i); // main()
54 bw.AddFunction(type_i_v); // TestAllInstructions()
55 bw.EndSection(WASM::Section::Function);
56
57 // We need this (and Element below) to be able to use call_indirect.
58 bw.BeginSection(WASM::Section::Table);
59 bw.AddTable();
60 bw.EndSection(WASM::Section::Table);
61
62 // Declare the linear memory we want to use, with 1 initial page.
63 bw.BeginSection(WASM::Section::Memory);
64 bw.AddMemory(1);
65 bw.EndSection(WASM::Section::Memory);
66
67 // Declare a global, used in the tests below.
68 bw.BeginSection(WASM::Section::Global);
69 bw.AddGlobal(WASM::I32, true);
70 bw.EmitI32Const(0);
71 bw.EmitEnd();
72 bw.EndSection(WASM::Section::Global);
73
74 // Here we'd normally declare a "Start" section, but the linker will
75 // take care for that for us.
76
77 // This initializes the Table declared above. Needed for call_indirect.
78 // For now we use a utility function that maps all functions ids 1:1 to the table.
79 bw.BeginSection(WASM::Section::Element);
80 bw.AddElementAllFunctions();
81 bw.EndSection(WASM::Section::Element);
82
83 // Now the exciting part: emitting function bodies.
84 bw.BeginSection(WASM::Section::Code);
85
86 // A list of 0 local types,
87 bw.AddCode({}, "main", false);
88 // Refers to data segment 0 at offset 0 below. This emits an i32.const
89 // instruction, whose immediate value will get relocated to refer to the
90 // data correctly.
91 bw.EmitI32ConstDataRef(0, 0);
92 bw.EmitCall(import_print);
93 bw.EmitI32Const(0); // Return value.
94 bw.EmitEndFunction();
95
96 // Test each instruction at least once. Needs to have correct stack inputs to pass
97 // wasm-validate etc, but is otherwise not meant to be meaningfull to execute.
98 bw.AddCode({}, "TestAllInstructions", false);
99 // Control flow.
100 bw.EmitNop();
101 bw.EmitBlock(WASM::VOID);
102 bw.EmitI32Const(true); bw.EmitBrIf(0);
103 bw.EmitBr(0);
104 bw.EmitEnd();
105 bw.EmitLoop(WASM::VOID);
106 bw.EmitI32Const(false); bw.EmitBrIf(0);
107 bw.EmitEnd();
108 bw.EmitI32Const(false); bw.EmitIf(WASM::I32);
109 bw.EmitI32Const(1);
110 bw.EmitElse();
111 bw.EmitI32Const(2);
112 bw.EmitEnd();
113 bw.EmitDrop();
114 bw.EmitBlock(WASM::VOID);
115 bw.EmitI32Const(2);
116 bw.EmitBrTable({}, 0);
117 bw.EmitEnd();
118 bw.EmitI32Const(0);
119 bw.EmitI32ConstFunctionRef(import_print);
120 bw.EmitCallIndirect(type_i_v);
121 bw.EmitI32Const(1); bw.EmitI32Const(2); bw.EmitI32Const(true); bw.EmitSelect();
122 // Variables.
123 bw.EmitGetLocal(0);
124 bw.EmitTeeLocal(0);
125 bw.EmitSetLocal(0);
126 bw.EmitGetGlobal(0);
127 bw.EmitSetGlobal(0);
128 // Memory.
129 for (int i = 0; i < 14; i++) bw.EmitI32Const(0); // Address.
130 bw.EmitI32Load(0); bw.EmitDrop();
131 bw.EmitI64Load(0); bw.EmitDrop();
132 bw.EmitF32Load(0); bw.EmitDrop();
133 bw.EmitF64Load(0); bw.EmitDrop();
134 bw.EmitI32Load8S(0); bw.EmitDrop();
135 bw.EmitI32Load8U(0); bw.EmitDrop();
136 bw.EmitI32Load16S(0); bw.EmitDrop();
137 bw.EmitI32Load16U(0); bw.EmitDrop();
138 bw.EmitI64Load8S(0); bw.EmitDrop();
139 bw.EmitI64Load8U(0); bw.EmitDrop();
140 bw.EmitI64Load16S(0); bw.EmitDrop();
141 bw.EmitI64Load16U(0); bw.EmitDrop();
142 bw.EmitI64Load32S(0); bw.EmitDrop();
143 bw.EmitI64Load32U(0); bw.EmitDrop();
144 for (int i = 0; i < 11; i++) bw.EmitI32Const(0); // Address.
145 bw.EmitI32Const(0); bw.EmitI32Store(0);
146 bw.EmitI64Const(0); bw.EmitI64Store(0);
147 bw.EmitF32Const(0); bw.EmitF32Store(0);
148 bw.EmitF64Const(0); bw.EmitF64Store(0);
149 bw.EmitI32Const(0); bw.EmitI32Store8(0);
150 bw.EmitI32Const(0); bw.EmitI32Store16(0);
151 bw.EmitI64Const(0); bw.EmitI64Store8(0);
152 bw.EmitI64Const(0); bw.EmitI64Store16(0);
153 bw.EmitI64Const(0); bw.EmitI64Store32(0);
154 bw.EmitCurrentMemory();
155 bw.EmitDrop();
156 bw.EmitGrowMemory();
157 // Equality operators.
158 bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32Eqz(); bw.EmitDrop();
159 bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32Eq(); bw.EmitDrop();
160 bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32Ne(); bw.EmitDrop();
161 bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32LtS(); bw.EmitDrop();
162 bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32LtU(); bw.EmitDrop();
163 bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32GtS(); bw.EmitDrop();
164 bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32GtU(); bw.EmitDrop();
165 bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32LeS(); bw.EmitDrop();
166 bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32LeU(); bw.EmitDrop();
167 bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32GeS(); bw.EmitDrop();
168 bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32GeU(); bw.EmitDrop();
169 bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64Eqz(); bw.EmitDrop();
170 bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64Eq(); bw.EmitDrop();
171 bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64Ne(); bw.EmitDrop();
172 bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64LtS(); bw.EmitDrop();
173 bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64LtU(); bw.EmitDrop();
174 bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64GtS(); bw.EmitDrop();
175 bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64GtU(); bw.EmitDrop();
176 bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64LeS(); bw.EmitDrop();
177 bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64LeU(); bw.EmitDrop();
178 bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64GeS(); bw.EmitDrop();
179 bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64GeU(); bw.EmitDrop();
180 bw.EmitF32Const(0); bw.EmitF32Const(0); bw.EmitF32Eq(); bw.EmitDrop();
181 bw.EmitF32Const(0); bw.EmitF32Const(0); bw.EmitF32Ne(); bw.EmitDrop();
182 bw.EmitF32Const(0); bw.EmitF32Const(0); bw.EmitF32Lt(); bw.EmitDrop();
183 bw.EmitF32Const(0); bw.EmitF32Const(0); bw.EmitF32Gt(); bw.EmitDrop();
184 bw.EmitF32Const(0); bw.EmitF32Const(0); bw.EmitF32Le(); bw.EmitDrop();
185 bw.EmitF32Const(0); bw.EmitF32Const(0); bw.EmitF32Ge(); bw.EmitDrop();
186 bw.EmitF64Const(0); bw.EmitF64Const(0); bw.EmitF64Eq(); bw.EmitDrop();
187 bw.EmitF64Const(0); bw.EmitF64Const(0); bw.EmitF64Ne(); bw.EmitDrop();
188 bw.EmitF64Const(0); bw.EmitF64Const(0); bw.EmitF64Lt(); bw.EmitDrop();
189 bw.EmitF64Const(0); bw.EmitF64Const(0); bw.EmitF64Gt(); bw.EmitDrop();
190 bw.EmitF64Const(0); bw.EmitF64Const(0); bw.EmitF64Le(); bw.EmitDrop();
191 bw.EmitF64Const(0); bw.EmitF64Const(0); bw.EmitF64Ge(); bw.EmitDrop();
192 // Numeric operators.
193 bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32Clz(); bw.EmitDrop();
194 bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32Ctz(); bw.EmitDrop();
195 bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32PopCnt(); bw.EmitDrop();
196 bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32Add(); bw.EmitDrop();
197 bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32Sub(); bw.EmitDrop();
198 bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32Mul(); bw.EmitDrop();
199 bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32DivS(); bw.EmitDrop();
200 bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32DivU(); bw.EmitDrop();
201 bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32RemS(); bw.EmitDrop();
202 bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32RemU(); bw.EmitDrop();
203 bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32And(); bw.EmitDrop();
204 bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32Or(); bw.EmitDrop();
205 bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32Xor(); bw.EmitDrop();
206 bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32Shl(); bw.EmitDrop();
207 bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32ShrS(); bw.EmitDrop();
208 bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32ShrU(); bw.EmitDrop();
209 bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32RotL(); bw.EmitDrop();
210 bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32RotR(); bw.EmitDrop();
211 bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64Clz(); bw.EmitDrop();
212 bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64Ctz(); bw.EmitDrop();
213 bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64PopCnt(); bw.EmitDrop();
214 bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64Add(); bw.EmitDrop();
215 bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64Sub(); bw.EmitDrop();
216 bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64Mul(); bw.EmitDrop();
217 bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64DivS(); bw.EmitDrop();
218 bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64DivU(); bw.EmitDrop();
219 bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64RemS(); bw.EmitDrop();
220 bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64RemU(); bw.EmitDrop();
221 bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64And(); bw.EmitDrop();
222 bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64Or(); bw.EmitDrop();
223 bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64Xor(); bw.EmitDrop();
224 bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64Shl(); bw.EmitDrop();
225 bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64ShrS(); bw.EmitDrop();
226 bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64ShrU(); bw.EmitDrop();
227 bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64RotL(); bw.EmitDrop();
228 bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64RotR(); bw.EmitDrop();
229 bw.EmitF32Const(0); bw.EmitF32Const(0); bw.EmitF32Abs(); bw.EmitDrop();
230 bw.EmitF32Const(0); bw.EmitF32Const(0); bw.EmitF32Neg(); bw.EmitDrop();
231 bw.EmitF32Const(0); bw.EmitF32Const(0); bw.EmitF32Ceil(); bw.EmitDrop();
232 bw.EmitF32Const(0); bw.EmitF32Const(0); bw.EmitF32Floor(); bw.EmitDrop();
233 bw.EmitF32Const(0); bw.EmitF32Const(0); bw.EmitF32Trunc(); bw.EmitDrop();
234 bw.EmitF32Const(0); bw.EmitF32Const(0); bw.EmitF32Nearest(); bw.EmitDrop();
235 bw.EmitF32Const(0); bw.EmitF32Const(0); bw.EmitF32Sqrt(); bw.EmitDrop();
236 bw.EmitF32Const(0); bw.EmitF32Const(0); bw.EmitF32Add(); bw.EmitDrop();
237 bw.EmitF32Const(0); bw.EmitF32Const(0); bw.EmitF32Sub(); bw.EmitDrop();
238 bw.EmitF32Const(0); bw.EmitF32Const(0); bw.EmitF32Mul(); bw.EmitDrop();
239 bw.EmitF32Const(0); bw.EmitF32Const(0); bw.EmitF32Div(); bw.EmitDrop();
240 bw.EmitF32Const(0); bw.EmitF32Const(0); bw.EmitF32Min(); bw.EmitDrop();
241 bw.EmitF32Const(0); bw.EmitF32Const(0); bw.EmitF32Max(); bw.EmitDrop();
242 bw.EmitF32Const(0); bw.EmitF32Const(0); bw.EmitF32CopySign(); bw.EmitDrop();
243 bw.EmitF64Const(0); bw.EmitF64Const(0); bw.EmitF64Abs(); bw.EmitDrop();
244 bw.EmitF64Const(0); bw.EmitF64Const(0); bw.EmitF64Neg(); bw.EmitDrop();
245 bw.EmitF64Const(0); bw.EmitF64Const(0); bw.EmitF64Ceil(); bw.EmitDrop();
246 bw.EmitF64Const(0); bw.EmitF64Const(0); bw.EmitF64Floor(); bw.EmitDrop();
247 bw.EmitF64Const(0); bw.EmitF64Const(0); bw.EmitF64Trunc(); bw.EmitDrop();
248 bw.EmitF64Const(0); bw.EmitF64Const(0); bw.EmitF64Nearest(); bw.EmitDrop();
249 bw.EmitF64Const(0); bw.EmitF64Const(0); bw.EmitF64Sqrt(); bw.EmitDrop();
250 bw.EmitF64Const(0); bw.EmitF64Const(0); bw.EmitF64Add(); bw.EmitDrop();
251 bw.EmitF64Const(0); bw.EmitF64Const(0); bw.EmitF64Sub(); bw.EmitDrop();
252 bw.EmitF64Const(0); bw.EmitF64Const(0); bw.EmitF64Mul(); bw.EmitDrop();
253 bw.EmitF64Const(0); bw.EmitF64Const(0); bw.EmitF64Div(); bw.EmitDrop();
254 bw.EmitF64Const(0); bw.EmitF64Const(0); bw.EmitF64Min(); bw.EmitDrop();
255 bw.EmitF64Const(0); bw.EmitF64Const(0); bw.EmitF64Max(); bw.EmitDrop();
256 bw.EmitF64Const(0); bw.EmitF64Const(0); bw.EmitF64CopySign(); bw.EmitDrop();
257 // Coversion operations.
258 bw.EmitI64Const(0); bw.EmitI32WrapI64(); bw.EmitDrop();
259 bw.EmitF32Const(0); bw.EmitI32TruncSF32(); bw.EmitDrop();
260 bw.EmitF32Const(0); bw.EmitI32TruncUF32(); bw.EmitDrop();
261 bw.EmitF64Const(0); bw.EmitI32TruncSF64(); bw.EmitDrop();
262 bw.EmitF64Const(0); bw.EmitI32TruncUF64(); bw.EmitDrop();
263 bw.EmitI32Const(0); bw.EmitI64ExtendSI32(); bw.EmitDrop();
264 bw.EmitI32Const(0); bw.EmitI64ExtendUI32(); bw.EmitDrop();
265 bw.EmitF32Const(0); bw.EmitI64TruncSF32(); bw.EmitDrop();
266 bw.EmitF32Const(0); bw.EmitI64TruncUF32(); bw.EmitDrop();
267 bw.EmitF64Const(0); bw.EmitI64TruncSF64(); bw.EmitDrop();
268 bw.EmitF64Const(0); bw.EmitI64TruncUF64(); bw.EmitDrop();
269 bw.EmitI32Const(0); bw.EmitF32ConvertSI32(); bw.EmitDrop();
270 bw.EmitI32Const(0); bw.EmitF32ConvertUI32(); bw.EmitDrop();
271 bw.EmitI64Const(0); bw.EmitF32ConvertSI64(); bw.EmitDrop();
272 bw.EmitI64Const(0); bw.EmitF32ConvertUI64(); bw.EmitDrop();
273 bw.EmitF64Const(0); bw.EmitF32DemoteF64(); bw.EmitDrop();
274 bw.EmitI32Const(0); bw.EmitF64ConvertSI32(); bw.EmitDrop();
275 bw.EmitI32Const(0); bw.EmitF64ConvertUI32(); bw.EmitDrop();
276 bw.EmitI64Const(0); bw.EmitF64ConvertSI64(); bw.EmitDrop();
277 bw.EmitI64Const(0); bw.EmitF64ConvertUI64(); bw.EmitDrop();
278 bw.EmitF32Const(0); bw.EmitF64PromoteF32(); bw.EmitDrop();
279 // Reinterpretations.
280 bw.EmitF32Const(0); bw.EmitI32ReinterpretF32(); bw.EmitDrop();
281 bw.EmitF64Const(0); bw.EmitI64ReinterpretF64(); bw.EmitDrop();
282 bw.EmitI32Const(0); bw.EmitF32ReinterpretI32(); bw.EmitDrop();
283 bw.EmitI64Const(0); bw.EmitF64ReinterpretI64(); bw.EmitDrop();
284 // More control flow.
285 bw.EmitReturn();
286 bw.EmitUnreachable();
287 bw.EmitEndFunction();
288
289 bw.EndSection(WASM::Section::Code);
290
291 // Add all our static data.
292 bw.BeginSection(WASM::Section::Data);
293
294 // This is our first segment, we referred to this above as 0.
295 auto hello = "Hello, World\n\0"sv;
296 // Data, name, and alignment.
297 bw.AddData(hello, "hello", 0);
298
299 // Create another segment, this time with function references.
300 int function_ref = (int)bw.GetNumFunctionImports() + 0; // Refers to main()
301 bw.AddData(std::string_view((char *)&function_ref, sizeof(int)), "funids", sizeof(int));
302 bw.DataFunctionRef(function_ref, 0); // Reloc it.
303
304 bw.EndSection(WASM::Section::Data);
305
306 // This call does all the remaining work of generating the linking
307 // information, and wrapping up the file.
308 bw.Finish();
309 return vec;
310 }
311
312 } // namespace WASM
313
314 #endif // WASM_BINARY_WRITER_TEST_H
315