stage2: handle assembly input names

This commit is contained in:
Veikka Tuominen 2022-03-31 00:38:19 +03:00 committed by Andrew Kelley
parent 6655c6092e
commit 75c2cff40e
7 changed files with 63 additions and 22 deletions

View File

@ -815,6 +815,8 @@ pub const VectorCmp = struct {
/// terminated string. pad to the next u32 after the null byte.
/// 3. for every inputs_len
/// - constraint: memory at this position is reinterpreted as a null
/// terminated string.
/// - name: memory at this position is reinterpreted as a null
/// terminated string. pad to the next u32 after the null byte.
/// 4. for every clobbers_len
/// - clobber_name: memory at this position is reinterpreted as a null

View File

@ -10295,15 +10295,12 @@ fn zirAsm(
};
const args = try sema.arena.alloc(Air.Inst.Ref, inputs_len);
const inputs = try sema.arena.alloc([]const u8, inputs_len);
const inputs = try sema.arena.alloc(struct { c: []const u8, n: []const u8 }, inputs_len);
for (args) |*arg, arg_i| {
const input = sema.code.extraData(Zir.Inst.Asm.Input, extra_i);
extra_i = input.end;
const name = sema.code.nullTerminatedString(input.data.name);
_ = name; // TODO: use the name
const uncasted_arg = sema.resolveInst(input.data.operand);
const uncasted_arg_ty = sema.typeOf(uncasted_arg);
switch (uncasted_arg_ty.zigTypeTag()) {
@ -10313,8 +10310,9 @@ fn zirAsm(
}
const constraint = sema.code.nullTerminatedString(input.data.constraint);
needed_capacity += constraint.len / 4 + 1;
inputs[arg_i] = constraint;
const name = sema.code.nullTerminatedString(input.data.name);
needed_capacity += (constraint.len + name.len + 1) / 4 + 1;
inputs[arg_i] = .{ .c = constraint, .n = name };
}
const clobbers = try sema.arena.alloc([]const u8, clobbers_len);
@ -10353,11 +10351,13 @@ fn zirAsm(
buffer[o.constraint.len] = 0;
sema.air_extra.items.len += o.constraint.len / 4 + 1;
}
for (inputs) |constraint| {
for (inputs) |input| {
const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());
mem.copy(u8, buffer, constraint);
buffer[constraint.len] = 0;
sema.air_extra.items.len += constraint.len / 4 + 1;
mem.copy(u8, buffer, input.c);
buffer[input.c.len] = 0;
mem.copy(u8, buffer[input.c.len + 1 ..], input.n);
buffer[input.c.len + 1 + input.n.len] = 0;
sema.air_extra.items.len += (input.c.len + input.n.len + 1) / 4 + 1;
}
for (clobbers) |clobber| {
const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());

View File

@ -3200,10 +3200,12 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
} else null;
for (inputs) |input| {
const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0);
const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
const constraint = std.mem.sliceTo(input_bytes, 0);
const input_name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0);
// This equation accounts for the fact that even if we have exactly 4 bytes
// for the string, we still use the next u32 for the null terminator.
extra_i += constraint.len / 4 + 1;
extra_i += (constraint.len + input_name.len + 1) / 4 + 1;
if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') {
return self.fail("unrecognized asm input constraint: '{s}'", .{constraint});

View File

@ -3609,10 +3609,12 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
} else null;
for (inputs) |input| {
const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0);
const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
const constraint = std.mem.sliceTo(input_bytes, 0);
const input_name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0);
// This equation accounts for the fact that even if we have exactly 4 bytes
// for the string, we still use the next u32 for the null terminator.
extra_i += constraint.len / 4 + 1;
extra_i += (constraint.len + input_name.len + 1) / 4 + 1;
if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') {
return self.fail("unrecognized asm input constraint: '{s}'", .{constraint});

View File

@ -2113,10 +2113,12 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
} else null;
for (inputs) |input| {
const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0);
const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
const constraint = std.mem.sliceTo(input_bytes, 0);
const input_name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0);
// This equation accounts for the fact that even if we have exactly 4 bytes
// for the string, we still use the next u32 for the null terminator.
extra_i += constraint.len / 4 + 1;
extra_i += (constraint.len + input_name.len + 1) / 4 + 1;
if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') {
return self.fail("unrecognized asm input constraint: '{s}'", .{constraint});

View File

@ -4618,10 +4618,12 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
} else null;
for (inputs) |input| {
const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0);
const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
const constraint = std.mem.sliceTo(input_bytes, 0);
const input_name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0);
// This equation accounts for the fact that even if we have exactly 4 bytes
// for the string, we still use the next u32 for the null terminator.
extra_i += constraint.len / 4 + 1;
extra_i += (constraint.len + input_name.len + 1) / 4 + 1;
if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') {
return self.fail("unrecognized asm input constraint: '{s}'", .{constraint});

View File

@ -4545,11 +4545,14 @@ pub const FuncGen = struct {
total_i += 1;
}
const input_start_extra_i = extra_i;
for (inputs) |input| {
const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0);
const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
const constraint = std.mem.sliceTo(input_bytes, 0);
const input_name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0);
// This equation accounts for the fact that even if we have exactly 4 bytes
// for the string, we still use the next u32 for the null terminator.
extra_i += constraint.len / 4 + 1;
extra_i += (constraint.len + input_name.len + 1) / 4 + 1;
const arg_llvm_value = try self.resolveInst(input);
@ -4591,11 +4594,12 @@ pub const FuncGen = struct {
var rendered_template = std.ArrayList(u8).init(self.gpa);
defer rendered_template.deinit();
const State = enum { start, percent };
const State = enum { start, percent, input };
var state: State = .start;
for (asm_source) |byte| {
var name_start: usize = undefined;
for (asm_source) |byte, i| {
switch (state) {
.start => switch (byte) {
'%' => state = .percent,
@ -4606,12 +4610,39 @@ pub const FuncGen = struct {
try rendered_template.append('%');
state = .start;
},
'[' => {
try rendered_template.append('$');
name_start = i + 1;
state = .input;
},
else => {
try rendered_template.append('%');
try rendered_template.append(byte);
state = .start;
},
},
.input => switch (byte) {
']' => {
const name = asm_source[name_start..i];
state = .start;
extra_i = input_start_extra_i;
for (inputs) |_, input_i| {
const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
const constraint = std.mem.sliceTo(input_bytes, 0);
const input_name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0);
extra_i += (constraint.len + input_name.len + 1) / 4 + 1;
if (std.mem.eql(u8, name, input_name)) {
try rendered_template.writer().print("{d}", .{input_i});
break;
}
} else {
return self.todo("TODO validate asm in Sema", .{});
}
},
else => {},
},
}
}