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(...@@ -6876,6 +6876,9 @@ fn asmExpr(
6876 const constraint = (try astgen.strLitAsString(constraint_token)).index;6876 const constraint = (try astgen.strLitAsString(constraint_token)).index;
6877 const has_arrow = token_tags[symbolic_name + 4] == .arrow;6877 const has_arrow = token_tags[symbolic_name + 4] == .arrow;
6878 if (has_arrow) {6878 if (has_arrow) {
6879 if (output_type_bits != 0) {
6880 return astgen.failNode(output_node, "inline assembly allows up to one output value", .{});
6881 }
6879 output_type_bits |= @as(u32, 1) << @intCast(u5, i);6882 output_type_bits |= @as(u32, 1) << @intCast(u5, i);
6880 const out_type_node = node_datas[output_node].lhs;6883 const out_type_node = node_datas[output_node].lhs;
6881 const out_type_inst = try typeExpr(gz, scope, out_type_node);6884 const out_type_inst = try typeExpr(gz, scope, out_type_node);
...@@ -6892,7 +6895,7 @@ fn asmExpr(...@@ -6892,7 +6895,7 @@ fn asmExpr(
6892 outputs[i] = .{6895 outputs[i] = .{
6893 .name = name,6896 .name = name,
6894 .constraint = constraint,6897 .constraint = constraint,
6895 .operand = try localVarRef(gz, scope, rl, node, ident_token),6898 .operand = try localVarRef(gz, scope, .ref, node, ident_token),
6896 };6899 };
6897 }6900 }
6898 }6901 }
src/Sema.zig+24-30
...@@ -11334,43 +11334,40 @@ fn zirAsm(...@@ -11334,43 +11334,40 @@ fn zirAsm(
11334 try sema.requireRuntimeBlock(block, src);11334 try sema.requireRuntimeBlock(block, src);
11335 }11335 }
1133611336
11337 if (outputs_len > 1) {
11338 return sema.fail(block, src, "TODO implement Sema for asm with more than 1 output", .{});
11339 }
11340
11341 var extra_i = extra.end;11337 var extra_i = extra.end;
11342 var output_type_bits = extra.data.output_type_bits;11338 var output_type_bits = extra.data.output_type_bits;
11343 var needed_capacity: usize = @typeInfo(Air.Asm).Struct.fields.len + outputs_len + inputs_len;11339 var needed_capacity: usize = @typeInfo(Air.Asm).Struct.fields.len + outputs_len + inputs_len;
1134411340
11345 const Output = struct {11341 const ConstraintName = struct { c: []const u8, n: []const u8 };
11346 constraint: []const u8,11342 const out_args = try sema.arena.alloc(Air.Inst.Ref, outputs_len);
11347 name: []const u8,11343 const outputs = try sema.arena.alloc(ConstraintName, outputs_len);
11348 ty: Type,11344 var expr_ty = Air.Inst.Ref.void_type;
11349 };11345
11350 const output: ?Output = if (outputs_len == 0) null else blk: {11346 for (out_args) |*arg, out_i| {
11351 const output = sema.code.extraData(Zir.Inst.Asm.Output, extra_i);11347 const output = sema.code.extraData(Zir.Inst.Asm.Output, extra_i);
11352 extra_i = output.end;11348 extra_i = output.end;
1135311349
11354 const is_type = @truncate(u1, output_type_bits) != 0;11350 const is_type = @truncate(u1, output_type_bits) != 0;
11355 output_type_bits >>= 1;11351 output_type_bits >>= 1;
1135611352
11357 if (!is_type) {11353 if (is_type) {
11358 return sema.fail(block, src, "TODO implement Sema for asm with non `->` output", .{});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);
11359 }11360 }
1136011361
11361 const constraint = sema.code.nullTerminatedString(output.data.constraint);11362 const constraint = sema.code.nullTerminatedString(output.data.constraint);
11362 const name = sema.code.nullTerminatedString(output.data.name);11363 const name = sema.code.nullTerminatedString(output.data.name);
11363 needed_capacity += (constraint.len + name.len + (2 + 3)) / 4;11364 needed_capacity += (constraint.len + name.len + (2 + 3)) / 4;
1136411365
11365 break :blk Output{11366 outputs[out_i] = .{ .c = constraint, .n = name };
11366 .constraint = constraint,11367 }
11367 .name = name,
11368 .ty = try sema.resolveType(block, ret_ty_src, output.data.operand),
11369 };
11370 };
1137111368
11372 const args = try sema.arena.alloc(Air.Inst.Ref, inputs_len);11369 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
11375 for (args) |*arg, arg_i| {11372 for (args) |*arg, arg_i| {
11376 const input = sema.code.extraData(Zir.Inst.Asm.Input, extra_i);11373 const input = sema.code.extraData(Zir.Inst.Asm.Input, extra_i);
...@@ -11405,7 +11402,7 @@ fn zirAsm(...@@ -11405,7 +11402,7 @@ fn zirAsm(
11405 const asm_air = try block.addInst(.{11402 const asm_air = try block.addInst(.{
11406 .tag = .assembly,11403 .tag = .assembly,
11407 .data = .{ .ty_pl = .{11404 .data = .{ .ty_pl = .{
11408 .ty = if (output) |o| try sema.addType(o.ty) else Air.Inst.Ref.void_type,11405 .ty = expr_ty,
11409 .payload = sema.addExtraAssumeCapacity(Air.Asm{11406 .payload = sema.addExtraAssumeCapacity(Air.Asm{
11410 .source_len = @intCast(u32, asm_source.len),11407 .source_len = @intCast(u32, asm_source.len),
11411 .outputs_len = outputs_len,11408 .outputs_len = outputs_len,
...@@ -11414,18 +11411,15 @@ fn zirAsm(...@@ -11414,18 +11411,15 @@ fn zirAsm(
11414 }),11411 }),
11415 } },11412 } },
11416 });11413 });
11417 if (output != null) {11414 sema.appendRefsAssumeCapacity(out_args);
11418 // Indicate the output is the asm instruction return value.
11419 sema.air_extra.appendAssumeCapacity(@enumToInt(Air.Inst.Ref.none));
11420 }
11421 sema.appendRefsAssumeCapacity(args);11415 sema.appendRefsAssumeCapacity(args);
11422 if (output) |o| {11416 for (outputs) |o| {
11423 const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());11417 const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());
11424 mem.copy(u8, buffer, o.constraint);11418 mem.copy(u8, buffer, o.c);
11425 buffer[o.constraint.len] = 0;11419 buffer[o.c.len] = 0;
11426 mem.copy(u8, buffer[o.constraint.len + 1 ..], o.name);11420 mem.copy(u8, buffer[o.c.len + 1 ..], o.n);
11427 buffer[o.constraint.len + 1 + o.name.len] = 0;11421 buffer[o.c.len + 1 + o.n.len] = 0;
11428 sema.air_extra.items.len += (o.constraint.len + o.name.len + (2 + 3)) / 4;11422 sema.air_extra.items.len += (o.c.len + o.n.len + (2 + 3)) / 4;
11429 }11423 }
11430 for (inputs) |input| {11424 for (inputs) |input| {
11431 const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());11425 const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());
src/codegen/llvm.zig+13-8
...@@ -5435,10 +5435,6 @@ pub const FuncGen = struct {...@@ -5435,10 +5435,6 @@ pub const FuncGen = struct {
5435 const inputs = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.inputs_len]);5435 const inputs = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.inputs_len]);
5436 extra_i += inputs.len;5436 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
5442 var llvm_constraints: std.ArrayListUnmanaged(u8) = .{};5438 var llvm_constraints: std.ArrayListUnmanaged(u8) = .{};
5443 defer llvm_constraints.deinit(self.gpa);5439 defer llvm_constraints.deinit(self.gpa);
54445440
...@@ -5446,7 +5442,10 @@ pub const FuncGen = struct {...@@ -5446,7 +5442,10 @@ pub const FuncGen = struct {
5446 defer arena_allocator.deinit();5442 defer arena_allocator.deinit();
5447 const arena = arena_allocator.allocator();5443 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;
5450 const llvm_param_types = try arena.alloc(*const llvm.Type, llvm_params_len);5449 const llvm_param_types = try arena.alloc(*const llvm.Type, llvm_params_len);
5451 const llvm_param_values = try arena.alloc(*const llvm.Value, llvm_params_len);5450 const llvm_param_values = try arena.alloc(*const llvm.Value, llvm_params_len);
5452 var llvm_param_i: usize = 0;5451 var llvm_param_i: usize = 0;
...@@ -5456,9 +5455,6 @@ pub const FuncGen = struct {...@@ -5456,9 +5455,6 @@ pub const FuncGen = struct {
5456 try name_map.ensureUnusedCapacity(arena, outputs.len + inputs.len);5455 try name_map.ensureUnusedCapacity(arena, outputs.len + inputs.len);
54575456
5458 for (outputs) |output| {5457 for (outputs) |output| {
5459 if (output != .none) {
5460 return self.todo("implement inline asm with non-returned output", .{});
5461 }
5462 const extra_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);5458 const extra_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
5463 const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0);5459 const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0);
5464 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);5460 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
...@@ -5471,6 +5467,15 @@ pub const FuncGen = struct {...@@ -5471,6 +5467,15 @@ pub const FuncGen = struct {
5471 llvm_constraints.appendAssumeCapacity(',');5467 llvm_constraints.appendAssumeCapacity(',');
5472 }5468 }
5473 llvm_constraints.appendAssumeCapacity('=');5469 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 }
5474 llvm_constraints.appendSliceAssumeCapacity(constraint[1..]);5479 llvm_constraints.appendSliceAssumeCapacity(constraint[1..]);
54755480
5476 name_map.putAssumeCapacityNoClobber(name, {});5481 name_map.putAssumeCapacityNoClobber(name, {});