| author | |
| committer | |
| log | 65389dc280b97365605bc3f7f4038c1972534b9a |
| tree | 37ac5852f019fe10e68f4853a7db2d83a46eafc9 |
| parent | b95942744c7ded279f5695ed20fdbbc806323cba |
* 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 simplicity10 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_len | 815 | /// 1. `Inst.Ref` for every inputs_len |
| 816 | /// 2. for every outputs_len | 816 | /// 2. for every outputs_len |
| 817 | /// - constraint: memory at this position is reinterpreted as a null | 817 | /// - 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_len | 821 | /// 3. for every inputs_len |
| 820 | /// - constraint: memory at this position is reinterpreted as a null | 822 | /// - 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; |
| 10537 | 10537 | ||
| 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 | } |
| 10549 | 10553 | ||
| 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; | ||
| 10552 | 10557 | ||
| 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( |
| 10573 | 10579 | ||
| 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 | } |
| 10579 | 10585 | ||
| ... | @@ -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 bytes | 3278 | // 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; |
| 3279 | 3281 | ||
| 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 bytes | 3289 | // 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; |
| 3290 | 3292 | ||
| 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 bytes | 4084 | // 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; |
| 4085 | 4087 | ||
| 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 bytes | 4095 | // 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; |
| 4096 | 4098 | ||
| 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 bytes | 2104 | // 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; |
| 2105 | 2107 | ||
| 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 bytes | 2115 | // 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; |
| 2116 | 2118 | ||
| 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 bytes | 648 | // 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; |
| 649 | 651 | ||
| 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 bytes | 659 | // 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; |
| 660 | 662 | ||
| 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 bytes | 4745 | // 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; |
| 4746 | 4748 | ||
| 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 bytes | 4756 | // 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; |
| 4757 | 4759 | ||
| 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 bytes | 3024 | // 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; |
| 3025 | 3027 | ||
| 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 { |
| 3031 | 3033 | ||
| 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 bytes | 3039 | // 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; |
| 3038 | 3042 | ||
| 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; |
| 4640 | 4640 | ||
| 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 bytes | 4651 | // 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; |
| 4649 | 4654 | ||
| 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..]); |
| 4656 | 4661 | ||
| 4662 | name_map.putAssumeCapacityNoClobber(name, {}); | ||
| 4657 | total_i += 1; | 4663 | total_i += 1; |
| 4658 | } | 4664 | } |
| 4659 | 4665 | ||
| 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 bytes | 4670 | // 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; |
| 4668 | 4673 | ||
| 4669 | const arg_llvm_value = try self.resolveInst(input); | 4674 | const arg_llvm_value = try self.resolveInst(input); |
| 4670 | 4675 | ||
| ... | @@ -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); |
| 4679 | 4684 | ||
| 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; |
| 4741 | 4747 | ||
| 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; |
| 543 | 543 | ||
| 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 bytes | 549 | // 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; | ||
| 549 | 553 | ||
| 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 | } |
| 559 | 563 | ||
| 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 bytes | 568 | // 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; | ||
| 565 | 572 | ||
| 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 bytes | 584 | // 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; |