authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-06-07 19:13:50+03:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-06-07 21:27:06+03:00
logfbd7e4506f46b73e351e1f3eb5e7cfc16ebbfc1f
tree574527e8cba0bc39eb18b722ef6a4221528215c8
parente4c0b848a46347fccced787488605ac66e83c38a

stage2: implement asm with multiple outputs


3 files changed, 41 insertions(+), 39 deletions(-)

src/AstGen.zig+4-1
......@@ -6876,6 +6876,9 @@ fn asmExpr(
68766876 const constraint = (try astgen.strLitAsString(constraint_token)).index;
68776877 const has_arrow = token_tags[symbolic_name + 4] == .arrow;
68786878 if (has_arrow) {
6879 if (output_type_bits != 0) {
6880 return astgen.failNode(output_node, "inline assembly allows up to one output value", .{});
6881 }
68796882 output_type_bits |= @as(u32, 1) << @intCast(u5, i);
68806883 const out_type_node = node_datas[output_node].lhs;
68816884 const out_type_inst = try typeExpr(gz, scope, out_type_node);
......@@ -6892,7 +6895,7 @@ fn asmExpr(
68926895 outputs[i] = .{
68936896 .name = name,
68946897 .constraint = constraint,
6895 .operand = try localVarRef(gz, scope, rl, node, ident_token),
6898 .operand = try localVarRef(gz, scope, .ref, node, ident_token),
68966899 };
68976900 }
68986901 }
src/Sema.zig+24-30
......@@ -11334,43 +11334,40 @@ fn zirAsm(
1133411334 try sema.requireRuntimeBlock(block, src);
1133511335 }
1133611336
11337 if (outputs_len > 1) {
11338 return sema.fail(block, src, "TODO implement Sema for asm with more than 1 output", .{});
11339 }
11340
1134111337 var extra_i = extra.end;
1134211338 var output_type_bits = extra.data.output_type_bits;
1134311339 var needed_capacity: usize = @typeInfo(Air.Asm).Struct.fields.len + outputs_len + inputs_len;
1134411340
11345 const Output = struct {
11346 constraint: []const u8,
11347 name: []const u8,
11348 ty: Type,
11349 };
11350 const output: ?Output = if (outputs_len == 0) null else blk: {
11341 const ConstraintName = struct { c: []const u8, n: []const u8 };
11342 const out_args = try sema.arena.alloc(Air.Inst.Ref, outputs_len);
11343 const outputs = try sema.arena.alloc(ConstraintName, outputs_len);
11344 var expr_ty = Air.Inst.Ref.void_type;
11345
11346 for (out_args) |*arg, out_i| {
1135111347 const output = sema.code.extraData(Zir.Inst.Asm.Output, extra_i);
1135211348 extra_i = output.end;
1135311349
1135411350 const is_type = @truncate(u1, output_type_bits) != 0;
1135511351 output_type_bits >>= 1;
1135611352
11357 if (!is_type) {
11358 return sema.fail(block, src, "TODO implement Sema for asm with non `->` output", .{});
11353 if (is_type) {
11354 // Indicate the output is the asm instruction return value.
11355 arg.* = .none;
11356 const out_ty = try sema.resolveType(block, ret_ty_src, output.data.operand);
11357 expr_ty = try sema.addType(out_ty);
11358 } else {
11359 arg.* = try sema.resolveInst(output.data.operand);
1135911360 }
1136011361
1136111362 const constraint = sema.code.nullTerminatedString(output.data.constraint);
1136211363 const name = sema.code.nullTerminatedString(output.data.name);
1136311364 needed_capacity += (constraint.len + name.len + (2 + 3)) / 4;
1136411365
11365 break :blk Output{
11366 .constraint = constraint,
11367 .name = name,
11368 .ty = try sema.resolveType(block, ret_ty_src, output.data.operand),
11369 };
11370 };
11366 outputs[out_i] = .{ .c = constraint, .n = name };
11367 }
1137111368
1137211369 const args = try sema.arena.alloc(Air.Inst.Ref, inputs_len);
11373 const inputs = try sema.arena.alloc(struct { c: []const u8, n: []const u8 }, inputs_len);
11370 const inputs = try sema.arena.alloc(ConstraintName, inputs_len);
1137411371
1137511372 for (args) |*arg, arg_i| {
1137611373 const input = sema.code.extraData(Zir.Inst.Asm.Input, extra_i);
......@@ -11405,7 +11402,7 @@ fn zirAsm(
1140511402 const asm_air = try block.addInst(.{
1140611403 .tag = .assembly,
1140711404 .data = .{ .ty_pl = .{
11408 .ty = if (output) |o| try sema.addType(o.ty) else Air.Inst.Ref.void_type,
11405 .ty = expr_ty,
1140911406 .payload = sema.addExtraAssumeCapacity(Air.Asm{
1141011407 .source_len = @intCast(u32, asm_source.len),
1141111408 .outputs_len = outputs_len,
......@@ -11414,18 +11411,15 @@ fn zirAsm(
1141411411 }),
1141511412 } },
1141611413 });
11417 if (output != null) {
11418 // Indicate the output is the asm instruction return value.
11419 sema.air_extra.appendAssumeCapacity(@enumToInt(Air.Inst.Ref.none));
11420 }
11414 sema.appendRefsAssumeCapacity(out_args);
1142111415 sema.appendRefsAssumeCapacity(args);
11422 if (output) |o| {
11416 for (outputs) |o| {
1142311417 const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());
11424 mem.copy(u8, buffer, o.constraint);
11425 buffer[o.constraint.len] = 0;
11426 mem.copy(u8, buffer[o.constraint.len + 1 ..], o.name);
11427 buffer[o.constraint.len + 1 + o.name.len] = 0;
11428 sema.air_extra.items.len += (o.constraint.len + o.name.len + (2 + 3)) / 4;
11418 mem.copy(u8, buffer, o.c);
11419 buffer[o.c.len] = 0;
11420 mem.copy(u8, buffer[o.c.len + 1 ..], o.n);
11421 buffer[o.c.len + 1 + o.n.len] = 0;
11422 sema.air_extra.items.len += (o.c.len + o.n.len + (2 + 3)) / 4;
1142911423 }
1143011424 for (inputs) |input| {
1143111425 const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());
src/codegen/llvm.zig+13-8
......@@ -5435,10 +5435,6 @@ pub const FuncGen = struct {
54355435 const inputs = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.inputs_len]);
54365436 extra_i += inputs.len;
54375437
5438 if (outputs.len > 1) {
5439 return self.todo("implement llvm codegen for asm with more than 1 output", .{});
5440 }
5441
54425438 var llvm_constraints: std.ArrayListUnmanaged(u8) = .{};
54435439 defer llvm_constraints.deinit(self.gpa);
54445440
......@@ -5446,7 +5442,10 @@ pub const FuncGen = struct {
54465442 defer arena_allocator.deinit();
54475443 const arena = arena_allocator.allocator();
54485444
5449 const llvm_params_len = inputs.len;
5445 const return_count: u8 = for (outputs) |output| {
5446 if (output == .none) break 1;
5447 } else 0;
5448 const llvm_params_len = inputs.len + outputs.len - return_count;
54505449 const llvm_param_types = try arena.alloc(*const llvm.Type, llvm_params_len);
54515450 const llvm_param_values = try arena.alloc(*const llvm.Value, llvm_params_len);
54525451 var llvm_param_i: usize = 0;
......@@ -5456,9 +5455,6 @@ pub const FuncGen = struct {
54565455 try name_map.ensureUnusedCapacity(arena, outputs.len + inputs.len);
54575456
54585457 for (outputs) |output| {
5459 if (output != .none) {
5460 return self.todo("implement inline asm with non-returned output", .{});
5461 }
54625458 const extra_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
54635459 const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0);
54645460 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
......@@ -5471,6 +5467,15 @@ pub const FuncGen = struct {
54715467 llvm_constraints.appendAssumeCapacity(',');
54725468 }
54735469 llvm_constraints.appendAssumeCapacity('=');
5470 if (output != .none) {
5471 try llvm_constraints.ensureUnusedCapacity(self.gpa, llvm_constraints.capacity + 1);
5472 llvm_constraints.appendAssumeCapacity('*');
5473
5474 const output_inst = try self.resolveInst(output);
5475 llvm_param_values[llvm_param_i] = output_inst;
5476 llvm_param_types[llvm_param_i] = output_inst.typeOf();
5477 llvm_param_i += 1;
5478 }
54745479 llvm_constraints.appendSliceAssumeCapacity(constraint[1..]);
54755480
54765481 name_map.putAssumeCapacityNoClobber(name, {});