asm: make fixed labels possible as displacement (#9549)

pull/9543/head
crthpl 2021-03-31 23:58:33 -07:00 committed by GitHub
parent 63f835c4ce
commit 8d5e310189
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 172 additions and 68 deletions

View File

@ -540,6 +540,7 @@ pub mut:
warnings []errors.Warning // all the checker warnings in the file
notices []errors.Notice // all the checker notices in the file
generic_fns []&FnDecl
global_labels []string // from `asm { .globl labelname }`
}
pub struct IdentFn {
@ -1064,13 +1065,12 @@ pub:
clobbered []AsmClobbered
pos token.Position
pub mut:
templates []AsmTemplate
scope &Scope
output []AsmIO
input []AsmIO
global_labels []string // listed after clobbers, paired with is_goto == true
local_labels []string // local to the assembly block
exported_symbols []string // functions defined in assembly block, exported with `.globl`
templates []AsmTemplate
scope &Scope
output []AsmIO
input []AsmIO
global_labels []string // labels defined in assembly block, exported with `.globl`
local_labels []string // local to the assembly block
}
pub struct AsmTemplate {
@ -1083,8 +1083,8 @@ pub mut:
pos token.Position
}
// [eax+5] | j | eax | true | `a` | 0.594 | 123 | 'hi' | label_name
pub type AsmArg = AsmAddressing | AsmAlias | AsmRegister | BoolLiteral | CharLiteral |
// [eax+5] | j | displacement literal (e.g. 123 in [rax + 123] ) | eax | true | `a` | 0.594 | 123 | label_name
pub type AsmArg = AsmAddressing | AsmAlias | AsmDisp | AsmRegister | BoolLiteral | CharLiteral |
FloatLiteral | IntegerLiteral | string
pub struct AsmRegister {
@ -1095,6 +1095,12 @@ mut:
size int
}
pub struct AsmDisp {
pub:
val string
pos token.Position
}
pub struct AsmAlias {
pub:
name string // a
@ -1103,13 +1109,13 @@ pub:
pub struct AsmAddressing {
pub:
displacement u32 // 8, 16 or 32 bit literal value
scale int = -1 // 1, 2, 4, or 8 literal
mode AddressingMode
pos token.Position
scale int = -1 // 1, 2, 4, or 8 literal
mode AddressingMode
pos token.Position
pub mut:
base AsmArg // gpr
index AsmArg // gpr
displacement AsmArg // 8, 16 or 32 bit literal value
base AsmArg // gpr
index AsmArg // gpr
}
// adressing modes:
@ -1125,9 +1131,8 @@ pub enum AddressingMode {
}
pub struct AsmClobbered {
pub:
reg AsmRegister
pub mut:
reg AsmRegister
comments []Comment
}
@ -1204,7 +1209,7 @@ pub const (
)
// TODO: saved priviled registers for arm
const (
pub const (
arm_no_number_register_list = ['fp' /* aka r11 */, /* not instruction pointer: */ 'ip' /* aka r12 */,
'sp' /* aka r13 */, 'lr' /* aka r14 */, /* this is instruction pointer ('program counter'): */
'pc' /* aka r15 */,
@ -1214,7 +1219,7 @@ const (
}
)
const (
pub const (
riscv_no_number_register_list = ['zero', 'ra', 'sp', 'gp', 'tp']
riscv_with_number_register_list = map{
'x#': 32

View File

@ -3768,11 +3768,11 @@ fn (mut c Checker) asm_stmt(mut stmt ast.AsmStmt) {
// }
}
for arg in template.args {
for mut arg in template.args {
c.asm_arg(arg, stmt, aliases)
}
}
for clob in stmt.clobbered {
for mut clob in stmt.clobbered {
c.asm_arg(clob.reg, stmt, aliases)
}
}
@ -3781,8 +3781,11 @@ fn (mut c Checker) asm_arg(arg ast.AsmArg, stmt ast.AsmStmt, aliases []string) {
match mut arg {
ast.AsmAlias {
name := arg.name
if name !in aliases && name !in stmt.local_labels && name !in stmt.global_labels {
suggestion := util.new_suggestion(name, aliases)
if name !in aliases && name !in stmt.local_labels && name !in c.file.global_labels {
mut possible := aliases.clone()
possible << stmt.local_labels
possible << c.file.global_labels
suggestion := util.new_suggestion(name, possible)
c.error(suggestion.say('alias or label `$arg.name` does not exist'), arg.pos)
}
}
@ -3790,6 +3793,7 @@ fn (mut c Checker) asm_arg(arg ast.AsmArg, stmt ast.AsmStmt, aliases []string) {
if arg.scale !in [-1, 1, 2, 4, 8] {
c.error('scale must be one of 1, 2, 4, or 8', arg.pos)
}
c.asm_arg(arg.displacement, stmt, aliases)
c.asm_arg(arg.base, stmt, aliases)
c.asm_arg(arg.index, stmt, aliases)
}
@ -3798,6 +3802,7 @@ fn (mut c Checker) asm_arg(arg ast.AsmArg, stmt ast.AsmStmt, aliases []string) {
ast.CharLiteral {}
ast.IntegerLiteral {}
ast.AsmRegister {} // if the register is not found, the parser will register it as an alias
ast.AsmDisp {}
string {}
}
}

View File

@ -750,31 +750,36 @@ fn (mut f Fmt) asm_arg(arg ast.AsmArg) {
f.asm_arg(base)
}
.displacement {
f.write('$displacement')
f.asm_arg(displacement)
}
.base_plus_displacement {
f.asm_arg(base)
f.write(' + $displacement')
f.write(' + ')
f.asm_arg(displacement)
}
.index_times_scale_plus_displacement {
f.asm_arg(index)
f.write(' * $scale + $displacement')
f.write(' * $scale + ')
f.asm_arg(displacement)
}
.base_plus_index_plus_displacement {
f.asm_arg(base)
f.write(' + ')
f.asm_arg(index)
f.write(' + $displacement')
f.write(' + ')
f.asm_arg(displacement)
}
.base_plus_index_times_scale_plus_displacement {
f.asm_arg(base)
f.write(' + ')
f.asm_arg(index)
f.write(' * $scale + $displacement')
f.write(' * $scale + ')
f.asm_arg(displacement)
}
.rip_plus_displacement {
f.asm_arg(base)
f.write(' + $displacement')
f.write(' + ')
f.asm_arg(displacement)
}
.invalid {
panic('fmt: invalid addressing mode')
@ -782,6 +787,9 @@ fn (mut f Fmt) asm_arg(arg ast.AsmArg) {
}
f.write(']')
}
ast.AsmDisp {
f.write(arg.val)
}
}
}

View File

@ -1861,12 +1861,9 @@ fn (mut g Gen) asm_arg(arg ast.AsmArg, stmt ast.AsmStmt) {
match arg {
ast.AsmAlias {
name := arg.name
if name in stmt.local_labels || name in stmt.global_labels {
asm_formatted_name := if name in stmt.local_labels {
name
} else { // val in stmt.global_labels
'%l[$name]'
}
if name in stmt.local_labels || name in stmt.global_labels
|| name in g.file.global_labels {
asm_formatted_name := if name in stmt.global_labels { '%l[$name]' } else { name }
g.write(asm_formatted_name)
} else {
g.write('%[$name]')
@ -1896,43 +1893,53 @@ fn (mut g Gen) asm_arg(arg ast.AsmArg, stmt ast.AsmStmt) {
.base {
g.write('(')
g.asm_arg(base, stmt)
g.write(')')
}
.displacement {
g.write('${displacement}(')
g.asm_arg(displacement, stmt)
g.write('()')
}
.base_plus_displacement {
g.write('${displacement}(')
g.asm_arg(displacement, stmt)
g.write('(')
g.asm_arg(base, stmt)
g.write(')')
}
.index_times_scale_plus_displacement {
g.write('${displacement}(,')
g.asm_arg(displacement, stmt)
g.write('(')
g.asm_arg(index, stmt)
g.write(',')
g.write(scale.str())
g.write(',$scale)')
}
.base_plus_index_plus_displacement {
g.write('${displacement}(')
g.asm_arg(displacement, stmt)
g.write('(')
g.asm_arg(base, stmt)
g.write(',')
g.asm_arg(index, stmt)
g.write(',1')
g.write(',1)')
}
.base_plus_index_times_scale_plus_displacement {
g.write('${displacement}(')
g.asm_arg(displacement, stmt)
g.write('(')
g.asm_arg(base, stmt)
g.write(',')
g.asm_arg(index, stmt)
g.write(',$scale')
g.write(',$scale)')
}
.rip_plus_displacement {
g.write('${displacement}(')
g.asm_arg(displacement, stmt)
g.write('(')
g.asm_arg(base, stmt)
g.write(')')
}
.invalid {
g.error('invalid addressing mode', arg.pos)
}
}
g.write(')')
}
ast.AsmDisp {
g.write(arg.val)
}
string {
g.write('$arg')
@ -1945,7 +1952,9 @@ fn (mut g Gen) gen_asm_ios(ios []ast.AsmIO) {
if io.alias != '' {
g.write('[$io.alias] ')
}
g.write('"$io.constraint" ($io.expr)')
g.write('"$io.constraint" (')
g.expr(io.expr)
g.write(')')
if i + 1 < ios.len {
g.writeln(',')
} else {

View File

@ -73,6 +73,7 @@ mut:
n_asm int // controls assembly labels
inside_asm_template bool
inside_asm bool
global_labels []string
}
// for tests
@ -281,6 +282,7 @@ pub fn (mut p Parser) parse() ast.File {
global_scope: p.global_scope
errors: p.errors
warnings: p.warnings
global_labels: p.global_labels
}
}
@ -876,7 +878,6 @@ fn (mut p Parser) asm_stmt(is_top_level bool) ast.AsmStmt {
}
mut local_labels := []string{}
mut exported_symbols := []string{}
// riscv: https://github.com/jameslzhu/riscv-card/blob/master/riscv-card.pdf
// x86: https://www.felixcloutier.com/x86/
// arm: https://developer.arm.com/documentation/dui0068/b/arm-instruction-reference
@ -921,8 +922,15 @@ fn (mut p Parser) asm_stmt(is_top_level bool) ast.AsmStmt {
}
}
ast.IntegerLiteral {
args << ast.IntegerLiteral{
...number_lit
if is_directive {
args << ast.AsmDisp{
val: number_lit.val
pos: number_lit.pos
}
} else {
args << ast.IntegerLiteral{
...number_lit
}
}
}
else {
@ -967,7 +975,9 @@ fn (mut p Parser) asm_stmt(is_top_level bool) ast.AsmStmt {
comments << p.comment()
}
if is_directive && name in ['globl', 'global'] {
exported_symbols << args
for arg in args {
p.global_labels << (arg as ast.AsmAlias).name
}
}
templates << ast.AsmTemplate{
name: name
@ -1045,7 +1055,6 @@ fn (mut p Parser) asm_stmt(is_top_level bool) ast.AsmStmt {
scope: scope
global_labels: global_labels
local_labels: local_labels
exported_symbols: exported_symbols
}
}
@ -1058,7 +1067,8 @@ fn (mut p Parser) reg_or_alias() ast.AsmArg {
p.check(.name)
return b
} else {
panic('parser bug: non-register ast.ScopeObject found in scope')
verror('parser bug: non-register ast.ScopeObject found in scope')
return ast.AsmDisp{} // should not be reached
}
} else {
p.check(.name)
@ -1173,8 +1183,15 @@ fn (mut p Parser) asm_addressing() ast.AsmAddressing {
pos: pos.extend(p.prev_tok.position())
}
} else if p.tok.kind == .number {
displacement := p.tok.lit.u32()
p.check(.name)
displacement := if p.tok.kind == .name {
x := ast.AsmArg(p.tok.lit)
p.check(.name)
x
} else {
x := ast.AsmArg(p.tok.lit)
p.check(.number)
x
}
p.check(.rsbr)
return ast.AsmAddressing{
mode: .displacement
@ -1187,13 +1204,22 @@ 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.tok.lit == 'rip' {
p.check(.name)
rip := p.reg_or_alias()
p.check(.plus)
displacement := p.tok.lit.u32()
p.check(.number)
displacement := if p.tok.kind == .name {
x := ast.AsmArg(p.tok.lit)
p.check(.name)
x
} else {
x := ast.AsmArg(p.tok.lit)
p.check(.number)
x
}
p.check(.rsbr)
return ast.AsmAddressing{
mode: .rip_plus_displacement
base: 'rip'
base: rip
displacement: displacement
pos: pos.extend(p.prev_tok.position())
}
@ -1202,8 +1228,15 @@ fn (mut p Parser) asm_addressing() ast.AsmAddressing {
p.check(.plus)
if p.peek_tok.kind == .rsbr {
if p.tok.kind == .number {
displacement := p.tok.lit.u32()
p.check(.number)
displacement := if p.tok.kind == .name {
x := ast.AsmArg(p.tok.lit)
p.check(.name)
x
} else {
x := ast.AsmArg(p.tok.lit)
p.check(.name)
x
}
p.check(.rsbr)
return ast.AsmAddressing{
mode: .base_plus_displacement
@ -1221,8 +1254,15 @@ fn (mut p Parser) asm_addressing() ast.AsmAddressing {
scale := p.tok.lit.int()
p.check(.number)
p.check(.plus)
displacement := p.tok.lit.u32()
p.check(.number)
displacement := if p.tok.kind == .name {
x := ast.AsmArg(p.tok.lit)
p.check(.name)
x
} else {
x := ast.AsmArg(p.tok.lit)
p.check(.number)
x
}
p.check(.rsbr)
return ast.AsmAddressing{
mode: .base_plus_index_times_scale_plus_displacement
@ -1234,8 +1274,15 @@ fn (mut p Parser) asm_addressing() ast.AsmAddressing {
}
} else if p.tok.kind == .plus {
p.check(.plus)
displacement := p.tok.lit.u32()
p.check(.number)
displacement := if p.tok.kind == .name {
x := ast.AsmArg(p.tok.lit)
p.check(.name)
x
} else {
x := ast.AsmArg(p.tok.lit)
p.check(.number)
x
}
p.check(.rsbr)
return ast.AsmAddressing{
mode: .base_plus_index_plus_displacement
@ -1252,8 +1299,15 @@ fn (mut p Parser) asm_addressing() ast.AsmAddressing {
scale := p.tok.lit.int()
p.check(.number)
p.check(.plus)
displacement := p.tok.lit.u32()
p.check(.number)
displacement := if p.tok.kind == .name {
x := ast.AsmArg(p.tok.lit)
p.check(.name)
x
} else {
x := ast.AsmArg(p.tok.lit)
p.check(.number)
x
}
p.check(.rsbr)
return ast.AsmAddressing{
mode: .index_times_scale_plus_displacement

View File

@ -1,7 +1,7 @@
import v.tests.assembly.util
fn test_inline_asm() {
a, mut b := 10, 0
a, mut b := i64(10), i64(0)
asm amd64 {
mov rax, a
mov b, rax
@ -97,3 +97,26 @@ fn test_inline_asm() {
assert util.add(8, 9, 34, 7) == 58 // test .amd64.v files
}
// this test does not appear in i386 test since rip relative addressing was introduced in 64-bit mode
fn test_rip_relative_label() {
mut a := i64(4)
asm amd64 {
mov a, [rip + one_two_three] // see below
; =r (a)
}
assert a == 48321074923
mut b := i64(4)
asm amd64 {
mov b, one_two_three // see below
; =r (b)
}
assert b == 48321074923
}
asm amd64 {
.global one_two_three
one_two_three:
.quad 48321074923
}