authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-03-31 00:38:19+03:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-31 01:33:28-04:00
log75c2cff40ef5c758ec18455324a50378684aff85
treedbad1cafdd53fcab11e9be52aa27702b9bbb1345
parent6655c6092efbdc8b1aeb89ff9f7a8b05f736916a

stage2: handle assembly input names


7 files changed, 63 insertions(+), 22 deletions(-)

src/Air.zig+2
...@@ -815,6 +815,8 @@ pub const VectorCmp = struct {...@@ -815,6 +815,8 @@ pub const VectorCmp = struct {
815/// terminated string. pad to the next u32 after the null byte.815/// terminated string. pad to the next u32 after the null byte.
816/// 3. for every inputs_len816/// 3. for every inputs_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/// 4. for every clobbers_len821/// 4. for every clobbers_len
820/// - clobber_name: memory at this position is reinterpreted as a null822/// - clobber_name: memory at this position is reinterpreted as a null
src/Sema.zig+10-10
...@@ -10295,15 +10295,12 @@ fn zirAsm(...@@ -10295,15 +10295,12 @@ fn zirAsm(
10295 };10295 };
1029610296
10297 const args = try sema.arena.alloc(Air.Inst.Ref, inputs_len);10297 const args = try sema.arena.alloc(Air.Inst.Ref, inputs_len);
10298 const inputs = try sema.arena.alloc([]const u8, inputs_len);10298 const inputs = try sema.arena.alloc(struct { c: []const u8, n: []const u8 }, inputs_len);
1029910299
10300 for (args) |*arg, arg_i| {10300 for (args) |*arg, arg_i| {
10301 const input = sema.code.extraData(Zir.Inst.Asm.Input, extra_i);10301 const input = sema.code.extraData(Zir.Inst.Asm.Input, extra_i);
10302 extra_i = input.end;10302 extra_i = input.end;
1030310303
10304 const name = sema.code.nullTerminatedString(input.data.name);
10305 _ = name; // TODO: use the name
10306
10307 const uncasted_arg = sema.resolveInst(input.data.operand);10304 const uncasted_arg = sema.resolveInst(input.data.operand);
10308 const uncasted_arg_ty = sema.typeOf(uncasted_arg);10305 const uncasted_arg_ty = sema.typeOf(uncasted_arg);
10309 switch (uncasted_arg_ty.zigTypeTag()) {10306 switch (uncasted_arg_ty.zigTypeTag()) {
...@@ -10313,8 +10310,9 @@ fn zirAsm(...@@ -10313,8 +10310,9 @@ fn zirAsm(
10313 }10310 }
1031410311
10315 const constraint = sema.code.nullTerminatedString(input.data.constraint);10312 const constraint = sema.code.nullTerminatedString(input.data.constraint);
10316 needed_capacity += constraint.len / 4 + 1;10313 const name = sema.code.nullTerminatedString(input.data.name);
10317 inputs[arg_i] = constraint;10314 needed_capacity += (constraint.len + name.len + 1) / 4 + 1;
10315 inputs[arg_i] = .{ .c = constraint, .n = name };
10318 }10316 }
1031910317
10320 const clobbers = try sema.arena.alloc([]const u8, clobbers_len);10318 const clobbers = try sema.arena.alloc([]const u8, clobbers_len);
...@@ -10353,11 +10351,13 @@ fn zirAsm(...@@ -10353,11 +10351,13 @@ fn zirAsm(
10353 buffer[o.constraint.len] = 0;10351 buffer[o.constraint.len] = 0;
10354 sema.air_extra.items.len += o.constraint.len / 4 + 1;10352 sema.air_extra.items.len += o.constraint.len / 4 + 1;
10355 }10353 }
10356 for (inputs) |constraint| {10354 for (inputs) |input| {
10357 const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());10355 const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());
10358 mem.copy(u8, buffer, constraint);10356 mem.copy(u8, buffer, input.c);
10359 buffer[constraint.len] = 0;10357 buffer[input.c.len] = 0;
10360 sema.air_extra.items.len += constraint.len / 4 + 1;10358 mem.copy(u8, buffer[input.c.len + 1 ..], input.n);
10359 buffer[input.c.len + 1 + input.n.len] = 0;
10360 sema.air_extra.items.len += (input.c.len + input.n.len + 1) / 4 + 1;
10361 }10361 }
10362 for (clobbers) |clobber| {10362 for (clobbers) |clobber| {
10363 const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());10363 const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());
src/arch/aarch64/CodeGen.zig+4-2
...@@ -3200,10 +3200,12 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -3200,10 +3200,12 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
3200 } else null;3200 } else null;
32013201
3202 for (inputs) |input| {3202 for (inputs) |input| {
3203 const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0);3203 const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
3204 const constraint = std.mem.sliceTo(input_bytes, 0);
3205 const input_name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0);
3204 // This equation accounts for the fact that even if we have exactly 4 bytes3206 // This equation accounts for the fact that even if we have exactly 4 bytes
3205 // for the string, we still use the next u32 for the null terminator.3207 // for the string, we still use the next u32 for the null terminator.
3206 extra_i += constraint.len / 4 + 1;3208 extra_i += (constraint.len + input_name.len + 1) / 4 + 1;
32073209
3208 if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') {3210 if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') {
3209 return self.fail("unrecognized asm input constraint: '{s}'", .{constraint});3211 return self.fail("unrecognized asm input constraint: '{s}'", .{constraint});
src/arch/arm/CodeGen.zig+4-2
...@@ -3609,10 +3609,12 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -3609,10 +3609,12 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
3609 } else null;3609 } else null;
36103610
3611 for (inputs) |input| {3611 for (inputs) |input| {
3612 const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0);3612 const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
3613 const constraint = std.mem.sliceTo(input_bytes, 0);
3614 const input_name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0);
3613 // This equation accounts for the fact that even if we have exactly 4 bytes3615 // This equation accounts for the fact that even if we have exactly 4 bytes
3614 // for the string, we still use the next u32 for the null terminator.3616 // for the string, we still use the next u32 for the null terminator.
3615 extra_i += constraint.len / 4 + 1;3617 extra_i += (constraint.len + input_name.len + 1) / 4 + 1;
36163618
3617 if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') {3619 if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') {
3618 return self.fail("unrecognized asm input constraint: '{s}'", .{constraint});3620 return self.fail("unrecognized asm input constraint: '{s}'", .{constraint});
src/arch/riscv64/CodeGen.zig+4-2
...@@ -2113,10 +2113,12 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -2113,10 +2113,12 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
2113 } else null;2113 } else null;
21142114
2115 for (inputs) |input| {2115 for (inputs) |input| {
2116 const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0);2116 const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
2117 const constraint = std.mem.sliceTo(input_bytes, 0);
2118 const input_name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0);
2117 // This equation accounts for the fact that even if we have exactly 4 bytes2119 // This equation accounts for the fact that even if we have exactly 4 bytes
2118 // for the string, we still use the next u32 for the null terminator.2120 // for the string, we still use the next u32 for the null terminator.
2119 extra_i += constraint.len / 4 + 1;2121 extra_i += (constraint.len + input_name.len + 1) / 4 + 1;
21202122
2121 if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') {2123 if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') {
2122 return self.fail("unrecognized asm input constraint: '{s}'", .{constraint});2124 return self.fail("unrecognized asm input constraint: '{s}'", .{constraint});
src/arch/x86_64/CodeGen.zig+4-2
...@@ -4618,10 +4618,12 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -4618,10 +4618,12 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
4618 } else null;4618 } else null;
46194619
4620 for (inputs) |input| {4620 for (inputs) |input| {
4621 const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0);4621 const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
4622 const constraint = std.mem.sliceTo(input_bytes, 0);
4623 const input_name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0);
4622 // This equation accounts for the fact that even if we have exactly 4 bytes4624 // This equation accounts for the fact that even if we have exactly 4 bytes
4623 // for the string, we still use the next u32 for the null terminator.4625 // for the string, we still use the next u32 for the null terminator.
4624 extra_i += constraint.len / 4 + 1;4626 extra_i += (constraint.len + input_name.len + 1) / 4 + 1;
46254627
4626 if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') {4628 if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') {
4627 return self.fail("unrecognized asm input constraint: '{s}'", .{constraint});4629 return self.fail("unrecognized asm input constraint: '{s}'", .{constraint});
src/codegen/llvm.zig+35-4
...@@ -4545,11 +4545,14 @@ pub const FuncGen = struct {...@@ -4545,11 +4545,14 @@ pub const FuncGen = struct {
4545 total_i += 1;4545 total_i += 1;
4546 }4546 }
45474547
4548 const input_start_extra_i = extra_i;
4548 for (inputs) |input| {4549 for (inputs) |input| {
4549 const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0);4550 const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
4551 const constraint = std.mem.sliceTo(input_bytes, 0);
4552 const input_name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0);
4550 // This equation accounts for the fact that even if we have exactly 4 bytes4553 // This equation accounts for the fact that even if we have exactly 4 bytes
4551 // for the string, we still use the next u32 for the null terminator.4554 // for the string, we still use the next u32 for the null terminator.
4552 extra_i += constraint.len / 4 + 1;4555 extra_i += (constraint.len + input_name.len + 1) / 4 + 1;
45534556
4554 const arg_llvm_value = try self.resolveInst(input);4557 const arg_llvm_value = try self.resolveInst(input);
45554558
...@@ -4591,11 +4594,12 @@ pub const FuncGen = struct {...@@ -4591,11 +4594,12 @@ pub const FuncGen = struct {
4591 var rendered_template = std.ArrayList(u8).init(self.gpa);4594 var rendered_template = std.ArrayList(u8).init(self.gpa);
4592 defer rendered_template.deinit();4595 defer rendered_template.deinit();
45934596
4594 const State = enum { start, percent };4597 const State = enum { start, percent, input };
45954598
4596 var state: State = .start;4599 var state: State = .start;
45974600
4598 for (asm_source) |byte| {4601 var name_start: usize = undefined;
4602 for (asm_source) |byte, i| {
4599 switch (state) {4603 switch (state) {
4600 .start => switch (byte) {4604 .start => switch (byte) {
4601 '%' => state = .percent,4605 '%' => state = .percent,
...@@ -4606,12 +4610,39 @@ pub const FuncGen = struct {...@@ -4606,12 +4610,39 @@ pub const FuncGen = struct {
4606 try rendered_template.append('%');4610 try rendered_template.append('%');
4607 state = .start;4611 state = .start;
4608 },4612 },
4613 '[' => {
4614 try rendered_template.append('$');
4615 name_start = i + 1;
4616 state = .input;
4617 },
4609 else => {4618 else => {
4610 try rendered_template.append('%');4619 try rendered_template.append('%');
4611 try rendered_template.append(byte);4620 try rendered_template.append(byte);
4612 state = .start;4621 state = .start;
4613 },4622 },
4614 },4623 },
4624 .input => switch (byte) {
4625 ']' => {
4626 const name = asm_source[name_start..i];
4627 state = .start;
4628
4629 extra_i = input_start_extra_i;
4630 for (inputs) |_, input_i| {
4631 const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
4632 const constraint = std.mem.sliceTo(input_bytes, 0);
4633 const input_name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0);
4634 extra_i += (constraint.len + input_name.len + 1) / 4 + 1;
4635
4636 if (std.mem.eql(u8, name, input_name)) {
4637 try rendered_template.writer().print("{d}", .{input_i});
4638 break;
4639 }
4640 } else {
4641 return self.todo("TODO validate asm in Sema", .{});
4642 }
4643 },
4644 else => {},
4645 },
4615 }4646 }
4616 }4647 }
46174648