authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-05-02 20:19:31-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-05-02 22:14:17-07:00
log65389dc280b97365605bc3f7f4038c1972534b9a
tree37ac5852f019fe10e68f4853a7db2d83a46eafc9
parentb95942744c7ded279f5695ed20fdbbc806323cba

stage2: improve inline asm stage1 compatibility

* outputs can have names and be referenced with template replacements the same as inputs. * fix print_air.zig not decoding correctly. * LLVM backend: use a table for template names for simplicity

10 files changed, 82 insertions(+), 53 deletions(-)

src/Air.zig+2
...@@ -815,6 +815,8 @@ pub const VectorCmp = struct {...@@ -815,6 +815,8 @@ pub const VectorCmp = struct {
815/// 1. `Inst.Ref` for every inputs_len815/// 1. `Inst.Ref` for every inputs_len
816/// 2. for every outputs_len816/// 2. for every outputs_len
817/// - constraint: memory at this position is reinterpreted as a null817/// - constraint: memory at this position is reinterpreted as a null
818/// terminated string.
819/// - name: memory at this position is reinterpreted as a null
818/// terminated string. pad to the next u32 after the null byte.820/// terminated string. pad to the next u32 after the null byte.
819/// 3. for every inputs_len821/// 3. for every inputs_len
820/// - constraint: memory at this position is reinterpreted as a null822/// - constraint: memory at this position is reinterpreted as a null
src/Sema.zig+13-5
...@@ -10535,7 +10535,11 @@ fn zirAsm(...@@ -10535,7 +10535,11 @@ fn zirAsm(
10535 var output_type_bits = extra.data.output_type_bits;10535 var output_type_bits = extra.data.output_type_bits;
10536 var needed_capacity: usize = @typeInfo(Air.Asm).Struct.fields.len + outputs_len + inputs_len;10536 var needed_capacity: usize = @typeInfo(Air.Asm).Struct.fields.len + outputs_len + inputs_len;
1053710537
10538 const Output = struct { constraint: []const u8, ty: Type };10538 const Output = struct {
10539 constraint: []const u8,
10540 name: []const u8,
10541 ty: Type,
10542 };
10539 const output: ?Output = if (outputs_len == 0) null else blk: {10543 const output: ?Output = if (outputs_len == 0) null else blk: {
10540 const output = sema.code.extraData(Zir.Inst.Asm.Output, extra_i);10544 const output = sema.code.extraData(Zir.Inst.Asm.Output, extra_i);
10541 extra_i = output.end;10545 extra_i = output.end;
...@@ -10548,10 +10552,12 @@ fn zirAsm(...@@ -10548,10 +10552,12 @@ fn zirAsm(
10548 }10552 }
1054910553
10550 const constraint = sema.code.nullTerminatedString(output.data.constraint);10554 const constraint = sema.code.nullTerminatedString(output.data.constraint);
10551 needed_capacity += constraint.len / 4 + 1;10555 const name = sema.code.nullTerminatedString(output.data.name);
10556 needed_capacity += (constraint.len + name.len + (2 + 3)) / 4;
1055210557
10553 break :blk Output{10558 break :blk Output{
10554 .constraint = constraint,10559 .constraint = constraint,
10560 .name = name,
10555 .ty = try sema.resolveType(block, ret_ty_src, output.data.operand),10561 .ty = try sema.resolveType(block, ret_ty_src, output.data.operand),
10556 };10562 };
10557 };10563 };
...@@ -10573,7 +10579,7 @@ fn zirAsm(...@@ -10573,7 +10579,7 @@ fn zirAsm(
1057310579
10574 const constraint = sema.code.nullTerminatedString(input.data.constraint);10580 const constraint = sema.code.nullTerminatedString(input.data.constraint);
10575 const name = sema.code.nullTerminatedString(input.data.name);10581 const name = sema.code.nullTerminatedString(input.data.name);
10576 needed_capacity += (constraint.len + name.len + 1) / 4 + 1;10582 needed_capacity += (constraint.len + name.len + (2 + 3)) / 4;
10577 inputs[arg_i] = .{ .c = constraint, .n = name };10583 inputs[arg_i] = .{ .c = constraint, .n = name };
10578 }10584 }
1057910585
...@@ -10611,7 +10617,9 @@ fn zirAsm(...@@ -10611,7 +10617,9 @@ fn zirAsm(
10611 const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());10617 const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());
10612 mem.copy(u8, buffer, o.constraint);10618 mem.copy(u8, buffer, o.constraint);
10613 buffer[o.constraint.len] = 0;10619 buffer[o.constraint.len] = 0;
10614 sema.air_extra.items.len += o.constraint.len / 4 + 1;10620 mem.copy(u8, buffer[o.constraint.len + 1 ..], o.name);
10621 buffer[o.constraint.len + 1 + o.name.len] = 0;
10622 sema.air_extra.items.len += (o.constraint.len + o.name.len + (2 + 3)) / 4;
10615 }10623 }
10616 for (inputs) |input| {10624 for (inputs) |input| {
10617 const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());10625 const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());
...@@ -10619,7 +10627,7 @@ fn zirAsm(...@@ -10619,7 +10627,7 @@ fn zirAsm(
10619 buffer[input.c.len] = 0;10627 buffer[input.c.len] = 0;
10620 mem.copy(u8, buffer[input.c.len + 1 ..], input.n);10628 mem.copy(u8, buffer[input.c.len + 1 ..], input.n);
10621 buffer[input.c.len + 1 + input.n.len] = 0;10629 buffer[input.c.len + 1 + input.n.len] = 0;
10622 sema.air_extra.items.len += (input.c.len + input.n.len + 1) / 4 + 1;10630 sema.air_extra.items.len += (input.c.len + input.n.len + (2 + 3)) / 4;
10623 }10631 }
10624 for (clobbers) |clobber| {10632 for (clobbers) |clobber| {
10625 const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());10633 const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());
src/arch/aarch64/CodeGen.zig+5-3
...@@ -3272,10 +3272,12 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -3272,10 +3272,12 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
3272 if (output != .none) {3272 if (output != .none) {
3273 return self.fail("TODO implement codegen for non-expr asm", .{});3273 return self.fail("TODO implement codegen for non-expr asm", .{});
3274 }3274 }
3275 const extra_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
3275 const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0);3276 const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0);
3277 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
3276 // This equation accounts for the fact that even if we have exactly 4 bytes3278 // This equation accounts for the fact that even if we have exactly 4 bytes
3277 // for the string, we still use the next u32 for the null terminator.3279 // for the string, we still use the next u32 for the null terminator.
3278 extra_i += constraint.len / 4 + 1;3280 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
32793281
3280 break constraint;3282 break constraint;
3281 } else null;3283 } else null;
...@@ -3283,10 +3285,10 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -3283,10 +3285,10 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
3283 for (inputs) |input| {3285 for (inputs) |input| {
3284 const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);3286 const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
3285 const constraint = std.mem.sliceTo(input_bytes, 0);3287 const constraint = std.mem.sliceTo(input_bytes, 0);
3286 const input_name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0);3288 const name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0);
3287 // This equation accounts for the fact that even if we have exactly 4 bytes3289 // This equation accounts for the fact that even if we have exactly 4 bytes
3288 // for the string, we still use the next u32 for the null terminator.3290 // for the string, we still use the next u32 for the null terminator.
3289 extra_i += (constraint.len + input_name.len + 1) / 4 + 1;3291 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
32903292
3291 if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') {3293 if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') {
3292 return self.fail("unrecognized asm input constraint: '{s}'", .{constraint});3294 return self.fail("unrecognized asm input constraint: '{s}'", .{constraint});
src/arch/arm/CodeGen.zig+5-3
...@@ -4078,10 +4078,12 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -4078,10 +4078,12 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
4078 if (output != .none) {4078 if (output != .none) {
4079 return self.fail("TODO implement codegen for non-expr asm", .{});4079 return self.fail("TODO implement codegen for non-expr asm", .{});
4080 }4080 }
4081 const extra_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
4081 const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0);4082 const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0);
4083 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
4082 // This equation accounts for the fact that even if we have exactly 4 bytes4084 // This equation accounts for the fact that even if we have exactly 4 bytes
4083 // for the string, we still use the next u32 for the null terminator.4085 // for the string, we still use the next u32 for the null terminator.
4084 extra_i += constraint.len / 4 + 1;4086 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
40854087
4086 break constraint;4088 break constraint;
4087 } else null;4089 } else null;
...@@ -4089,10 +4091,10 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -4089,10 +4091,10 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
4089 for (inputs) |input| {4091 for (inputs) |input| {
4090 const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);4092 const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
4091 const constraint = std.mem.sliceTo(input_bytes, 0);4093 const constraint = std.mem.sliceTo(input_bytes, 0);
4092 const input_name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0);4094 const name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0);
4093 // This equation accounts for the fact that even if we have exactly 4 bytes4095 // This equation accounts for the fact that even if we have exactly 4 bytes
4094 // for the string, we still use the next u32 for the null terminator.4096 // for the string, we still use the next u32 for the null terminator.
4095 extra_i += (constraint.len + input_name.len + 1) / 4 + 1;4097 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
40964098
4097 if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') {4099 if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') {
4098 return self.fail("unrecognized asm input constraint: '{s}'", .{constraint});4100 return self.fail("unrecognized asm input constraint: '{s}'", .{constraint});
src/arch/riscv64/CodeGen.zig+5-3
...@@ -2098,10 +2098,12 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -2098,10 +2098,12 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
2098 if (output != .none) {2098 if (output != .none) {
2099 return self.fail("TODO implement codegen for non-expr asm", .{});2099 return self.fail("TODO implement codegen for non-expr asm", .{});
2100 }2100 }
2101 const extra_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
2101 const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0);2102 const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0);
2103 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
2102 // This equation accounts for the fact that even if we have exactly 4 bytes2104 // This equation accounts for the fact that even if we have exactly 4 bytes
2103 // for the string, we still use the next u32 for the null terminator.2105 // for the string, we still use the next u32 for the null terminator.
2104 extra_i += constraint.len / 4 + 1;2106 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
21052107
2106 break constraint;2108 break constraint;
2107 } else null;2109 } else null;
...@@ -2109,10 +2111,10 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -2109,10 +2111,10 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
2109 for (inputs) |input| {2111 for (inputs) |input| {
2110 const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);2112 const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
2111 const constraint = std.mem.sliceTo(input_bytes, 0);2113 const constraint = std.mem.sliceTo(input_bytes, 0);
2112 const input_name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0);2114 const name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0);
2113 // This equation accounts for the fact that even if we have exactly 4 bytes2115 // This equation accounts for the fact that even if we have exactly 4 bytes
2114 // for the string, we still use the next u32 for the null terminator.2116 // for the string, we still use the next u32 for the null terminator.
2115 extra_i += (constraint.len + input_name.len + 1) / 4 + 1;2117 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
21162118
2117 if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') {2119 if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') {
2118 return self.fail("unrecognized asm input constraint: '{s}'", .{constraint});2120 return self.fail("unrecognized asm input constraint: '{s}'", .{constraint});
src/arch/sparcv9/CodeGen.zig+5-3
...@@ -642,10 +642,12 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -642,10 +642,12 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
642 if (output != .none) {642 if (output != .none) {
643 return self.fail("TODO implement codegen for non-expr asm", .{});643 return self.fail("TODO implement codegen for non-expr asm", .{});
644 }644 }
645 const extra_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
645 const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0);646 const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0);
647 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
646 // This equation accounts for the fact that even if we have exactly 4 bytes648 // This equation accounts for the fact that even if we have exactly 4 bytes
647 // for the string, we still use the next u32 for the null terminator.649 // for the string, we still use the next u32 for the null terminator.
648 extra_i += constraint.len / 4 + 1;650 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
649651
650 break constraint;652 break constraint;
651 } else null;653 } else null;
...@@ -653,10 +655,10 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -653,10 +655,10 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
653 for (inputs) |input| {655 for (inputs) |input| {
654 const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);656 const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
655 const constraint = std.mem.sliceTo(input_bytes, 0);657 const constraint = std.mem.sliceTo(input_bytes, 0);
656 const input_name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0);658 const name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0);
657 // This equation accounts for the fact that even if we have exactly 4 bytes659 // This equation accounts for the fact that even if we have exactly 4 bytes
658 // for the string, we still use the next u32 for the null terminator.660 // for the string, we still use the next u32 for the null terminator.
659 extra_i += (constraint.len + input_name.len + 1) / 4 + 1;661 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
660662
661 if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') {663 if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') {
662 return self.fail("unrecognized asm input constraint: '{s}'", .{constraint});664 return self.fail("unrecognized asm input constraint: '{s}'", .{constraint});
src/arch/x86_64/CodeGen.zig+5-3
...@@ -4739,10 +4739,12 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -4739,10 +4739,12 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
4739 if (output != .none) {4739 if (output != .none) {
4740 return self.fail("TODO implement codegen for non-expr asm", .{});4740 return self.fail("TODO implement codegen for non-expr asm", .{});
4741 }4741 }
4742 const extra_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
4742 const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0);4743 const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0);
4744 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
4743 // This equation accounts for the fact that even if we have exactly 4 bytes4745 // This equation accounts for the fact that even if we have exactly 4 bytes
4744 // for the string, we still use the next u32 for the null terminator.4746 // for the string, we still use the next u32 for the null terminator.
4745 extra_i += constraint.len / 4 + 1;4747 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
47464748
4747 break constraint;4749 break constraint;
4748 } else null;4750 } else null;
...@@ -4750,10 +4752,10 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -4750,10 +4752,10 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
4750 for (inputs) |input| {4752 for (inputs) |input| {
4751 const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);4753 const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
4752 const constraint = std.mem.sliceTo(input_bytes, 0);4754 const constraint = std.mem.sliceTo(input_bytes, 0);
4753 const input_name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0);4755 const name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0);
4754 // This equation accounts for the fact that even if we have exactly 4 bytes4756 // This equation accounts for the fact that even if we have exactly 4 bytes
4755 // for the string, we still use the next u32 for the null terminator.4757 // for the string, we still use the next u32 for the null terminator.
4756 extra_i += (constraint.len + input_name.len + 1) / 4 + 1;4758 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
47574759
4758 if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') {4760 if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') {
4759 return self.fail("unrecognized asm input constraint: '{s}'", .{constraint});4761 return self.fail("unrecognized asm input constraint: '{s}'", .{constraint});
src/codegen/c.zig+7-3
...@@ -3018,10 +3018,12 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3018,10 +3018,12 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
3018 if (output != .none) {3018 if (output != .none) {
3019 return f.fail("TODO implement codegen for non-expr asm", .{});3019 return f.fail("TODO implement codegen for non-expr asm", .{});
3020 }3020 }
3021 const extra_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]);
3021 const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(f.air.extra[extra_i..]), 0);3022 const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(f.air.extra[extra_i..]), 0);
3023 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
3022 // This equation accounts for the fact that even if we have exactly 4 bytes3024 // This equation accounts for the fact that even if we have exactly 4 bytes
3023 // for the string, we still use the next u32 for the null terminator.3025 // for the string, we still use the next u32 for the null terminator.
3024 extra_i += constraint.len / 4 + 1;3026 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
30253027
3026 break constraint;3028 break constraint;
3027 } else null;3029 } else null;
...@@ -3031,10 +3033,12 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3031,10 +3033,12 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
30313033
3032 const inputs_extra_begin = extra_i;3034 const inputs_extra_begin = extra_i;
3033 for (inputs) |input, i| {3035 for (inputs) |input, i| {
3034 const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(f.air.extra[extra_i..]), 0);3036 const input_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]);
3037 const constraint = std.mem.sliceTo(input_bytes, 0);
3038 const name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0);
3035 // This equation accounts for the fact that even if we have exactly 4 bytes3039 // This equation accounts for the fact that even if we have exactly 4 bytes
3036 // for the string, we still use the next u32 for the null terminator.3040 // for the string, we still use the next u32 for the null terminator.
3037 extra_i += constraint.len / 4 + 1;3041 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
30383042
3039 if (constraint[0] == '{' and constraint[constraint.len - 1] == '}') {3043 if (constraint[0] == '{' and constraint[constraint.len - 1] == '}') {
3040 const reg = constraint[1 .. constraint.len - 1];3044 const reg = constraint[1 .. constraint.len - 1];
src/codegen/llvm.zig+17-20
...@@ -4638,14 +4638,19 @@ pub const FuncGen = struct {...@@ -4638,14 +4638,19 @@ pub const FuncGen = struct {
4638 var llvm_param_i: usize = 0;4638 var llvm_param_i: usize = 0;
4639 var total_i: usize = 0;4639 var total_i: usize = 0;
46404640
4641 var name_map: std.StringArrayHashMapUnmanaged(void) = .{};
4642 try name_map.ensureUnusedCapacity(arena, outputs.len + inputs.len);
4643
4641 for (outputs) |output| {4644 for (outputs) |output| {
4642 if (output != .none) {4645 if (output != .none) {
4643 return self.todo("implement inline asm with non-returned output", .{});4646 return self.todo("implement inline asm with non-returned output", .{});
4644 }4647 }
4648 const extra_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
4645 const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0);4649 const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0);
4650 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
4646 // This equation accounts for the fact that even if we have exactly 4 bytes4651 // This equation accounts for the fact that even if we have exactly 4 bytes
4647 // for the string, we still use the next u32 for the null terminator.4652 // for the string, we still use the next u32 for the null terminator.
4648 extra_i += constraint.len / 4 + 1;4653 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
46494654
4650 try llvm_constraints.ensureUnusedCapacity(self.gpa, constraint.len + 1);4655 try llvm_constraints.ensureUnusedCapacity(self.gpa, constraint.len + 1);
4651 if (total_i != 0) {4656 if (total_i != 0) {
...@@ -4654,17 +4659,17 @@ pub const FuncGen = struct {...@@ -4654,17 +4659,17 @@ pub const FuncGen = struct {
4654 llvm_constraints.appendAssumeCapacity('=');4659 llvm_constraints.appendAssumeCapacity('=');
4655 llvm_constraints.appendSliceAssumeCapacity(constraint[1..]);4660 llvm_constraints.appendSliceAssumeCapacity(constraint[1..]);
46564661
4662 name_map.putAssumeCapacityNoClobber(name, {});
4657 total_i += 1;4663 total_i += 1;
4658 }4664 }
46594665
4660 const input_start_extra_i = extra_i;
4661 for (inputs) |input| {4666 for (inputs) |input| {
4662 const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);4667 const extra_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
4663 const constraint = std.mem.sliceTo(input_bytes, 0);4668 const constraint = std.mem.sliceTo(extra_bytes, 0);
4664 const input_name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0);4669 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
4665 // This equation accounts for the fact that even if we have exactly 4 bytes4670 // This equation accounts for the fact that even if we have exactly 4 bytes
4666 // for the string, we still use the next u32 for the null terminator.4671 // for the string, we still use the next u32 for the null terminator.
4667 extra_i += (constraint.len + input_name.len + 1) / 4 + 1;4672 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
46684673
4669 const arg_llvm_value = try self.resolveInst(input);4674 const arg_llvm_value = try self.resolveInst(input);
46704675
...@@ -4677,6 +4682,7 @@ pub const FuncGen = struct {...@@ -4677,6 +4682,7 @@ pub const FuncGen = struct {
4677 }4682 }
4678 llvm_constraints.appendSliceAssumeCapacity(constraint);4683 llvm_constraints.appendSliceAssumeCapacity(constraint);
46794684
4685 name_map.putAssumeCapacityNoClobber(name, {});
4680 llvm_param_i += 1;4686 llvm_param_i += 1;
4681 total_i += 1;4687 total_i += 1;
4682 }4688 }
...@@ -4739,20 +4745,11 @@ pub const FuncGen = struct {...@@ -4739,20 +4745,11 @@ pub const FuncGen = struct {
4739 const name = asm_source[name_start..i];4745 const name = asm_source[name_start..i];
4740 state = .start;4746 state = .start;
47414747
4742 extra_i = input_start_extra_i;4748 const index = name_map.getIndex(name) orelse {
4743 for (inputs) |_, input_i| {4749 // we should validate the assembly in Sema; by now it is too late
4744 const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);4750 return self.todo("unknown input or output name: '{s}'", .{name});
4745 const constraint = std.mem.sliceTo(input_bytes, 0);4751 };
4746 const input_name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0);4752 try rendered_template.writer().print("{d}", .{index});
4747 extra_i += (constraint.len + input_name.len + 1) / 4 + 1;
4748
4749 if (std.mem.eql(u8, name, input_name)) {
4750 try rendered_template.writer().print("{d}", .{input_i});
4751 break;
4752 }
4753 } else {
4754 return self.todo("TODO validate asm in Sema", .{});
4755 }
4756 },4753 },
4757 else => {},4754 else => {},
4758 },4755 },
src/print_air.zig+18-10
...@@ -542,15 +542,19 @@ const Writer = struct {...@@ -542,15 +542,19 @@ const Writer = struct {
542 extra_i += inputs.len;542 extra_i += inputs.len;
543543
544 for (outputs) |output| {544 for (outputs) |output| {
545 const constraint = w.air.nullTerminatedString(extra_i);545 const extra_bytes = std.mem.sliceAsBytes(w.air.extra[extra_i..]);
546 const constraint = std.mem.sliceTo(extra_bytes, 0);
547 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
548
546 // This equation accounts for the fact that even if we have exactly 4 bytes549 // This equation accounts for the fact that even if we have exactly 4 bytes
547 // for the string, we still use the next u32 for the null terminator.550 // for the strings and their null terminators, we still use the next u32
548 extra_i += constraint.len / 4 + 1;551 // for the null terminator.
552 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
549553
550 if (output == .none) {554 if (output == .none) {
551 try s.print(", -> {s}", .{constraint});555 try s.print(", [{s}] -> {s}", .{ name, constraint });
552 } else {556 } else {
553 try s.print(", out {s} = (", .{constraint});557 try s.print(", [{s}] out {s} = (", .{ name, constraint });
554 try w.writeOperand(s, inst, op_index, output);558 try w.writeOperand(s, inst, op_index, output);
555 op_index += 1;559 op_index += 1;
556 try s.writeByte(')');560 try s.writeByte(')');
...@@ -558,12 +562,15 @@ const Writer = struct {...@@ -558,12 +562,15 @@ const Writer = struct {
558 }562 }
559563
560 for (inputs) |input| {564 for (inputs) |input| {
561 const constraint = w.air.nullTerminatedString(extra_i);565 const extra_bytes = std.mem.sliceAsBytes(w.air.extra[extra_i..]);
566 const constraint = std.mem.sliceTo(extra_bytes, 0);
567 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
562 // This equation accounts for the fact that even if we have exactly 4 bytes568 // This equation accounts for the fact that even if we have exactly 4 bytes
563 // for the string, we still use the next u32 for the null terminator.569 // for the strings and their null terminators, we still use the next u32
564 extra_i += constraint.len / 4 + 1;570 // for the null terminator.
571 extra_i += (constraint.len + name.len + 1) / 4 + 1;
565572
566 try s.print(", in {s} = (", .{constraint});573 try s.print(", [{s}] in {s} = (", .{ name, constraint });
567 try w.writeOperand(s, inst, op_index, input);574 try w.writeOperand(s, inst, op_index, input);
568 op_index += 1;575 op_index += 1;
569 try s.writeByte(')');576 try s.writeByte(')');
...@@ -572,7 +579,8 @@ const Writer = struct {...@@ -572,7 +579,8 @@ const Writer = struct {
572 {579 {
573 var clobber_i: u32 = 0;580 var clobber_i: u32 = 0;
574 while (clobber_i < clobbers_len) : (clobber_i += 1) {581 while (clobber_i < clobbers_len) : (clobber_i += 1) {
575 const clobber = w.air.nullTerminatedString(extra_i);582 const extra_bytes = std.mem.sliceAsBytes(w.air.extra[extra_i..]);
583 const clobber = std.mem.sliceTo(extra_bytes, 0);
576 // This equation accounts for the fact that even if we have exactly 4 bytes584 // This equation accounts for the fact that even if we have exactly 4 bytes
577 // for the string, we still use the next u32 for the null terminator.585 // for the string, we still use the next u32 for the null terminator.
578 extra_i += clobber.len / 4 + 1;586 extra_i += clobber.len / 4 + 1;