all: small asm fixes and number labels ()

pull/9739/head
crthpl 2021-04-14 16:30:23 -07:00 committed by GitHub
parent 968cb13a36
commit 0099458c0a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 183 additions and 88 deletions

View File

@ -1101,9 +1101,8 @@ pub type AsmArg = AsmAddressing | AsmAlias | AsmDisp | AsmRegister | BoolLiteral
FloatLiteral | IntegerLiteral | string FloatLiteral | IntegerLiteral | string
pub struct AsmRegister { pub struct AsmRegister {
pub: pub mut:
name string // eax or r12d name string // eax or r12d etc.
mut:
typ Type typ Type
size int size int
} }
@ -1116,8 +1115,9 @@ pub:
pub struct AsmAlias { pub struct AsmAlias {
pub: pub:
pos token.Position
pub mut:
name string // a name string // a
pos token.Position
} }
pub struct AsmAddressing { pub struct AsmAddressing {

View File

@ -3839,12 +3839,9 @@ fn (mut c Checker) asm_stmt(mut stmt ast.AsmStmt) {
*/ */
if template.name !in ['skip', 'space', 'byte', 'word', 'short', 'int', 'long', 'quad', if template.name !in ['skip', 'space', 'byte', 'word', 'short', 'int', 'long', 'quad',
'globl', 'global', 'section', 'text', 'data', 'bss', 'fill', 'org', 'previous', 'globl', 'global', 'section', 'text', 'data', 'bss', 'fill', 'org', 'previous',
'string', 'asciz', 'ascii'] { // all tcc supported assembler directive 'string', 'asciz', 'ascii'] { // all tcc-supported assembler directives
c.error('unknown assembler directive: `$template.name`', template.pos) c.error('unknown assembler directive: `$template.name`', template.pos)
} }
// if c.file in {
// }
} }
for mut arg in template.args { for mut arg in template.args {
c.asm_arg(arg, stmt, aliases) c.asm_arg(arg, stmt, aliases)

View File

@ -1969,7 +1969,22 @@ fn (mut g Gen) asm_arg(arg ast.AsmArg, stmt ast.AsmStmt) {
} }
} }
ast.AsmDisp { ast.AsmDisp {
g.write(arg.val) if arg.val.len >= 2 && arg.val[0] in [`b`, `f`] {
mut is_digit := true
for c in arg.val[1..] {
if !c.is_digit() {
is_digit = false
break
}
}
if is_digit {
g.write(arg.val[1..] + rune(arg.val[0]).str())
} else {
g.write(arg.val)
}
} else {
g.write(arg.val)
}
} }
string { string {
g.write('$arg') g.write('$arg')

View File

@ -859,11 +859,11 @@ fn (mut p Parser) asm_stmt(is_top_level bool) ast.AsmStmt {
if p.tok.lit == 'volatile' && p.tok.kind == .name { if p.tok.lit == 'volatile' && p.tok.kind == .name {
arch = pref.arch_from_string(p.peek_tok.lit) or { pref.Arch._auto } arch = pref.arch_from_string(p.peek_tok.lit) or { pref.Arch._auto }
is_volatile = true is_volatile = true
p.check(.name) p.next()
} else if p.tok.kind == .key_goto { } else if p.tok.kind == .key_goto {
arch = pref.arch_from_string(p.peek_tok.lit) or { pref.Arch._auto } arch = pref.arch_from_string(p.peek_tok.lit) or { pref.Arch._auto }
is_goto = true is_goto = true
p.check(.key_goto) p.next()
} }
if arch == ._auto && !p.pref.is_fmt { if arch == ._auto && !p.pref.is_fmt {
p.error('unknown assembly architecture') p.error('unknown assembly architecture')
@ -871,7 +871,7 @@ fn (mut p Parser) asm_stmt(is_top_level bool) ast.AsmStmt {
if p.tok.kind != .name { if p.tok.kind != .name {
p.error('must specify assembly architecture') p.error('must specify assembly architecture')
} else { } else {
p.check(.name) p.next()
} }
p.check_for_impure_v(ast.pref_arch_to_table_language(arch), p.prev_tok.position()) p.check_for_impure_v(ast.pref_arch_to_table_language(arch), p.prev_tok.position())
@ -894,11 +894,14 @@ fn (mut p Parser) asm_stmt(is_top_level bool) ast.AsmStmt {
mut name := '' mut name := ''
is_directive := p.tok.kind == .dot is_directive := p.tok.kind == .dot
if is_directive { if is_directive {
p.check(.dot) 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. 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() p.next()
} else if p.tok.kind == .number {
name = p.tok.lit
p.next()
} else { } else {
name = p.tok.lit name = p.tok.lit
p.check(.name) p.check(.name)
@ -907,7 +910,7 @@ fn (mut p Parser) asm_stmt(is_top_level bool) ast.AsmStmt {
if arch in [.rv32, .rv64] { if arch in [.rv32, .rv64] {
for p.tok.kind == .dot { for p.tok.kind == .dot {
name += '.' name += '.'
p.check(.dot) p.next()
name += p.tok.lit name += p.tok.lit
p.check(.name) p.check(.name)
} }
@ -915,69 +918,92 @@ fn (mut p Parser) asm_stmt(is_top_level bool) ast.AsmStmt {
mut is_label := false mut is_label := false
mut args := []ast.AsmArg{} mut args := []ast.AsmArg{}
args_loop: for { if p.tok.line_nr == p.prev_tok.line_nr {
if p.prev_tok.position().line_nr < p.tok.position().line_nr { args_loop: for {
break if p.prev_tok.position().line_nr < p.tok.position().line_nr {
} break
match p.tok.kind {
.name {
args << p.reg_or_alias()
} }
.number { match p.tok.kind {
number_lit := p.parse_number_literal() .name {
match number_lit { if p.tok.kind == .name && p.tok.lit.len >= 2
ast.FloatLiteral { && (p.tok.lit.starts_with('b') || p.tok.lit.starts_with('f')) {
args << ast.FloatLiteral{ mut is_digit := true
...number_lit for c in p.tok.lit[1..] {
} if !c.is_digit() {
} is_digit = false
ast.IntegerLiteral { break
if is_directive {
args << ast.AsmDisp{
val: number_lit.val
pos: number_lit.pos
} }
}
if is_digit {
args << ast.AsmDisp{
val: p.tok.lit
pos: p.tok.position()
}
p.check(.name)
} else { } else {
args << ast.IntegerLiteral{ args << p.reg_or_alias()
}
} else {
args << p.reg_or_alias()
}
}
.number {
number_lit := p.parse_number_literal()
match number_lit {
ast.FloatLiteral {
args << ast.FloatLiteral{
...number_lit ...number_lit
} }
} }
} ast.IntegerLiteral {
else { if is_directive || number_lit.val.ends_with('b')
verror('p.parse_number_literal() invalid output: `$number_lit`') || number_lit.val.ends_with('f') {
args << ast.AsmDisp{
val: number_lit.val
pos: number_lit.pos
}
} else {
args << ast.IntegerLiteral{
...number_lit
}
}
}
else {
verror('p.parse_number_literal() invalid output: `$number_lit`')
}
} }
} }
} .chartoken {
.chartoken { args << ast.CharLiteral{
args << ast.CharLiteral{ val: p.tok.lit
val: p.tok.lit pos: p.tok.position()
pos: p.tok.position() }
p.next()
}
.colon {
is_label = true
p.next()
local_labels << name
break
}
.lsbr {
args << p.asm_addressing()
}
.rcbr {
break
}
.semicolon {
break
}
else {
p.error('invalid token in assembly block')
} }
p.check(.chartoken)
} }
.colon { if p.tok.kind == .comma {
is_label = true p.next()
p.check(.colon) } else {
local_labels << name
break break
} }
.lsbr {
args << p.asm_addressing()
}
.rcbr {
break
}
.semicolon {
break
}
else {
p.error('invalid token in assembly block')
}
}
if p.tok.kind == .comma {
p.check(.comma)
} else {
break
} }
// if p.prev_tok.position().line_nr < p.tok.position().line_nr { // if p.prev_tok.position().line_nr < p.tok.position().line_nr {
// break // break
@ -1015,14 +1041,14 @@ fn (mut p Parser) asm_stmt(is_top_level bool) ast.AsmStmt {
// because p.reg_or_alias() requires the scope with registers to recognize registers. // because p.reg_or_alias() requires the scope with registers to recognize registers.
backup_scope = p.scope backup_scope = p.scope
p.scope = scope p.scope = scope
p.check(.semicolon) p.next()
for p.tok.kind == .name { for p.tok.kind == .name {
reg := ast.AsmRegister{ reg := ast.AsmRegister{
name: p.tok.lit name: p.tok.lit
typ: 0 typ: 0
size: -1 size: -1
} }
p.check(.name) p.next()
mut comments := []ast.Comment{} mut comments := []ast.Comment{}
for p.tok.kind == .comment { for p.tok.kind == .comment {
@ -1039,10 +1065,10 @@ fn (mut p Parser) asm_stmt(is_top_level bool) ast.AsmStmt {
} }
if is_goto && p.tok.kind == .semicolon { if is_goto && p.tok.kind == .semicolon {
p.check(.semicolon) p.next()
for p.tok.kind == .name { for p.tok.kind == .name {
global_labels << p.tok.lit global_labels << p.tok.lit
p.check(.name) p.next()
} }
} }
} }
@ -1074,7 +1100,6 @@ fn (mut p Parser) asm_stmt(is_top_level bool) ast.AsmStmt {
} }
fn (mut p Parser) reg_or_alias() ast.AsmArg { fn (mut p Parser) reg_or_alias() ast.AsmArg {
assert p.tok.kind == .name
if p.tok.lit in p.scope.objects { if p.tok.lit in p.scope.objects {
x := p.scope.objects[p.tok.lit] x := p.scope.objects[p.tok.lit]
if x is ast.AsmRegister { if x is ast.AsmRegister {
@ -1200,7 +1225,7 @@ fn (mut p Parser) asm_addressing() ast.AsmAddressing {
} else if p.tok.kind == .number { } else if p.tok.kind == .number {
displacement := if p.tok.kind == .name { displacement := if p.tok.kind == .name {
x := ast.AsmArg(p.tok.lit) x := ast.AsmArg(p.tok.lit)
p.check(.name) p.next()
x x
} else { } else {
x := ast.AsmArg(p.tok.lit) x := ast.AsmArg(p.tok.lit)
@ -1220,11 +1245,11 @@ fn (mut p Parser) asm_addressing() ast.AsmAddressing {
if p.peek_tok.kind == .plus && p.tok.kind == .name { // [base + displacement], [base + index scale + displacement], [base + index + displacement] or [rip + displacement] if p.peek_tok.kind == .plus && p.tok.kind == .name { // [base + displacement], [base + index scale + displacement], [base + index + displacement] or [rip + displacement]
if p.tok.lit == 'rip' { if p.tok.lit == 'rip' {
rip := p.reg_or_alias() rip := p.reg_or_alias()
p.check(.plus) p.next()
displacement := if p.tok.kind == .name { displacement := if p.tok.kind == .name {
x := ast.AsmArg(p.tok.lit) x := ast.AsmArg(p.tok.lit)
p.check(.name) p.next()
x x
} else { } else {
x := ast.AsmArg(p.tok.lit) x := ast.AsmArg(p.tok.lit)
@ -1240,16 +1265,16 @@ fn (mut p Parser) asm_addressing() ast.AsmAddressing {
} }
} }
base := p.reg_or_alias() base := p.reg_or_alias()
p.check(.plus) p.next()
if p.peek_tok.kind == .rsbr { if p.peek_tok.kind == .rsbr {
if p.tok.kind == .number { if p.tok.kind == .number {
displacement := if p.tok.kind == .name { displacement := if p.tok.kind == .name {
x := ast.AsmArg(p.tok.lit) x := ast.AsmArg(p.tok.lit)
p.check(.name) p.next()
x x
} else { } else {
x := ast.AsmArg(p.tok.lit) x := ast.AsmArg(p.tok.lit)
p.check(.name) p.check(.number)
x x
} }
p.check(.rsbr) p.check(.rsbr)
@ -1265,13 +1290,13 @@ fn (mut p Parser) asm_addressing() ast.AsmAddressing {
} }
index := p.reg_or_alias() index := p.reg_or_alias()
if p.tok.kind == .mul { if p.tok.kind == .mul {
p.check(.mul) p.next()
scale := p.tok.lit.int() scale := p.tok.lit.int()
p.check(.number) p.check(.number)
p.check(.plus) p.check(.plus)
displacement := if p.tok.kind == .name { displacement := if p.tok.kind == .name {
x := ast.AsmArg(p.tok.lit) x := ast.AsmArg(p.tok.lit)
p.check(.name) p.next()
x x
} else { } else {
x := ast.AsmArg(p.tok.lit) x := ast.AsmArg(p.tok.lit)
@ -1288,10 +1313,10 @@ fn (mut p Parser) asm_addressing() ast.AsmAddressing {
pos: pos.extend(p.prev_tok.position()) pos: pos.extend(p.prev_tok.position())
} }
} else if p.tok.kind == .plus { } else if p.tok.kind == .plus {
p.check(.plus) p.next()
displacement := if p.tok.kind == .name { displacement := if p.tok.kind == .name {
x := ast.AsmArg(p.tok.lit) x := ast.AsmArg(p.tok.lit)
p.check(.name) p.next()
x x
} else { } else {
x := ast.AsmArg(p.tok.lit) x := ast.AsmArg(p.tok.lit)
@ -1310,13 +1335,13 @@ fn (mut p Parser) asm_addressing() ast.AsmAddressing {
} }
if p.peek_tok.kind == .mul { // [index scale + displacement] if p.peek_tok.kind == .mul { // [index scale + displacement]
index := p.reg_or_alias() index := p.reg_or_alias()
p.check(.mul) p.next()
scale := p.tok.lit.int() scale := p.tok.lit.int()
p.check(.number) p.check(.number)
p.check(.plus) p.check(.plus)
displacement := if p.tok.kind == .name { displacement := if p.tok.kind == .name {
x := ast.AsmArg(p.tok.lit) x := ast.AsmArg(p.tok.lit)
p.check(.name) p.next()
x x
} else { } else {
x := ast.AsmArg(p.tok.lit) x := ast.AsmArg(p.tok.lit)
@ -1371,10 +1396,10 @@ fn (mut p Parser) asm_ios(output bool) []ast.AsmIO {
} }
if p.tok.kind == .assign { if p.tok.kind == .assign {
constraint += '=' constraint += '='
p.check(.assign) p.next()
} else if p.tok.kind == .plus { } else if p.tok.kind == .plus {
constraint += '+' constraint += '+'
p.check(.plus) p.next()
} }
constraint += p.tok.lit constraint += p.tok.lit
p.check(.name) p.check(.name)
@ -1387,7 +1412,7 @@ fn (mut p Parser) asm_ios(output bool) []ast.AsmIO {
} }
mut alias := '' mut alias := ''
if p.tok.kind == .key_as { if p.tok.kind == .key_as {
p.check(.key_as) p.next()
alias = p.tok.lit alias = p.tok.lit
p.check(.name) p.check(.name)
} else if mut expr is ast.Ident { } else if mut expr is ast.Ident {

View File

@ -96,7 +96,36 @@ fn test_inline_asm() {
} }
assert n == [7, 11, 2, 6] assert n == [7, 11, 2, 6]
assert util.add(8, 9, 34, 7) == 58 // test .amd64.v files assert util.add(8, 9, 34, 7) == 58 // test .amd64.v imported files
mut manu := Manu{}
asm amd64 {
mov eax, 0
cpuid
; =b (manu.ebx) as ebx0
=d (manu.edx) as edx0
=c (manu.ecx) as ecx0
}
manu.str()
}
[packed]
struct Manu {
mut:
ebx u32
edx u32
ecx u32
zero byte // for string
}
fn (m Manu) str() string {
return unsafe {
string{
str: &byte(&m)
len: 24
is_lit: 1
}
}
} }
// this test does not appear in i386 test since rip relative addressing was introduced in 64-bit mode // this test does not appear in i386 test since rip relative addressing was introduced in 64-bit mode

View File

@ -95,4 +95,33 @@ fn test_inline_asm() {
r (n.data) as in_data r (n.data) as in_data
} }
assert n == [7, 11, 2, 6] assert n == [7, 11, 2, 6]
mut manu := Manu{}
asm amd64 {
mov eax, 0
cpuid
; =b (manu.ebx) as ebx0
=d (manu.edx) as edx0
=c (manu.ecx) as ecx0
}
manu.str()
}
[packed]
struct Manu {
mut:
ebx u32
edx u32
ecx u32
zero byte // for string
}
fn (m Manu) str() string {
return unsafe {
string{
str: &byte(&m)
len: 24
is_lit: 1
}
}
} }

View File

@ -3,9 +3,9 @@ module util
pub fn add(a ...int) int { pub fn add(a ...int) int {
mut res := 0 mut res := 0
asm amd64 { asm amd64 {
loop_start3: 1:
addq rax, [in_data + rcx * 4 + 0] addq rax, [in_data + rcx * 4 + 0]
loop loop_start3 loop b1
addq rax, [in_data + rcx * 4 + 0] addq rax, [in_data + rcx * 4 + 0]
; +a (res) ; +a (res)
; c (a.len - 1) // c is counter (loop) register ; c (a.len - 1) // c is counter (loop) register