Commit 907dc1e13f

Daniele Cocca <daniele.cocca@gmail.com>
2022-03-20 22:04:28
CBE: improve support for asm inputs
This is not complete support for asm expressions, but allows a few more test cases from test/behavior/asm.zig to pass. Since the non-register inputs are named `input_${n}` they can cause name collisions: I'm wrapping the asm expressions in their own block to prevent that. Contextually, this change also makes test/behavior/asm.zig run for stage2, but skips individual tests for most backends (I only verified the C and LLVM backends successfully run one new test case) and the entire test file for aarch64, where it's running into preexisting shortcomings.
1 parent ebafdb9
Changed files (3)
src
codegen
test
src/codegen/c.zig
@@ -3014,9 +3014,10 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
     } else null;
 
     const writer = f.object.writer();
-    const inputs_extra_begin = extra_i;
+    try writer.writeAll("{\n");
 
-    for (inputs) |input| {
+    const inputs_extra_begin = extra_i;
+    for (inputs) |input, i| {
         const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(f.air.extra[extra_i..]), 0);
         // This equation accounts for the fact that even if we have exactly 4 bytes
         // for the string, we still use the next u32 for the null terminator.
@@ -3032,7 +3033,11 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
             try f.writeCValue(writer, arg_c_value);
             try writer.writeAll(";\n");
         } else {
-            return f.fail("TODO non-explicit inline asm regs", .{});
+            try writer.writeAll("register ");
+            try f.renderType(writer, f.air.typeOf(input));
+            try writer.print(" input_{d} = ", .{i});
+            try f.writeCValue(writer, try f.resolveInst(input));
+            try writer.writeAll(";\n");
         }
     }
 
@@ -3074,12 +3079,15 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
                 }
                 try writer.print("\"r\"({s}_constant)", .{reg});
             } else {
-                // This is blocked by the earlier test
-                unreachable;
+                if (index > 0) {
+                    try writer.writeAll(", ");
+                }
+                try writer.print("\"r\"(input_{d})", .{index});
             }
         }
     }
     try writer.writeAll(");\n");
+    try writer.writeAll("}\n");
 
     if (f.liveness.isUnused(inst))
         return CValue.none;
test/behavior/asm.zig
@@ -5,7 +5,10 @@ const expect = std.testing.expect;
 const is_x86_64_linux = builtin.cpu.arch == .x86_64 and builtin.os.tag == .linux;
 
 comptime {
-    if (is_x86_64_linux) {
+    if (builtin.zig_backend != .stage2_arm and
+        builtin.zig_backend != .stage2_aarch64 and
+        is_x86_64_linux)
+    {
         asm (
             \\.globl this_is_my_alias;
             \\.type this_is_my_alias, @function;
@@ -15,12 +18,26 @@ comptime {
 }
 
 test "module level assembly" {
+    if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // TODO
+
     if (is_x86_64_linux) {
         try expect(this_is_my_alias() == 1234);
     }
 }
 
 test "output constraint modifiers" {
+    if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // TODO
+
     // This is only testing compilation.
     var a: u32 = 3;
     asm volatile (""
@@ -36,6 +53,13 @@ test "output constraint modifiers" {
 }
 
 test "alternative constraints" {
+    if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // TODO
+
     // Make sure we allow commas as a separator for alternative constraints.
     var a: u32 = 3;
     asm volatile (""
@@ -46,6 +70,11 @@ test "alternative constraints" {
 }
 
 test "sized integer/float in asm input" {
+    if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+
     asm volatile (""
         :
         : [_] "m" (@as(usize, 3)),
@@ -89,6 +118,13 @@ test "sized integer/float in asm input" {
 }
 
 test "struct/array/union types as input values" {
+    if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // TODO
+
     asm volatile (""
         :
         : [_] "m" (@as([1]u32, undefined)),
test/behavior.zig
@@ -165,10 +165,7 @@ test {
     }
 
     if (builtin.os.tag != .wasi) {
-        if (builtin.zig_backend == .stage1) {
-            // TODO get these tests passing with stage2
-            _ = @import("behavior/asm.zig");
-        }
+        _ = @import("behavior/asm.zig");
     }
 
     if (builtin.zig_backend != .stage2_arm and