Commit 361217bda2

Andrew Kelley <andrew@ziglang.org>
2021-10-20 23:50:07
stage2: fix inline assembly with expression output
Thanks @g-w1 for the print_air.zig implementation for inline assembly. I copied it and slightly modified it from your open pull request.
1 parent d949180
Changed files (3)
lib
src
lib/std/heap.zig
@@ -295,7 +295,7 @@ const PageAllocator = struct {
             }
         }
 
-        const max_drop_len = alignment - std.math.min(alignment, mem.page_size);
+        const max_drop_len = alignment - @minimum(alignment, mem.page_size);
         const alloc_len = if (max_drop_len <= aligned_len - n)
             aligned_len
         else
@@ -529,7 +529,7 @@ const WasmPageAllocator = struct {
 
     fn freePages(start: usize, end: usize) void {
         if (start < extendedOffset()) {
-            conventional.recycle(start, std.math.min(extendedOffset(), end) - start);
+            conventional.recycle(start, @minimum(extendedOffset(), end) - start);
         }
         if (end > extendedOffset()) {
             var new_end = end;
src/codegen/llvm.zig
@@ -2331,17 +2331,19 @@ pub const FuncGen = struct {
         const air_asm = self.air.extraData(Air.Asm, ty_pl.payload);
         const zir = self.dg.decl.getFileScope().zir;
         const extended = zir.instructions.items(.data)[air_asm.data.zir_index].extended;
-        const zir_extra = zir.extraData(Zir.Inst.Asm, extended.operand);
-        const asm_source = zir.nullTerminatedString(zir_extra.data.asm_source);
-        const outputs_len = @truncate(u5, extended.small);
-        const args_len = @truncate(u5, extended.small >> 5);
-        const clobbers_len = @truncate(u5, extended.small >> 10);
         const is_volatile = @truncate(u1, extended.small >> 15) != 0;
-        const outputs = @bitCast([]const Air.Inst.Ref, self.air.extra[air_asm.end..][0..outputs_len]);
-        const args = @bitCast([]const Air.Inst.Ref, self.air.extra[air_asm.end + outputs.len ..][0..args_len]);
+        if (!is_volatile and self.liveness.isUnused(inst)) {
+            return null;
+        }
+        const outputs_len = @truncate(u5, extended.small);
         if (outputs_len > 1) {
             return self.todo("implement llvm codegen for asm with more than 1 output", .{});
         }
+        const args_len = @truncate(u5, extended.small >> 5);
+        const clobbers_len = @truncate(u5, extended.small >> 10);
+        const zir_extra = zir.extraData(Zir.Inst.Asm, extended.operand);
+        const asm_source = zir.nullTerminatedString(zir_extra.data.asm_source);
+        const args = @bitCast([]const Air.Inst.Ref, self.air.extra[air_asm.end..][0..args_len]);
 
         var extra_i: usize = zir_extra.end;
         const output_constraint: ?[]const u8 = out: {
@@ -2354,10 +2356,6 @@ pub const FuncGen = struct {
             break :out null;
         };
 
-        if (!is_volatile and self.liveness.isUnused(inst)) {
-            return null;
-        }
-
         var llvm_constraints: std.ArrayListUnmanaged(u8) = .{};
         defer llvm_constraints.deinit(self.gpa);
 
@@ -2365,7 +2363,7 @@ pub const FuncGen = struct {
         defer arena_allocator.deinit();
         const arena = &arena_allocator.allocator;
 
-        const llvm_params_len = args.len + @boolToInt(output_constraint != null);
+        const llvm_params_len = args.len;
         const llvm_param_types = try arena.alloc(*const llvm.Type, llvm_params_len);
         const llvm_param_values = try arena.alloc(*const llvm.Value, llvm_params_len);
 
@@ -2377,7 +2375,8 @@ pub const FuncGen = struct {
             if (total_i != 0) {
                 llvm_constraints.appendAssumeCapacity(',');
             }
-            llvm_constraints.appendSliceAssumeCapacity(constraint);
+            llvm_constraints.appendAssumeCapacity('=');
+            llvm_constraints.appendSliceAssumeCapacity(constraint[1..]);
 
             total_i += 1;
         }
src/print_air.zig
@@ -370,9 +370,52 @@ const Writer = struct {
     }
 
     fn writeAssembly(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
-        _ = w;
-        _ = inst;
-        try s.writeAll("TODO");
+        const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;
+        const air_asm = w.air.extraData(Air.Asm, ty_pl.payload);
+        const zir = w.zir;
+        const extended = zir.instructions.items(.data)[air_asm.data.zir_index].extended;
+        const zir_extra = zir.extraData(Zir.Inst.Asm, extended.operand);
+        const asm_source = zir.nullTerminatedString(zir_extra.data.asm_source);
+        const outputs_len = @truncate(u5, extended.small);
+        const args_len = @truncate(u5, extended.small >> 5);
+        const clobbers_len = @truncate(u5, extended.small >> 10);
+        const args = @bitCast([]const Air.Inst.Ref, w.air.extra[air_asm.end..][0..args_len]);
+
+        var extra_i: usize = zir_extra.end;
+        const output_constraint: ?[]const u8 = out: {
+            var i: usize = 0;
+            while (i < outputs_len) : (i += 1) {
+                const output = zir.extraData(Zir.Inst.Asm.Output, extra_i);
+                extra_i = output.end;
+                break :out zir.nullTerminatedString(output.data.constraint);
+            }
+            break :out null;
+        };
+
+        try s.print("\"{s}\"", .{asm_source});
+
+        if (output_constraint) |constraint| {
+            const ret_ty = w.air.typeOfIndex(inst);
+            try s.print(", {s} -> {}", .{ constraint, ret_ty });
+        }
+
+        for (args) |arg| {
+            const input = zir.extraData(Zir.Inst.Asm.Input, extra_i);
+            extra_i = input.end;
+            const constraint = zir.nullTerminatedString(input.data.constraint);
+
+            try s.print(", {s} = (", .{constraint});
+            try w.writeOperand(s, inst, 0, arg);
+            try s.writeByte(')');
+        }
+
+        const clobbers = zir.extra[extra_i..][0..clobbers_len];
+        for (clobbers) |clobber_index| {
+            const clobber = zir.nullTerminatedString(clobber_index);
+            try s.writeAll(", ~{");
+            try s.writeAll(clobber);
+            try s.writeAll("}");
+        }
     }
 
     fn writeDbgStmt(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {