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 {
62906290 var rendered_template = std.ArrayList(u8).init(self.gpa);
62916291 defer rendered_template.deinit();
62926292
6293 const State = enum { start, percent, input };
6293 const State = enum { start, percent, input, modifier };
62946294
62956295 var state: State = .start;
62966296
62976297 var name_start: usize = undefined;
6298 var modifier_start: usize = undefined;
62986299 for (asm_source) |byte, i| {
62996300 switch (state) {
63006301 .start => switch (byte) {
......@@ -6309,6 +6310,7 @@ pub const FuncGen = struct {
63096310 },
63106311 '[' => {
63116312 try rendered_template.append('$');
6313 try rendered_template.append('{');
63126314 name_start = i + 1;
63136315 state = .input;
63146316 },
......@@ -6319,15 +6321,30 @@ pub const FuncGen = struct {
63196321 },
63206322 },
63216323 .input => switch (byte) {
6322 ']' => {
6324 ']', ':' => {
63236325 const name = asm_source[name_start..i];
6324 state = .start;
63256326
63266327 const index = name_map.get(name) orelse {
63276328 // we should validate the assembly in Sema; by now it is too late
63286329 return self.todo("unknown input or output name: '{s}'", .{name});
63296330 };
63306331 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;
63316348 },
63326349 else => {},
63336350 },
test/behavior/asm.zig+13
......@@ -136,3 +136,16 @@ extern fn this_is_my_alias() i32;
136136export fn derp() i32 {
137137 return 1234;
138138}
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}