Commit 2897641fb9

Cody Tapscott <topolarity@tapscott.me>
2022-11-10 22:02:05
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
1 parent b605cb2
Changed files (2)
src
codegen
test
behavior
src/codegen/llvm.zig
@@ -6290,11 +6290,12 @@ pub const FuncGen = struct {
         var rendered_template = std.ArrayList(u8).init(self.gpa);
         defer rendered_template.deinit();
 
-        const State = enum { start, percent, input };
+        const State = enum { start, percent, input, modifier };
 
         var state: State = .start;
 
         var name_start: usize = undefined;
+        var modifier_start: usize = undefined;
         for (asm_source) |byte, i| {
             switch (state) {
                 .start => switch (byte) {
@@ -6309,6 +6310,7 @@ pub const FuncGen = struct {
                     },
                     '[' => {
                         try rendered_template.append('$');
+                        try rendered_template.append('{');
                         name_start = i + 1;
                         state = .input;
                     },
@@ -6319,15 +6321,30 @@ pub const FuncGen = struct {
                     },
                 },
                 .input => switch (byte) {
-                    ']' => {
+                    ']', ':' => {
                         const name = asm_source[name_start..i];
-                        state = .start;
 
                         const index = name_map.get(name) orelse {
                             // we should validate the assembly in Sema; by now it is too late
                             return self.todo("unknown input or output name: '{s}'", .{name});
                         };
                         try rendered_template.writer().print("{d}", .{index});
+                        if (byte == ':') {
+                            try rendered_template.append(':');
+                            modifier_start = i + 1;
+                            state = .modifier;
+                        } else {
+                            try rendered_template.append('}');
+                            state = .start;
+                        }
+                    },
+                    else => {},
+                },
+                .modifier => switch (byte) {
+                    ']' => {
+                        try rendered_template.appendSlice(asm_source[modifier_start..i]);
+                        try rendered_template.append('}');
+                        state = .start;
                     },
                     else => {},
                 },
test/behavior/asm.zig
@@ -136,3 +136,16 @@ extern fn this_is_my_alias() i32;
 export fn derp() i32 {
     return 1234;
 }
+
+test "asm modifiers (AArch64)" {
+    if (builtin.target.cpu.arch != .aarch64) return error.SkipZigTest;
+    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
+
+    var x: u32 = 15;
+    const double = asm ("add %[ret:w], %[in:w], %[in:w]"
+        : [ret] "=r" (-> u32),
+        : [in] "r" (x),
+    );
+    try expect(double == 2 * x);
+}