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