authorgravatar for topolarity@tapscott.meCody Tapscott <topolarity@tapscott.me> 2022-11-10 14:02:05-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-01-09 14:00:11-07:00
logbc3324365090f3c9077df147b52fbc0c3c19b753
tree2df30175dbb4430ac32694add75597e4845f46d9
parent48798da29b368cf934ed81eb19a6fbf5c5aa3de9

stage2: Support modifiers in inline asm

These are supported using %[ident:mod] syntax. This allows requesting, e.g., the "w" (32-bit) vs. "x" (64-bit) views of AArch64 registers. See https://llvm.org/docs/LangRef.html#asm-template-argument-modifiers

2 files changed, 33 insertions(+), 3 deletions(-)

src/codegen/llvm.zig+20-3
...@@ -6290,11 +6290,12 @@ pub const FuncGen = struct {...@@ -6290,11 +6290,12 @@ pub const FuncGen = struct {
6290 var rendered_template = std.ArrayList(u8).init(self.gpa);6290 var rendered_template = std.ArrayList(u8).init(self.gpa);
6291 defer rendered_template.deinit();6291 defer rendered_template.deinit();
62926292
6293 const State = enum { start, percent, input };6293 const State = enum { start, percent, input, modifier };
62946294
6295 var state: State = .start;6295 var state: State = .start;
62966296
6297 var name_start: usize = undefined;6297 var name_start: usize = undefined;
6298 var modifier_start: usize = undefined;
6298 for (asm_source) |byte, i| {6299 for (asm_source) |byte, i| {
6299 switch (state) {6300 switch (state) {
6300 .start => switch (byte) {6301 .start => switch (byte) {
...@@ -6309,6 +6310,7 @@ pub const FuncGen = struct {...@@ -6309,6 +6310,7 @@ pub const FuncGen = struct {
6309 },6310 },
6310 '[' => {6311 '[' => {
6311 try rendered_template.append('$');6312 try rendered_template.append('$');
6313 try rendered_template.append('{');
6312 name_start = i + 1;6314 name_start = i + 1;
6313 state = .input;6315 state = .input;
6314 },6316 },
...@@ -6319,15 +6321,30 @@ pub const FuncGen = struct {...@@ -6319,15 +6321,30 @@ pub const FuncGen = struct {
6319 },6321 },
6320 },6322 },
6321 .input => switch (byte) {6323 .input => switch (byte) {
6322 ']' => {6324 ']', ':' => {
6323 const name = asm_source[name_start..i];6325 const name = asm_source[name_start..i];
6324 state = .start;
63256326
6326 const index = name_map.get(name) orelse {6327 const index = name_map.get(name) orelse {
6327 // we should validate the assembly in Sema; by now it is too late6328 // we should validate the assembly in Sema; by now it is too late
6328 return self.todo("unknown input or output name: '{s}'", .{name});6329 return self.todo("unknown input or output name: '{s}'", .{name});
6329 };6330 };
6330 try rendered_template.writer().print("{d}", .{index});6331 try rendered_template.writer().print("{d}", .{index});
6332 if (byte == ':') {
6333 try rendered_template.append(':');
6334 modifier_start = i + 1;
6335 state = .modifier;
6336 } else {
6337 try rendered_template.append('}');
6338 state = .start;
6339 }
6340 },
6341 else => {},
6342 },
6343 .modifier => switch (byte) {
6344 ']' => {
6345 try rendered_template.appendSlice(asm_source[modifier_start..i]);
6346 try rendered_template.append('}');
6347 state = .start;
6331 },6348 },
6332 else => {},6349 else => {},
6333 },6350 },
test/behavior/asm.zig+13
...@@ -136,3 +136,16 @@ extern fn this_is_my_alias() i32;...@@ -136,3 +136,16 @@ extern fn this_is_my_alias() i32;
136export fn derp() i32 {136export fn derp() i32 {
137 return 1234;137 return 1234;
138}138}
139
140test "asm modifiers (AArch64)" {
141 if (builtin.target.cpu.arch != .aarch64) return error.SkipZigTest;
142 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
143 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
144
145 var x: u32 = 15;
146 const double = asm ("add %[ret:w], %[in:w], %[in:w]"
147 : [ret] "=r" (-> u32),
148 : [in] "r" (x),
149 );
150 try expect(double == 2 * x);
151}