Commit fbd7e4506f
Changed files (3)
src
src/codegen/llvm.zig
@@ -5435,10 +5435,6 @@ pub const FuncGen = struct {
const inputs = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.inputs_len]);
extra_i += inputs.len;
- if (outputs.len > 1) {
- return self.todo("implement llvm codegen for asm with more than 1 output", .{});
- }
-
var llvm_constraints: std.ArrayListUnmanaged(u8) = .{};
defer llvm_constraints.deinit(self.gpa);
@@ -5446,7 +5442,10 @@ pub const FuncGen = struct {
defer arena_allocator.deinit();
const arena = arena_allocator.allocator();
- const llvm_params_len = inputs.len;
+ const return_count: u8 = for (outputs) |output| {
+ if (output == .none) break 1;
+ } else 0;
+ const llvm_params_len = inputs.len + outputs.len - return_count;
const llvm_param_types = try arena.alloc(*const llvm.Type, llvm_params_len);
const llvm_param_values = try arena.alloc(*const llvm.Value, llvm_params_len);
var llvm_param_i: usize = 0;
@@ -5456,9 +5455,6 @@ pub const FuncGen = struct {
try name_map.ensureUnusedCapacity(arena, outputs.len + inputs.len);
for (outputs) |output| {
- if (output != .none) {
- return self.todo("implement inline asm with non-returned output", .{});
- }
const extra_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0);
const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
@@ -5471,6 +5467,15 @@ pub const FuncGen = struct {
llvm_constraints.appendAssumeCapacity(',');
}
llvm_constraints.appendAssumeCapacity('=');
+ if (output != .none) {
+ try llvm_constraints.ensureUnusedCapacity(self.gpa, llvm_constraints.capacity + 1);
+ llvm_constraints.appendAssumeCapacity('*');
+
+ const output_inst = try self.resolveInst(output);
+ llvm_param_values[llvm_param_i] = output_inst;
+ llvm_param_types[llvm_param_i] = output_inst.typeOf();
+ llvm_param_i += 1;
+ }
llvm_constraints.appendSliceAssumeCapacity(constraint[1..]);
name_map.putAssumeCapacityNoClobber(name, {});
src/AstGen.zig
@@ -6876,6 +6876,9 @@ fn asmExpr(
const constraint = (try astgen.strLitAsString(constraint_token)).index;
const has_arrow = token_tags[symbolic_name + 4] == .arrow;
if (has_arrow) {
+ if (output_type_bits != 0) {
+ return astgen.failNode(output_node, "inline assembly allows up to one output value", .{});
+ }
output_type_bits |= @as(u32, 1) << @intCast(u5, i);
const out_type_node = node_datas[output_node].lhs;
const out_type_inst = try typeExpr(gz, scope, out_type_node);
@@ -6892,7 +6895,7 @@ fn asmExpr(
outputs[i] = .{
.name = name,
.constraint = constraint,
- .operand = try localVarRef(gz, scope, rl, node, ident_token),
+ .operand = try localVarRef(gz, scope, .ref, node, ident_token),
};
}
}
src/Sema.zig
@@ -11334,43 +11334,40 @@ fn zirAsm(
try sema.requireRuntimeBlock(block, src);
}
- if (outputs_len > 1) {
- return sema.fail(block, src, "TODO implement Sema for asm with more than 1 output", .{});
- }
-
var extra_i = extra.end;
var output_type_bits = extra.data.output_type_bits;
var needed_capacity: usize = @typeInfo(Air.Asm).Struct.fields.len + outputs_len + inputs_len;
- const Output = struct {
- constraint: []const u8,
- name: []const u8,
- ty: Type,
- };
- const output: ?Output = if (outputs_len == 0) null else blk: {
+ const ConstraintName = struct { c: []const u8, n: []const u8 };
+ const out_args = try sema.arena.alloc(Air.Inst.Ref, outputs_len);
+ const outputs = try sema.arena.alloc(ConstraintName, outputs_len);
+ var expr_ty = Air.Inst.Ref.void_type;
+
+ for (out_args) |*arg, out_i| {
const output = sema.code.extraData(Zir.Inst.Asm.Output, extra_i);
extra_i = output.end;
const is_type = @truncate(u1, output_type_bits) != 0;
output_type_bits >>= 1;
- if (!is_type) {
- return sema.fail(block, src, "TODO implement Sema for asm with non `->` output", .{});
+ if (is_type) {
+ // Indicate the output is the asm instruction return value.
+ arg.* = .none;
+ const out_ty = try sema.resolveType(block, ret_ty_src, output.data.operand);
+ expr_ty = try sema.addType(out_ty);
+ } else {
+ arg.* = try sema.resolveInst(output.data.operand);
}
const constraint = sema.code.nullTerminatedString(output.data.constraint);
const name = sema.code.nullTerminatedString(output.data.name);
needed_capacity += (constraint.len + name.len + (2 + 3)) / 4;
- break :blk Output{
- .constraint = constraint,
- .name = name,
- .ty = try sema.resolveType(block, ret_ty_src, output.data.operand),
- };
- };
+ outputs[out_i] = .{ .c = constraint, .n = name };
+ }
const args = try sema.arena.alloc(Air.Inst.Ref, inputs_len);
- const inputs = try sema.arena.alloc(struct { c: []const u8, n: []const u8 }, inputs_len);
+ const inputs = try sema.arena.alloc(ConstraintName, inputs_len);
for (args) |*arg, arg_i| {
const input = sema.code.extraData(Zir.Inst.Asm.Input, extra_i);
@@ -11405,7 +11402,7 @@ fn zirAsm(
const asm_air = try block.addInst(.{
.tag = .assembly,
.data = .{ .ty_pl = .{
- .ty = if (output) |o| try sema.addType(o.ty) else Air.Inst.Ref.void_type,
+ .ty = expr_ty,
.payload = sema.addExtraAssumeCapacity(Air.Asm{
.source_len = @intCast(u32, asm_source.len),
.outputs_len = outputs_len,
@@ -11414,18 +11411,15 @@ fn zirAsm(
}),
} },
});
- if (output != null) {
- // Indicate the output is the asm instruction return value.
- sema.air_extra.appendAssumeCapacity(@enumToInt(Air.Inst.Ref.none));
- }
+ sema.appendRefsAssumeCapacity(out_args);
sema.appendRefsAssumeCapacity(args);
- if (output) |o| {
+ for (outputs) |o| {
const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());
- mem.copy(u8, buffer, o.constraint);
- buffer[o.constraint.len] = 0;
- mem.copy(u8, buffer[o.constraint.len + 1 ..], o.name);
- buffer[o.constraint.len + 1 + o.name.len] = 0;
- sema.air_extra.items.len += (o.constraint.len + o.name.len + (2 + 3)) / 4;
+ mem.copy(u8, buffer, o.c);
+ buffer[o.c.len] = 0;
+ mem.copy(u8, buffer[o.c.len + 1 ..], o.n);
+ buffer[o.c.len + 1 + o.n.len] = 0;
+ sema.air_extra.items.len += (o.c.len + o.n.len + (2 + 3)) / 4;
}
for (inputs) |input| {
const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());