From 4688c75389c51829014b83e8659fcff0e5c98308 Mon Sep 17 00:00:00 2001 From: crthpl <56052645+crthpl@users.noreply.github.com> Date: Thu, 17 Jun 2021 15:20:46 -0700 Subject: [PATCH] cgen, parser: fix several assembly bugs (#10498) --- vlib/v/gen/c/cgen.v | 14 ++++- vlib/v/parser/parser.v | 77 ++++++++++++++++---------- vlib/v/tests/assembly/asm_test.amd64.v | 57 ++++++++++++++----- 3 files changed, 101 insertions(+), 47 deletions(-) diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 75382d2362..01d96a810f 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -1950,7 +1950,7 @@ fn (mut g Gen) gen_asm_stmt(stmt ast.AsmStmt) { g.write(' ') } // swap destionation and operands for att syntax - if template.args.len != 0 { + if template.args.len != 0 && !template.is_directive { template.args.prepend(template.args[template.args.len - 1]) template.args.delete(template.args.len - 1) } @@ -2052,8 +2052,16 @@ fn (mut g Gen) asm_arg(arg ast.AsmArg, stmt ast.AsmStmt) { g.write(')') } .index_times_scale_plus_displacement { - g.asm_arg(displacement, stmt) - g.write('(') + if displacement is ast.AsmDisp { + g.asm_arg(displacement, stmt) + g.write('(, ') + } else if displacement is ast.AsmRegister { + g.write('(') + g.asm_arg(displacement, stmt) + g.write(',') + } else { + panic('unexpected $displacement.type_name()') + } g.asm_arg(index, stmt) g.write(',$scale)') } diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 8dcc611b0c..35dcebfd90 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -885,22 +885,32 @@ fn (mut p Parser) asm_stmt(is_top_level bool) ast.AsmStmt { for p.tok.kind !in [.semicolon, .rcbr] { template_pos := p.tok.position() mut name := '' + if p.tok.kind == .name && arch == .amd64 && p.tok.lit in ['rex', 'vex', 'xop'] { + name += p.tok.lit + p.next() + for p.tok.kind == .dot { + p.next() + name += '.' + p.tok.lit + p.check(.name) + } + name += ' ' + } is_directive := p.tok.kind == .dot if is_directive { p.next() } if p.tok.kind in [.key_in, .key_lock, .key_orelse] { // `in`, `lock`, `or` are v keywords that are also x86/arm/riscv instructions. - name = p.tok.kind.str() + name += p.tok.kind.str() p.next() } else if p.tok.kind == .number { - name = p.tok.lit + name += p.tok.lit p.next() } else { - name = p.tok.lit + name += p.tok.lit p.check(.name) } // dots are part of instructions for some riscv extensions - if arch in [.rv32, .rv64, .amd64] { + if arch in [.rv32, .rv64] { for p.tok.kind == .dot { name += '.' p.next() @@ -949,8 +959,9 @@ fn (mut p Parser) asm_stmt(is_top_level bool) ast.AsmStmt { } } ast.IntegerLiteral { - if is_directive || number_lit.val.ends_with('b') - || number_lit.val.ends_with('f') { + if (is_directive || number_lit.val.ends_with('b') + || number_lit.val.ends_with('f')) + && !number_lit.val.starts_with('0x') { args << ast.AsmDisp{ val: number_lit.val pos: number_lit.pos @@ -1217,11 +1228,12 @@ fn (mut p Parser) asm_addressing() ast.AsmAddressing { } } else if p.tok.kind == .number { displacement := if p.tok.kind == .name { - x := ast.AsmArg(p.tok.lit) - p.next() - x + p.reg_or_alias() } else { - x := ast.AsmArg(p.tok.lit) + x := ast.AsmArg(ast.AsmDisp{ + val: p.tok.lit + pos: p.tok.position() + }) p.check(.number) x } @@ -1241,11 +1253,12 @@ fn (mut p Parser) asm_addressing() ast.AsmAddressing { p.next() displacement := if p.tok.kind == .name { - x := ast.AsmArg(p.tok.lit) - p.next() - x + p.reg_or_alias() } else { - x := ast.AsmArg(p.tok.lit) + x := ast.AsmArg(ast.AsmDisp{ + val: p.tok.lit + pos: p.tok.position() + }) p.check(.number) x } @@ -1262,11 +1275,12 @@ fn (mut p Parser) asm_addressing() ast.AsmAddressing { if p.peek_tok.kind == .rsbr { if p.tok.kind == .number { displacement := if p.tok.kind == .name { - x := ast.AsmArg(p.tok.lit) - p.next() - x + p.reg_or_alias() } else { - x := ast.AsmArg(p.tok.lit) + x := ast.AsmArg(ast.AsmDisp{ + val: p.tok.lit + pos: p.tok.position() + }) p.check(.number) x } @@ -1288,11 +1302,12 @@ fn (mut p Parser) asm_addressing() ast.AsmAddressing { p.check(.number) p.check(.plus) displacement := if p.tok.kind == .name { - x := ast.AsmArg(p.tok.lit) - p.next() - x + p.reg_or_alias() } else { - x := ast.AsmArg(p.tok.lit) + x := ast.AsmArg(ast.AsmDisp{ + val: p.tok.lit + pos: p.tok.position() + }) p.check(.number) x } @@ -1308,11 +1323,12 @@ fn (mut p Parser) asm_addressing() ast.AsmAddressing { } else if p.tok.kind == .plus { p.next() displacement := if p.tok.kind == .name { - x := ast.AsmArg(p.tok.lit) - p.next() - x + p.reg_or_alias() } else { - x := ast.AsmArg(p.tok.lit) + x := ast.AsmArg(ast.AsmDisp{ + val: p.tok.lit + pos: p.tok.position() + }) p.check(.number) x } @@ -1333,11 +1349,12 @@ fn (mut p Parser) asm_addressing() ast.AsmAddressing { p.check(.number) p.check(.plus) displacement := if p.tok.kind == .name { - x := ast.AsmArg(p.tok.lit) - p.next() - x + p.reg_or_alias() } else { - x := ast.AsmArg(p.tok.lit) + x := ast.AsmArg(ast.AsmDisp{ + val: p.tok.lit + pos: p.tok.position() + }) p.check(.number) x } diff --git a/vlib/v/tests/assembly/asm_test.amd64.v b/vlib/v/tests/assembly/asm_test.amd64.v index 1f8c04b542..18e84402db 100644 --- a/vlib/v/tests/assembly/asm_test.amd64.v +++ b/vlib/v/tests/assembly/asm_test.amd64.v @@ -80,6 +80,7 @@ fn test_inline_asm() { asm amd64 { movq [m], 7 // have to specify size with q ; ; r (m) + ; memory } assert l == 7 @@ -98,15 +99,15 @@ fn test_inline_asm() { assert util.add(8, 9, 34, 7) == 58 // test .amd64.v imported files - mut manu := Manu{} + mut o := Manu{} asm amd64 { mov eax, 0 cpuid - ; =b (manu.ebx) as ebx0 - =d (manu.edx) as edx0 - =c (manu.ecx) as ecx0 + ; =b (o.ebx) as ebx0 + =d (o.edx) as edx0 + =c (o.ecx) as ecx0 } - manu.str() + o.str() } [packed] @@ -129,19 +130,47 @@ fn (m Manu) str() string { } // this test does not appear in i386 test since rip relative addressing was introduced in 64-bit mode +// doesn't actually work +[if !macos] fn test_rip_relative_label() { - mut a := i64(4) - asm amd64 { - mov a, [rip + one_two_three] // see below - ; =r (a) + $if !macos { + mut a := i64(4) + asm amd64 { + mov a, [rip + one_two_three] // see below + ; =r (a) + } + assert a == 48321074923 } - assert a == 48321074923 } -asm amd64 { - .global one_two_three - one_two_three: - .quad 48321074923 +$if !macos { + asm amd64 { + .global one_two_three + one_two_three: + .quad 48321074923 + } +} + +// this test does not appear in i386 test since rip relative addressing was introduced in 64-bit mode +// doesn't actually work +[if !macos] +fn test_rip_relative_label_byte() { + $if !macos { + mut a := int(4) + asm amd64 { + mov a, [rip + byte_sequence] // see below + ; =r (a) + } + assert a == 0x480f3527 + } +} + +$if !macos { + asm amd64 { + .global one_two_three + byte_sequence: + .byte 0x27, 0x35, 0x0f, 0x48 + } } fn test_flag_output() {