@@ -60,9 +60,7 @@ class X64Visitor : public WASMDecoder<X64Visitor>,
60
60
}
61
61
62
62
void visit_Unreachable () {}
63
-
64
63
void visit_EmtpyBlockType () {}
65
-
66
64
void visit_Drop () { m_a.asm_pop_r64 (X64Reg::rax); }
67
65
68
66
void call_imported_function (uint32_t func_idx) {
@@ -210,19 +208,58 @@ class X64Visitor : public WASMDecoder<X64Visitor>,
210
208
m_a.add_label (" .else_" + label);
211
209
}
212
210
211
+ void visit_GlobalGet (uint32_t globalidx) {
212
+ std::string loc = " global_" + std::to_string (globalidx);
213
+ std::string var_type = var_type_to_string[globals[globalidx].type ];
214
+
215
+ X64Reg base = X64Reg::rbx;
216
+ m_a.asm_mov_r64_label (X64Reg::rbx, loc);
217
+ if (var_type == " i32" || var_type == " i64" ) {
218
+ m_a.asm_mov_r64_m64 (X64Reg::rax, &base, nullptr , 1 , 0 );
219
+ m_a.asm_push_r64 (X64Reg::rax);
220
+ } else if (var_type == " f32" || var_type == " f64" ) {
221
+ m_a.asm_movsd_r64_m64 (X64FReg::xmm0, &base, nullptr , 1 , 0 );
222
+ m_a.asm_sub_r64_imm32 (X64Reg::rsp, 8 ); // create space for value to be fetched
223
+ X64Reg stack_top = X64Reg::rsp;
224
+ m_a.asm_movsd_m64_r64 (&stack_top, nullptr , 1 , 0 , X64FReg::xmm0);
225
+ } else {
226
+ throw AssemblerError (" WASM_X64: Var type not supported" );
227
+ }
228
+ }
229
+
230
+ void visit_GlobalSet (uint32_t globalidx) {
231
+ if (globals[globalidx].mut == 0 ) {
232
+ throw AssemblerError (" Attempt to modify unmutable global variable" );
233
+ }
234
+
235
+ std::string loc = " global_" + std::to_string (globalidx);
236
+ std::string var_type = var_type_to_string[globals[globalidx].type ];
237
+
238
+ X64Reg base = X64Reg::rbx;
239
+ m_a.asm_mov_r64_label (X64Reg::rbx, loc);
240
+ if (var_type == " i32" || var_type == " i64" ) {
241
+ m_a.asm_pop_r64 (X64Reg::rax);
242
+ m_a.asm_mov_m64_r64 (&base, nullptr , 1 , 0 , X64Reg::rax);
243
+ } else if (var_type == " f32" || var_type == " f64" ) {
244
+ X64Reg stack_top = X64Reg::rsp;
245
+ m_a.asm_movsd_r64_m64 (X64FReg::xmm0, &stack_top, nullptr , 1 , 0 );
246
+ m_a.asm_add_r64_imm32 (X64Reg::rsp, 8 ); // deallocate space
247
+ m_a.asm_movsd_m64_r64 (&base, nullptr , 1 , 0 , X64FReg::xmm0);
248
+ } else {
249
+ throw AssemblerError (" WASM_X64: Var type not supported" );
250
+ }
251
+ }
252
+
213
253
void visit_LocalGet (uint32_t localidx) {
214
254
X64Reg base = X64Reg::rbp;
215
255
auto cur_func_param_type = func_types[type_indices[cur_func_idx]];
216
256
int no_of_params = (int )cur_func_param_type.param_types .size ();
217
257
if ((int )localidx < no_of_params) {
218
258
std::string var_type = var_type_to_string[cur_func_param_type.param_types [localidx]];
219
- if (var_type == " i32" ) {
220
- m_a.asm_mov_r64_m64 (X64Reg::rax, &base, nullptr , 1 , 8 * (2 + no_of_params - (int )localidx - 1 ));
221
- m_a.asm_push_r64 (X64Reg::rax);
222
- } else if (var_type == " i64" ) {
259
+ if (var_type == " i32" || var_type == " i64" ) {
223
260
m_a.asm_mov_r64_m64 (X64Reg::rax, &base, nullptr , 1 , 8 * (2 + no_of_params - (int )localidx - 1 ));
224
261
m_a.asm_push_r64 (X64Reg::rax);
225
- } else if (var_type == " f64" ) {
262
+ } else if (var_type == " f32 " || var_type == " f64" ) {
226
263
m_a.asm_sub_r64_imm32 (X64Reg::rsp, 8 ); // create space for value to be fetched
227
264
m_a.asm_movsd_r64_m64 (X64FReg::xmm0, &base, nullptr , 1 , 8 * (2 + no_of_params - (int )localidx - 1 ));
228
265
X64Reg stack_top = X64Reg::rsp;
@@ -233,13 +270,10 @@ class X64Visitor : public WASMDecoder<X64Visitor>,
233
270
} else {
234
271
localidx -= no_of_params;
235
272
std::string var_type = var_type_to_string[codes[cur_func_idx].locals [localidx].type ];
236
- if (var_type == " i32" ) {
273
+ if (var_type == " i32" || var_type == " i64 " ) {
237
274
m_a.asm_mov_r64_m64 (X64Reg::rax, &base, nullptr , 1 , -8 * (1 + (int )localidx));
238
275
m_a.asm_push_r64 (X64Reg::rax);
239
- } else if (var_type == " i64" ) {
240
- m_a.asm_mov_r64_m64 (X64Reg::rax, &base, nullptr , 1 , -8 * (1 + (int )localidx));
241
- m_a.asm_push_r64 (X64Reg::rax);
242
- } else if (var_type == " f64" ) {
276
+ } else if (var_type == " f32" || var_type == " f64" ) {
243
277
m_a.asm_sub_r64_imm32 (X64Reg::rsp, 8 ); // create space for value to be fetched
244
278
m_a.asm_movsd_r64_m64 (X64FReg::xmm0, &base, nullptr , 1 , -8 * (1 + (int )localidx));
245
279
X64Reg stack_top = X64Reg::rsp;
@@ -256,13 +290,10 @@ class X64Visitor : public WASMDecoder<X64Visitor>,
256
290
int no_of_params = (int )cur_func_param_type.param_types .size ();
257
291
if ((int )localidx < no_of_params) {
258
292
std::string var_type = var_type_to_string[cur_func_param_type.param_types [localidx]];
259
- if (var_type == " i32" ) {
260
- m_a.asm_pop_r64 (X64Reg::rax);
261
- m_a.asm_mov_m64_r64 (&base, nullptr , 1 , 8 * (2 + no_of_params - (int )localidx - 1 ), X64Reg::rax);
262
- } else if (var_type == " i64" ) {
293
+ if (var_type == " i32" || var_type == " i64" ) {
263
294
m_a.asm_pop_r64 (X64Reg::rax);
264
295
m_a.asm_mov_m64_r64 (&base, nullptr , 1 , 8 * (2 + no_of_params - (int )localidx - 1 ), X64Reg::rax);
265
- } else if (var_type == " f64" ) {
296
+ } else if (var_type == " f32 " || var_type == " f64" ) {
266
297
X64Reg stack_top = X64Reg::rsp;
267
298
m_a.asm_movsd_r64_m64 (X64FReg::xmm0, &stack_top, nullptr , 1 , 0 );
268
299
m_a.asm_movsd_m64_r64 (&base, nullptr , 1 , 8 * (2 + no_of_params - (int )localidx - 1 ), X64FReg::xmm0);
@@ -273,13 +304,10 @@ class X64Visitor : public WASMDecoder<X64Visitor>,
273
304
} else {
274
305
localidx -= no_of_params;
275
306
std::string var_type = var_type_to_string[codes[cur_func_idx].locals [localidx].type ];
276
- if (var_type == " i32" ) {
307
+ if (var_type == " i32" || var_type == " i64 " ) {
277
308
m_a.asm_pop_r64 (X64Reg::rax);
278
309
m_a.asm_mov_m64_r64 (&base, nullptr , 1 , -8 * (1 + (int )localidx), X64Reg::rax);
279
- } else if (var_type == " i64" ) {
280
- m_a.asm_pop_r64 (X64Reg::rax);
281
- m_a.asm_mov_m64_r64 (&base, nullptr , 1 , -8 * (1 + (int )localidx), X64Reg::rax);
282
- } else if (var_type == " f64" ) {
310
+ } else if (var_type == " f32" || var_type == " f64" ) {
283
311
X64Reg stack_top = X64Reg::rsp;
284
312
m_a.asm_movsd_r64_m64 (X64FReg::xmm0, &stack_top, nullptr , 1 , 0 );
285
313
m_a.asm_movsd_m64_r64 (&base, nullptr , 1 , -8 * (1 + (int )localidx), X64FReg::xmm0);
@@ -290,95 +318,30 @@ class X64Visitor : public WASMDecoder<X64Visitor>,
290
318
}
291
319
}
292
320
293
- void visit_I32Const (int32_t value) {
294
- m_a.asm_mov_r64_imm64 (X64Reg::rax, labs ((int64_t )value));
295
- if (value < 0 ) m_a.asm_neg_r64 (X64Reg::rax);
296
- m_a.asm_push_r64 (X64Reg::rax);
297
- }
298
-
299
- template <typename F>
300
- void handleI32Opt (F && f) {
301
- m_a.asm_pop_r64 (X64Reg::rbx);
302
- m_a.asm_pop_r64 (X64Reg::rax);
303
- f ();
304
- m_a.asm_push_r64 (X64Reg::rax);
305
- }
306
-
307
- void visit_I32Add () {
308
- handleI32Opt ([&](){ m_a.asm_add_r64_r64 (X64Reg::rax, X64Reg::rbx);});
309
- }
310
- void visit_I32Sub () {
311
- handleI32Opt ([&](){ m_a.asm_sub_r64_r64 (X64Reg::rax, X64Reg::rbx);});
312
- }
313
- void visit_I32Mul () {
314
- handleI32Opt ([&](){ m_a.asm_mul_r64 (X64Reg::rbx);});
315
- }
316
- void visit_I32DivS () {
317
- handleI32Opt ([&](){
318
- m_a.asm_mov_r64_imm64 (X64Reg::rdx, 0 );
319
- m_a.asm_div_r64 (X64Reg::rbx);
320
- });
321
- }
322
-
323
- void visit_I32And () {
324
- handleI32Opt ([&](){ m_a.asm_and_r64_r64 (X64Reg::rax, X64Reg::rbx);});
325
- }
326
-
327
- void visit_I32Or () {
328
- handleI32Opt ([&](){ m_a.asm_or_r64_r64 (X64Reg::rax, X64Reg::rbx);});
329
- }
330
-
331
- void visit_I32Xor () {
332
- handleI32Opt ([&](){ m_a.asm_xor_r64_r64 (X64Reg::rax, X64Reg::rbx);});
333
- }
334
-
335
- void visit_I32Shl () {
336
- m_a.asm_pop_r64 (X64Reg::rcx);
337
- m_a.asm_pop_r64 (X64Reg::rax);
338
- m_a.asm_shl_r64_cl (X64Reg::rax);
339
- m_a.asm_push_r64 (X64Reg::rax);
340
- }
341
- void visit_I32ShrS () {
342
- m_a.asm_pop_r64 (X64Reg::rcx);
343
- m_a.asm_pop_r64 (X64Reg::rax);
344
- m_a.asm_sar_r64_cl (X64Reg::rax);
345
- m_a.asm_push_r64 (X64Reg::rax);
346
- }
347
-
348
- void visit_I32Eqz () {
349
- m_a.asm_mov_r64_imm64 (X64Reg::rax, 0 );
350
- m_a.asm_push_r64 (X64Reg::rax);
351
- handle_I32Compare<&X86Assembler::asm_je_label>();
352
- }
321
+ void visit_I32Const (int32_t value) { visit_I64Const (int64_t (value)); }
353
322
354
- using JumpFn = void (X86Assembler::*)(const std::string&);
355
- template <JumpFn T>
356
- void handle_I32Compare () {
357
- std::string label = std::to_string (offset);
358
- m_a.asm_pop_r64 (X64Reg::rbx);
359
- m_a.asm_pop_r64 (X64Reg::rax);
360
- // `rax` and `rbx` contain the left and right operands, respectively
361
- m_a.asm_cmp_r64_r64 (X64Reg::rax, X64Reg::rbx);
323
+ void visit_I32Add () { visit_I64Add (); }
324
+ void visit_I32Sub () { visit_I64Sub (); }
325
+ void visit_I32Mul () { visit_I64Mul (); }
326
+ void visit_I32DivS () { visit_I64DivS (); }
362
327
363
- (m_a.*T)(" .compare_1" + label);
328
+ void visit_I32And () { visit_I64And (); }
329
+ void visit_I32Or () { visit_I64Or (); }
330
+ void visit_I32Xor () { visit_I64Xor (); }
331
+ void visit_I32Shl () { visit_I64Shl (); }
332
+ void visit_I32ShrS () { visit_I64ShrS (); }
364
333
365
- // if the `compare` condition in `true`, jump to compare_1
366
- // and assign `1` else assign `0`
367
- m_a.asm_push_imm8 (0 );
368
- m_a.asm_jmp_label (" .compare.end_" + label);
369
- m_a.add_label (" .compare_1" + label);
370
- m_a.asm_push_imm8 (1 );
371
- m_a.add_label (" .compare.end_" + label);
372
- }
334
+ void visit_I32Eqz () { visit_I64Eqz (); }
335
+ void visit_I32Eq () { visit_I64Eq (); }
336
+ void visit_I32GtS () { visit_I64GtS (); }
337
+ void visit_I32GeS () { visit_I64GeS (); }
338
+ void visit_I32LtS () { visit_I64LtS (); }
339
+ void visit_I32LeS () { visit_I64LeS (); }
340
+ void visit_I32Ne () { visit_I64Ne (); }
373
341
374
- void visit_I32Eq () { handle_I32Compare<&X86Assembler::asm_je_label>(); }
375
- void visit_I32GtS () { handle_I32Compare<&X86Assembler::asm_jg_label>(); }
376
- void visit_I32GeS () { handle_I32Compare<&X86Assembler::asm_jge_label>(); }
377
- void visit_I32LtS () { handle_I32Compare<&X86Assembler::asm_jl_label>(); }
378
- void visit_I32LeS () { handle_I32Compare<&X86Assembler::asm_jle_label>(); }
379
- void visit_I32Ne () { handle_I32Compare<&X86Assembler::asm_jne_label>(); }
342
+ void visit_I32WrapI64 () { } // empty, since i32's and i64's are considered similar currently.
380
343
381
- void visit_I64Const (int32_t value) {
344
+ void visit_I64Const (int64_t value) {
382
345
m_a.asm_mov_r64_imm64 (X64Reg::rax, labs ((int64_t )value));
383
346
if (value < 0 ) m_a.asm_neg_r64 (X64Reg::rax);
384
347
m_a.asm_push_r64 (X64Reg::rax);
@@ -427,10 +390,6 @@ class X64Visitor : public WASMDecoder<X64Visitor>,
427
390
m_a.asm_push_r64 (X64Reg::rdx);
428
391
}
429
392
430
- void visit_I32WrapI64 () {
431
- // empty, since i32's and i64's are considered similar currently.
432
- }
433
-
434
393
void visit_I64Store (uint32_t /* mem_align*/ , uint32_t /* mem_offset*/ ) {
435
394
m_a.asm_pop_r64 (X64Reg::rbx);
436
395
m_a.asm_pop_r64 (X64Reg::rax);
@@ -458,6 +417,7 @@ class X64Visitor : public WASMDecoder<X64Visitor>,
458
417
handle_I64Compare<&X86Assembler::asm_je_label>();
459
418
}
460
419
420
+ using JumpFn = void (X86Assembler::*)(const std::string&);
461
421
template <JumpFn T>
462
422
void handle_I64Compare () {
463
423
std::string label = std::to_string (offset);
@@ -492,15 +452,17 @@ class X64Visitor : public WASMDecoder<X64Visitor>,
492
452
m_a.asm_push_r64 (X64Reg::rax);
493
453
}
494
454
495
- void visit_I64ExtendI32S () {
496
- // empty, since all i32's are already considered as i64's currently.
497
- }
455
+ void visit_I64ExtendI32S () { } // empty, since all i32's are already considered as i64's currently.
498
456
499
457
std::string float_to_str (double z) {
500
458
std::string float_str = " " ;
501
- for (auto ch:std::to_string (z)) {
459
+ std::ostringstream strs;
460
+ strs << z;
461
+ for (auto ch:strs.str ()) {
502
462
if (ch == ' -' ) {
503
463
float_str += " neg_" ;
464
+ } else if (ch == ' +' ) {
465
+ float_str += " _plus_" ;
504
466
} else if (ch == ' .' ) {
505
467
float_str += " _dot_" ;
506
468
} else {
@@ -577,8 +539,47 @@ class X64Visitor : public WASMDecoder<X64Visitor>,
577
539
m_a.asm_movsd_m64_r64 (&stack_top, nullptr , 1 , 0 , X64FReg::xmm0); // store float on integer stack top;
578
540
}
579
541
542
+ void visit_F64ConvertI32S () { visit_F64ConvertI64S (); } // I32's considered as I64's currently
543
+ void visit_F64PromoteF32 () { } // F32's considered as F64's currently
544
+
545
+ void visit_F64Neg () {
546
+ visit_F64Const (double (-1.0 ));
547
+ visit_F64Mul ();
548
+ }
549
+
550
+ void visit_F64Sqrt () {
551
+ X64Reg stack_top = X64Reg::rsp;
552
+ // load operand into floating-point register
553
+ m_a.asm_movsd_r64_m64 (X64FReg::xmm1, &stack_top, nullptr , 1 , 0 );
554
+ m_a.asm_add_r64_imm32 (X64Reg::rsp, 8 ); // pop the argument
555
+
556
+ m_a.asm_sqrtsd_r64_r64 (X64FReg::xmm0, X64FReg::xmm1); // perform sqrt operation
557
+
558
+ m_a.asm_sub_r64_imm32 (X64Reg::rsp, 8 ); // decrement stack and create space
559
+ m_a.asm_movsd_m64_r64 (&stack_top, nullptr , 1 , 0 , X64FReg::xmm0); // store the result on stack top;
560
+ }
561
+
562
+
563
+ void visit_F32Const (float z) { visit_F64Const (double (z)); }
564
+
565
+ void visit_F32Add () { visit_F64Add (); }
566
+ void visit_F32Sub () { visit_F64Sub (); }
567
+ void visit_F32Mul () { visit_F64Mul (); }
568
+ void visit_F32Div () { visit_F64Div (); }
569
+
570
+ void visit_F32Eq () { visit_F64Eq (); }
571
+ void visit_F32Gt () { visit_F64Gt (); }
572
+ void visit_F32Ge () { visit_F64Ge (); }
573
+ void visit_F32Lt () { visit_F64Lt (); }
574
+ void visit_F32Le () { visit_F64Le (); }
575
+ void visit_F32Ne () { visit_F64Ne (); }
576
+
577
+ void visit_F32ConvertI64S () { visit_F64ConvertI32S (); }
578
+ void visit_F32Neg () { visit_F64Neg (); }
579
+ void visit_F32Sqrt () { visit_F64Sqrt (); }
580
+
580
581
void gen_x64_bytes () {
581
- emit_elf64_header (m_a);
582
+ emit_elf64_header (m_a, 7U );
582
583
583
584
// declare compile-time strings
584
585
std::string base_memory = " " ; /* in wasm backend, memory starts after 4 bytes*/
@@ -614,6 +615,36 @@ class X64Visitor : public WASMDecoder<X64Visitor>,
614
615
emit_double_const (m_a, d.first , d.second );
615
616
}
616
617
618
+ for (size_t i = 0 ; i < globals.size (); i++) {
619
+ uint32_t tmp_offset = globals[i].insts_start_idx ;
620
+ wasm::read_b8 (wasm_bytes, tmp_offset); // read byte for i32/i64/f32/f64.const
621
+
622
+ std::string global_loc = " global_" + std::to_string (i);
623
+ switch (globals[i].type ) {
624
+ case 0x7F : {
625
+ int32_t val = wasm::read_i32 (wasm_bytes, offset);
626
+ emit_i64_const (m_a, global_loc, val);
627
+ break ;
628
+ }
629
+ case 0x7E : {
630
+ int64_t val = wasm::read_i64 (wasm_bytes, offset);
631
+ emit_i64_const (m_a, global_loc, val);
632
+ break ;
633
+ }
634
+ case 0x7D : {
635
+ float val = wasm::read_f32 (wasm_bytes, offset);
636
+ emit_double_const (m_a, global_loc, val);
637
+ break ;
638
+ }
639
+ case 0x7C : {
640
+ double val = wasm::read_f64 (wasm_bytes, offset);
641
+ emit_double_const (m_a, global_loc, val);
642
+ break ;
643
+ }
644
+ default : throw CodeGenError (" decode_global_section: Unsupport global type" ); break ;
645
+ }
646
+ }
647
+
617
648
emit_elf64_footer (m_a);
618
649
}
619
650
};
0 commit comments