Commit 75c2cff40e

Veikka Tuominen <git@vexu.eu>
2022-03-30 23:38:19
stage2: handle assembly input names
1 parent 6655c60
Changed files (7)
src/arch/aarch64/CodeGen.zig
@@ -3200,10 +3200,12 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
         } else null;
 
         for (inputs) |input| {
-            const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0);
+            const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
+            const constraint = std.mem.sliceTo(input_bytes, 0);
+            const input_name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 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.
-            extra_i += constraint.len / 4 + 1;
+            extra_i += (constraint.len + input_name.len + 1) / 4 + 1;
 
             if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') {
                 return self.fail("unrecognized asm input constraint: '{s}'", .{constraint});
src/arch/arm/CodeGen.zig
@@ -3609,10 +3609,12 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
         } else null;
 
         for (inputs) |input| {
-            const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0);
+            const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
+            const constraint = std.mem.sliceTo(input_bytes, 0);
+            const input_name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 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.
-            extra_i += constraint.len / 4 + 1;
+            extra_i += (constraint.len + input_name.len + 1) / 4 + 1;
 
             if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') {
                 return self.fail("unrecognized asm input constraint: '{s}'", .{constraint});
src/arch/riscv64/CodeGen.zig
@@ -2113,10 +2113,12 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
         } else null;
 
         for (inputs) |input| {
-            const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0);
+            const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
+            const constraint = std.mem.sliceTo(input_bytes, 0);
+            const input_name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 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.
-            extra_i += constraint.len / 4 + 1;
+            extra_i += (constraint.len + input_name.len + 1) / 4 + 1;
 
             if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') {
                 return self.fail("unrecognized asm input constraint: '{s}'", .{constraint});
src/arch/x86_64/CodeGen.zig
@@ -4618,10 +4618,12 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
         } else null;
 
         for (inputs) |input| {
-            const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0);
+            const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
+            const constraint = std.mem.sliceTo(input_bytes, 0);
+            const input_name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 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.
-            extra_i += constraint.len / 4 + 1;
+            extra_i += (constraint.len + input_name.len + 1) / 4 + 1;
 
             if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') {
                 return self.fail("unrecognized asm input constraint: '{s}'", .{constraint});
src/codegen/llvm.zig
@@ -4545,11 +4545,14 @@ pub const FuncGen = struct {
             total_i += 1;
         }
 
+        const input_start_extra_i = extra_i;
         for (inputs) |input| {
-            const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0);
+            const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
+            const constraint = std.mem.sliceTo(input_bytes, 0);
+            const input_name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 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.
-            extra_i += constraint.len / 4 + 1;
+            extra_i += (constraint.len + input_name.len + 1) / 4 + 1;
 
             const arg_llvm_value = try self.resolveInst(input);
 
@@ -4591,11 +4594,12 @@ pub const FuncGen = struct {
         var rendered_template = std.ArrayList(u8).init(self.gpa);
         defer rendered_template.deinit();
 
-        const State = enum { start, percent };
+        const State = enum { start, percent, input };
 
         var state: State = .start;
 
-        for (asm_source) |byte| {
+        var name_start: usize = undefined;
+        for (asm_source) |byte, i| {
             switch (state) {
                 .start => switch (byte) {
                     '%' => state = .percent,
@@ -4606,12 +4610,39 @@ pub const FuncGen = struct {
                         try rendered_template.append('%');
                         state = .start;
                     },
+                    '[' => {
+                        try rendered_template.append('$');
+                        name_start = i + 1;
+                        state = .input;
+                    },
                     else => {
                         try rendered_template.append('%');
                         try rendered_template.append(byte);
                         state = .start;
                     },
                 },
+                .input => switch (byte) {
+                    ']' => {
+                        const name = asm_source[name_start..i];
+                        state = .start;
+
+                        extra_i = input_start_extra_i;
+                        for (inputs) |_, input_i| {
+                            const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
+                            const constraint = std.mem.sliceTo(input_bytes, 0);
+                            const input_name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0);
+                            extra_i += (constraint.len + input_name.len + 1) / 4 + 1;
+
+                            if (std.mem.eql(u8, name, input_name)) {
+                                try rendered_template.writer().print("{d}", .{input_i});
+                                break;
+                            }
+                        } else {
+                            return self.todo("TODO validate asm in Sema", .{});
+                        }
+                    },
+                    else => {},
+                },
             }
         }
 
src/Air.zig
@@ -815,6 +815,8 @@ pub const VectorCmp = struct {
 ///      terminated string. pad to the next u32 after the null byte.
 /// 3. for every inputs_len
 ///    - constraint: memory at this position is reinterpreted as a null
+///      terminated string.
+///    - name: memory at this position is reinterpreted as a null
 ///      terminated string. pad to the next u32 after the null byte.
 /// 4. for every clobbers_len
 ///    - clobber_name: memory at this position is reinterpreted as a null
src/Sema.zig
@@ -10295,15 +10295,12 @@ fn zirAsm(
     };
 
     const args = try sema.arena.alloc(Air.Inst.Ref, inputs_len);
-    const inputs = try sema.arena.alloc([]const u8, inputs_len);
+    const inputs = try sema.arena.alloc(struct { c: []const u8, n: []const u8 }, inputs_len);
 
     for (args) |*arg, arg_i| {
         const input = sema.code.extraData(Zir.Inst.Asm.Input, extra_i);
         extra_i = input.end;
 
-        const name = sema.code.nullTerminatedString(input.data.name);
-        _ = name; // TODO: use the name
-
         const uncasted_arg = sema.resolveInst(input.data.operand);
         const uncasted_arg_ty = sema.typeOf(uncasted_arg);
         switch (uncasted_arg_ty.zigTypeTag()) {
@@ -10313,8 +10310,9 @@ fn zirAsm(
         }
 
         const constraint = sema.code.nullTerminatedString(input.data.constraint);
-        needed_capacity += constraint.len / 4 + 1;
-        inputs[arg_i] = constraint;
+        const name = sema.code.nullTerminatedString(input.data.name);
+        needed_capacity += (constraint.len + name.len + 1) / 4 + 1;
+        inputs[arg_i] = .{ .c = constraint, .n = name };
     }
 
     const clobbers = try sema.arena.alloc([]const u8, clobbers_len);
@@ -10353,11 +10351,13 @@ fn zirAsm(
         buffer[o.constraint.len] = 0;
         sema.air_extra.items.len += o.constraint.len / 4 + 1;
     }
-    for (inputs) |constraint| {
+    for (inputs) |input| {
         const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());
-        mem.copy(u8, buffer, constraint);
-        buffer[constraint.len] = 0;
-        sema.air_extra.items.len += constraint.len / 4 + 1;
+        mem.copy(u8, buffer, input.c);
+        buffer[input.c.len] = 0;
+        mem.copy(u8, buffer[input.c.len + 1 ..], input.n);
+        buffer[input.c.len + 1 + input.n.len] = 0;
+        sema.air_extra.items.len += (input.c.len + input.n.len + 1) / 4 + 1;
     }
     for (clobbers) |clobber| {
         const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());