| 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 | 815 | /// 1. `Inst.Ref` for every inputs_len |
| 816 | 816 | /// 2. for every outputs_len |
| 817 | 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 | 820 | /// terminated string. pad to the next u32 after the null byte. |
| 819 | 821 | /// 3. for every inputs_len |
| 820 | 822 | /// - constraint: memory at this position is reinterpreted as a null |
src/Sema.zig+13-5| ... | ... | @@ -10535,7 +10535,11 @@ fn zirAsm( |
| 10535 | 10535 | var output_type_bits = extra.data.output_type_bits; |
| 10536 | 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 | 10543 | const output: ?Output = if (outputs_len == 0) null else blk: { |
| 10540 | 10544 | const output = sema.code.extraData(Zir.Inst.Asm.Output, extra_i); |
| 10541 | 10545 | extra_i = output.end; |
| ... | ... | @@ -10548,10 +10552,12 @@ fn zirAsm( |
| 10548 | 10552 | } |
| 10549 | 10553 | |
| 10550 | 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 | 10558 | break :blk Output{ |
| 10554 | 10559 | .constraint = constraint, |
| 10560 | .name = name, | |
| 10555 | 10561 | .ty = try sema.resolveType(block, ret_ty_src, output.data.operand), |
| 10556 | 10562 | }; |
| 10557 | 10563 | }; |
| ... | ... | @@ -10573,7 +10579,7 @@ fn zirAsm( |
| 10573 | 10579 | |
| 10574 | 10580 | const constraint = sema.code.nullTerminatedString(input.data.constraint); |
| 10575 | 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 | 10583 | inputs[arg_i] = .{ .c = constraint, .n = name }; |
| 10578 | 10584 | } |
| 10579 | 10585 | |
| ... | ... | @@ -10611,7 +10617,9 @@ fn zirAsm( |
| 10611 | 10617 | const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice()); |
| 10612 | 10618 | mem.copy(u8, buffer, o.constraint); |
| 10613 | 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 | 10624 | for (inputs) |input| { |
| 10617 | 10625 | const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice()); |
| ... | ... | @@ -10619,7 +10627,7 @@ fn zirAsm( |
| 10619 | 10627 | buffer[input.c.len] = 0; |
| 10620 | 10628 | mem.copy(u8, buffer[input.c.len + 1 ..], input.n); |
| 10621 | 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 | 10632 | for (clobbers) |clobber| { |
| 10625 | 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 | 3272 | if (output != .none) { |
| 3273 | 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 | 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 | 3278 | // This equation accounts for the fact that even if we have exactly 4 bytes |
| 3277 | 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 | 3282 | break constraint; |
| 3281 | 3283 | } else null; |
| ... | ... | @@ -3283,10 +3285,10 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 3283 | 3285 | for (inputs) |input| { |
| 3284 | 3286 | const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]); |
| 3285 | 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 | 3289 | // This equation accounts for the fact that even if we have exactly 4 bytes |
| 3288 | 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 | 3293 | if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') { |
| 3292 | 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 | 4078 | if (output != .none) { |
| 4079 | 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 | 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 | 4084 | // This equation accounts for the fact that even if we have exactly 4 bytes |
| 4083 | 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 | 4088 | break constraint; |
| 4087 | 4089 | } else null; |
| ... | ... | @@ -4089,10 +4091,10 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 4089 | 4091 | for (inputs) |input| { |
| 4090 | 4092 | const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]); |
| 4091 | 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 | 4095 | // This equation accounts for the fact that even if we have exactly 4 bytes |
| 4094 | 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 | 4099 | if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') { |
| 4098 | 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 | 2098 | if (output != .none) { |
| 2099 | 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 | 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 | 2104 | // This equation accounts for the fact that even if we have exactly 4 bytes |
| 2103 | 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 | 2108 | break constraint; |
| 2107 | 2109 | } else null; |
| ... | ... | @@ -2109,10 +2111,10 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 2109 | 2111 | for (inputs) |input| { |
| 2110 | 2112 | const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]); |
| 2111 | 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 | 2115 | // This equation accounts for the fact that even if we have exactly 4 bytes |
| 2114 | 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 | 2119 | if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') { |
| 2118 | 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 | 642 | if (output != .none) { |
| 643 | 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 | 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 | 648 | // This equation accounts for the fact that even if we have exactly 4 bytes |
| 647 | 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 | 652 | break constraint; |
| 651 | 653 | } else null; |
| ... | ... | @@ -653,10 +655,10 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 653 | 655 | for (inputs) |input| { |
| 654 | 656 | const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]); |
| 655 | 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 | 659 | // This equation accounts for the fact that even if we have exactly 4 bytes |
| 658 | 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 | 663 | if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') { |
| 662 | 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 | 4739 | if (output != .none) { |
| 4740 | 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 | 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 | 4745 | // This equation accounts for the fact that even if we have exactly 4 bytes |
| 4744 | 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 | 4749 | break constraint; |
| 4748 | 4750 | } else null; |
| ... | ... | @@ -4750,10 +4752,10 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 4750 | 4752 | for (inputs) |input| { |
| 4751 | 4753 | const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]); |
| 4752 | 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 | 4756 | // This equation accounts for the fact that even if we have exactly 4 bytes |
| 4755 | 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 | 4760 | if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') { |
| 4759 | 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 | 3018 | if (output != .none) { |
| 3019 | 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 | 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 | 3024 | // This equation accounts for the fact that even if we have exactly 4 bytes |
| 3023 | 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 | 3028 | break constraint; |
| 3027 | 3029 | } else null; |
| ... | ... | @@ -3031,10 +3033,12 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3031 | 3033 | |
| 3032 | 3034 | const inputs_extra_begin = extra_i; |
| 3033 | 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 | 3039 | // This equation accounts for the fact that even if we have exactly 4 bytes |
| 3036 | 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 | 3043 | if (constraint[0] == '{' and constraint[constraint.len - 1] == '}') { |
| 3040 | 3044 | const reg = constraint[1 .. constraint.len - 1]; |
src/codegen/llvm.zig+17-20| ... | ... | @@ -4638,14 +4638,19 @@ pub const FuncGen = struct { |
| 4638 | 4638 | var llvm_param_i: usize = 0; |
| 4639 | 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 | 4644 | for (outputs) |output| { |
| 4642 | 4645 | if (output != .none) { |
| 4643 | 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 | 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 | 4651 | // This equation accounts for the fact that even if we have exactly 4 bytes |
| 4647 | 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 | 4655 | try llvm_constraints.ensureUnusedCapacity(self.gpa, constraint.len + 1); |
| 4651 | 4656 | if (total_i != 0) { |
| ... | ... | @@ -4654,17 +4659,17 @@ pub const FuncGen = struct { |
| 4654 | 4659 | llvm_constraints.appendAssumeCapacity('='); |
| 4655 | 4660 | llvm_constraints.appendSliceAssumeCapacity(constraint[1..]); |
| 4656 | 4661 | |
| 4662 | name_map.putAssumeCapacityNoClobber(name, {}); | |
| 4657 | 4663 | total_i += 1; |
| 4658 | 4664 | } |
| 4659 | 4665 | |
| 4660 | const input_start_extra_i = extra_i; | |
| 4661 | 4666 | for (inputs) |input| { |
| 4662 | const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]); | |
| 4663 | const constraint = std.mem.sliceTo(input_bytes, 0); | |
| 4664 | const input_name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0); | |
| 4667 | const extra_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]); | |
| 4668 | const constraint = std.mem.sliceTo(extra_bytes, 0); | |
| 4669 | const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0); | |
| 4665 | 4670 | // This equation accounts for the fact that even if we have exactly 4 bytes |
| 4666 | 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 | 4674 | const arg_llvm_value = try self.resolveInst(input); |
| 4670 | 4675 | |
| ... | ... | @@ -4677,6 +4682,7 @@ pub const FuncGen = struct { |
| 4677 | 4682 | } |
| 4678 | 4683 | llvm_constraints.appendSliceAssumeCapacity(constraint); |
| 4679 | 4684 | |
| 4685 | name_map.putAssumeCapacityNoClobber(name, {}); | |
| 4680 | 4686 | llvm_param_i += 1; |
| 4681 | 4687 | total_i += 1; |
| 4682 | 4688 | } |
| ... | ... | @@ -4739,20 +4745,11 @@ pub const FuncGen = struct { |
| 4739 | 4745 | const name = asm_source[name_start..i]; |
| 4740 | 4746 | state = .start; |
| 4741 | 4747 | |
| 4742 | extra_i = input_start_extra_i; | |
| 4743 | for (inputs) |_, input_i| { | |
| 4744 | const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]); | |
| 4745 | const constraint = std.mem.sliceTo(input_bytes, 0); | |
| 4746 | const input_name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0); | |
| 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 | } | |
| 4748 | const index = name_map.getIndex(name) orelse { | |
| 4749 | // we should validate the assembly in Sema; by now it is too late | |
| 4750 | return self.todo("unknown input or output name: '{s}'", .{name}); | |
| 4751 | }; | |
| 4752 | try rendered_template.writer().print("{d}", .{index}); | |
| 4756 | 4753 | }, |
| 4757 | 4754 | else => {}, |
| 4758 | 4755 | }, |
src/print_air.zig+18-10| ... | ... | @@ -542,15 +542,19 @@ const Writer = struct { |
| 542 | 542 | extra_i += inputs.len; |
| 543 | 543 | |
| 544 | 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 | 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. | |
| 548 | extra_i += constraint.len / 4 + 1; | |
| 550 | // for the strings and their null terminators, we still use the next u32 | |
| 551 | // for the null terminator. | |
| 552 | extra_i += (constraint.len + name.len + (2 + 3)) / 4; | |
| 549 | 553 | |
| 550 | 554 | if (output == .none) { |
| 551 | try s.print(", -> {s}", .{constraint}); | |
| 555 | try s.print(", [{s}] -> {s}", .{ name, constraint }); | |
| 552 | 556 | } else { |
| 553 | try s.print(", out {s} = (", .{constraint}); | |
| 557 | try s.print(", [{s}] out {s} = (", .{ name, constraint }); | |
| 554 | 558 | try w.writeOperand(s, inst, op_index, output); |
| 555 | 559 | op_index += 1; |
| 556 | 560 | try s.writeByte(')'); |
| ... | ... | @@ -558,12 +562,15 @@ const Writer = struct { |
| 558 | 562 | } |
| 559 | 563 | |
| 560 | 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 | 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. | |
| 564 | extra_i += constraint.len / 4 + 1; | |
| 569 | // for the strings and their null terminators, we still use the next u32 | |
| 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 | 574 | try w.writeOperand(s, inst, op_index, input); |
| 568 | 575 | op_index += 1; |
| 569 | 576 | try s.writeByte(')'); |
| ... | ... | @@ -572,7 +579,8 @@ const Writer = struct { |
| 572 | 579 | { |
| 573 | 580 | var clobber_i: u32 = 0; |
| 574 | 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 | 584 | // This equation accounts for the fact that even if we have exactly 4 bytes |
| 577 | 585 | // for the string, we still use the next u32 for the null terminator. |
| 578 | 586 | extra_i += clobber.len / 4 + 1; |