asm: make fixed labels possible as displacement (#9549)
parent
63f835c4ce
commit
8d5e310189
|
@ -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
|
||||
|
|
|
@ -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 {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue