| author | |
| committer | |
| log | fbd7e4506f46b73e351e1f3eb5e7cfc16ebbfc1f |
| tree | 574527e8cba0bc39eb18b722ef6a4221528215c8 |
| parent | e4c0b848a46347fccced787488605ac66e83c38a |
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 | } |
| 11336 | 11336 | ||
| 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; |
| 11344 | 11340 | ||
| 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; |
| 11353 | 11349 | ||
| 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; |
| 11356 | 11352 | ||
| 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 | } |
| 11360 | 11361 | ||
| 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; |
| 11364 | 11365 | ||
| 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 | }; | ||
| 11371 | 11368 | ||
| 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); |
| 11374 | 11371 | ||
| 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; |
| 5437 | 5437 | ||
| 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); |
| 5444 | 5440 | ||
| ... | @@ -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(); |
| 5448 | 5444 | ||
| 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); |
| 5457 | 5456 | ||
| 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..]); |
| 5475 | 5480 | ||
| 5476 | name_map.putAssumeCapacityNoClobber(name, {}); | 5481 | name_map.putAssumeCapacityNoClobber(name, {}); |