mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +00:00
Merge 717ac0d5ce into 9082b004b6
This commit is contained in:
commit
2815674c08
6 changed files with 87 additions and 35 deletions
|
|
@ -13010,9 +13010,9 @@ const GenZir = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
const small: Zir.Inst.Asm.Small = .{
|
const small: Zir.Inst.Asm.Small = .{
|
||||||
|
.is_volatile = args.is_volatile,
|
||||||
.outputs_len = @intCast(args.outputs.len),
|
.outputs_len = @intCast(args.outputs.len),
|
||||||
.inputs_len = @intCast(args.inputs.len),
|
.inputs_len = @intCast(args.inputs.len),
|
||||||
.is_volatile = args.is_volatile,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const new_index: Zir.Inst.Index = @enumFromInt(astgen.instructions.len);
|
const new_index: Zir.Inst.Index = @enumFromInt(astgen.instructions.len);
|
||||||
|
|
|
||||||
29
src/Sema.zig
29
src/Sema.zig
|
|
@ -16385,6 +16385,7 @@ fn zirAsm(
|
||||||
|
|
||||||
const pt = sema.pt;
|
const pt = sema.pt;
|
||||||
const zcu = pt.zcu;
|
const zcu = pt.zcu;
|
||||||
|
const ip = &zcu.intern_pool;
|
||||||
const extra = sema.code.extraData(Zir.Inst.Asm, extended.operand);
|
const extra = sema.code.extraData(Zir.Inst.Asm, extended.operand);
|
||||||
const src = block.nodeOffset(extra.data.src_node);
|
const src = block.nodeOffset(extra.data.src_node);
|
||||||
const ret_ty_src = block.src(.{ .node_offset_asm_ret_ty = extra.data.src_node });
|
const ret_ty_src = block.src(.{ .node_offset_asm_ret_ty = extra.data.src_node });
|
||||||
|
|
@ -16423,28 +16424,38 @@ fn zirAsm(
|
||||||
|
|
||||||
for (out_args, 0..) |*arg, out_i| {
|
for (out_args, 0..) |*arg, out_i| {
|
||||||
const output = sema.code.extraData(Zir.Inst.Asm.Output, extra_i);
|
const output = sema.code.extraData(Zir.Inst.Asm.Output, extra_i);
|
||||||
|
const output_src = block.src(.{ .asm_output = .{
|
||||||
|
.offset = src.offset.node_offset.x,
|
||||||
|
.output_index = @intCast(out_i),
|
||||||
|
} });
|
||||||
extra_i = output.end;
|
extra_i = output.end;
|
||||||
|
|
||||||
const is_type = @as(u1, @truncate(output_type_bits)) != 0;
|
const is_type = @as(u1, @truncate(output_type_bits)) != 0;
|
||||||
output_type_bits >>= 1;
|
output_type_bits >>= 1;
|
||||||
|
|
||||||
|
const name = sema.code.nullTerminatedString(output.data.name);
|
||||||
|
|
||||||
if (is_type) {
|
if (is_type) {
|
||||||
// Indicate the output is the asm instruction return value.
|
// Indicate the output is the asm instruction return value.
|
||||||
arg.* = .none;
|
arg.* = .none;
|
||||||
const out_ty = try sema.resolveType(block, ret_ty_src, output.data.operand);
|
const out_ty = try sema.resolveType(block, ret_ty_src, output.data.operand);
|
||||||
expr_ty = Air.internedToRef(out_ty.toIntern());
|
expr_ty = Air.internedToRef(out_ty.toIntern());
|
||||||
} else {
|
} else {
|
||||||
arg.* = try sema.resolveInst(output.data.operand);
|
const inst = try sema.resolveInst(output.data.operand);
|
||||||
|
if (!sema.checkRuntimeValue(inst)) {
|
||||||
|
const output_name = try ip.getOrPutString(sema.gpa, pt.tid, name, .no_embedded_nulls);
|
||||||
|
return sema.failWithContainsReferenceToComptimeVar(block, output_src, output_name, "assembly output", .fromInterned(inst.toInterned().?));
|
||||||
|
}
|
||||||
|
arg.* = inst;
|
||||||
}
|
}
|
||||||
|
|
||||||
const constraint = sema.code.nullTerminatedString(output.data.constraint);
|
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;
|
needed_capacity += (constraint.len + name.len + (2 + 3)) / 4;
|
||||||
|
|
||||||
if (output.data.operand.toIndex()) |index| {
|
if (output.data.operand.toIndex()) |index| {
|
||||||
if (zir_tags[@intFromEnum(index)] == .ref) {
|
if (zir_tags[@intFromEnum(index)] == .ref) {
|
||||||
// TODO: better error location; it would be even nicer if there were notes that pointed at the output and the variable definition
|
// TODO: it would be even nicer if there were notes that pointed at the variable definition
|
||||||
return sema.fail(block, src, "asm cannot output to const local '{s}'", .{name});
|
return sema.fail(block, output_src, "asm cannot output to const local '{s}'", .{name});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -16456,9 +16467,18 @@ fn zirAsm(
|
||||||
|
|
||||||
for (args, 0..) |*arg, arg_i| {
|
for (args, 0..) |*arg, arg_i| {
|
||||||
const input = sema.code.extraData(Zir.Inst.Asm.Input, extra_i);
|
const input = sema.code.extraData(Zir.Inst.Asm.Input, extra_i);
|
||||||
|
const input_src = block.src(.{ .asm_input = .{
|
||||||
|
.offset = src.offset.node_offset.x,
|
||||||
|
.input_index = @intCast(arg_i),
|
||||||
|
} });
|
||||||
extra_i = input.end;
|
extra_i = input.end;
|
||||||
|
|
||||||
const uncasted_arg = try sema.resolveInst(input.data.operand);
|
const uncasted_arg = try sema.resolveInst(input.data.operand);
|
||||||
|
const name = sema.code.nullTerminatedString(input.data.name);
|
||||||
|
if (!sema.checkRuntimeValue(uncasted_arg)) {
|
||||||
|
const input_name = try ip.getOrPutString(sema.gpa, pt.tid, name, .no_embedded_nulls);
|
||||||
|
return sema.failWithContainsReferenceToComptimeVar(block, input_src, input_name, "assembly input", .fromInterned(uncasted_arg.toInterned().?));
|
||||||
|
}
|
||||||
const uncasted_arg_ty = sema.typeOf(uncasted_arg);
|
const uncasted_arg_ty = sema.typeOf(uncasted_arg);
|
||||||
switch (uncasted_arg_ty.zigTypeTag(zcu)) {
|
switch (uncasted_arg_ty.zigTypeTag(zcu)) {
|
||||||
.comptime_int => arg.* = try sema.coerce(block, .usize, uncasted_arg, src),
|
.comptime_int => arg.* = try sema.coerce(block, .usize, uncasted_arg, src),
|
||||||
|
|
@ -16469,7 +16489,6 @@ fn zirAsm(
|
||||||
}
|
}
|
||||||
|
|
||||||
const constraint = sema.code.nullTerminatedString(input.data.constraint);
|
const constraint = sema.code.nullTerminatedString(input.data.constraint);
|
||||||
const name = sema.code.nullTerminatedString(input.data.name);
|
|
||||||
needed_capacity += (constraint.len + name.len + (2 + 3)) / 4;
|
needed_capacity += (constraint.len + name.len + (2 + 3)) / 4;
|
||||||
inputs[arg_i] = .{ .c = constraint, .n = name };
|
inputs[arg_i] = .{ .c = constraint, .n = name };
|
||||||
}
|
}
|
||||||
|
|
|
||||||
31
src/Zcu.zig
31
src/Zcu.zig
|
|
@ -1542,6 +1542,25 @@ pub const SrcLoc = struct {
|
||||||
};
|
};
|
||||||
return tree.nodeToSpan(src_node);
|
return tree.nodeToSpan(src_node);
|
||||||
},
|
},
|
||||||
|
.asm_input => |input| {
|
||||||
|
const tree = try src_loc.file_scope.getTree(zcu);
|
||||||
|
const node = input.offset.toAbsolute(src_loc.base_node);
|
||||||
|
const full = tree.fullAsm(node).?;
|
||||||
|
const asm_input = full.inputs[input.input_index];
|
||||||
|
return tree.nodeToSpan(tree.nodeData(asm_input).node_and_token[0]);
|
||||||
|
},
|
||||||
|
.asm_output => |output| {
|
||||||
|
const tree = try src_loc.file_scope.getTree(zcu);
|
||||||
|
const node = output.offset.toAbsolute(src_loc.base_node);
|
||||||
|
const full = tree.fullAsm(node).?;
|
||||||
|
const asm_output = full.outputs[output.output_index];
|
||||||
|
const data = tree.nodeData(asm_output).opt_node_and_token;
|
||||||
|
return if (data[0].unwrap()) |output_node|
|
||||||
|
tree.nodeToSpan(output_node)
|
||||||
|
else
|
||||||
|
// token points to the ')'
|
||||||
|
tree.tokenToSpan(data[1] - 1);
|
||||||
|
},
|
||||||
.for_input => |for_input| {
|
.for_input => |for_input| {
|
||||||
const tree = try src_loc.file_scope.getTree(zcu);
|
const tree = try src_loc.file_scope.getTree(zcu);
|
||||||
const node = for_input.for_node_offset.toAbsolute(src_loc.base_node);
|
const node = for_input.for_node_offset.toAbsolute(src_loc.base_node);
|
||||||
|
|
@ -2507,6 +2526,18 @@ pub const LazySrcLoc = struct {
|
||||||
/// The source location points to the operand of a `return` statement, or
|
/// The source location points to the operand of a `return` statement, or
|
||||||
/// the `return` itself if there is no explicit operand.
|
/// the `return` itself if there is no explicit operand.
|
||||||
node_offset_return_operand: Ast.Node.Offset,
|
node_offset_return_operand: Ast.Node.Offset,
|
||||||
|
/// The source location points to an assembly input
|
||||||
|
asm_input: struct {
|
||||||
|
/// Points to the assembly node
|
||||||
|
offset: Ast.Node.Offset,
|
||||||
|
input_index: u32,
|
||||||
|
},
|
||||||
|
/// The source location points to an assembly output
|
||||||
|
asm_output: struct {
|
||||||
|
/// Points to the assembly node
|
||||||
|
offset: Ast.Node.Offset,
|
||||||
|
output_index: u32,
|
||||||
|
},
|
||||||
/// The source location points to a for loop input.
|
/// The source location points to a for loop input.
|
||||||
for_input: struct {
|
for_input: struct {
|
||||||
/// Points to the for loop AST node.
|
/// Points to the for loop AST node.
|
||||||
|
|
|
||||||
|
|
@ -1267,18 +1267,14 @@ const Writer = struct {
|
||||||
tmpl_is_expr: bool,
|
tmpl_is_expr: bool,
|
||||||
) !void {
|
) !void {
|
||||||
const extra = self.code.extraData(Zir.Inst.Asm, extended.operand);
|
const extra = self.code.extraData(Zir.Inst.Asm, extended.operand);
|
||||||
const outputs_len = @as(u5, @truncate(extended.small));
|
const small: Zir.Inst.Asm.Small = @bitCast(extended.small);
|
||||||
const inputs_len = @as(u5, @truncate(extended.small >> 5));
|
|
||||||
const clobbers_len = @as(u5, @truncate(extended.small >> 10));
|
|
||||||
const is_volatile = @as(u1, @truncate(extended.small >> 15)) != 0;
|
|
||||||
|
|
||||||
try self.writeFlag(stream, "volatile, ", is_volatile);
|
try self.writeFlag(stream, "volatile, ", small.is_volatile);
|
||||||
if (tmpl_is_expr) {
|
if (tmpl_is_expr) {
|
||||||
try self.writeInstRef(stream, @enumFromInt(@intFromEnum(extra.data.asm_source)));
|
try self.writeInstRef(stream, @enumFromInt(@intFromEnum(extra.data.asm_source)));
|
||||||
try stream.writeAll(", ");
|
|
||||||
} else {
|
} else {
|
||||||
const asm_source = self.code.nullTerminatedString(extra.data.asm_source);
|
const asm_source = self.code.nullTerminatedString(extra.data.asm_source);
|
||||||
try stream.print("\"{f}\", ", .{std.zig.fmtString(asm_source)});
|
try stream.print("\"{f}\"", .{std.zig.fmtString(asm_source)});
|
||||||
}
|
}
|
||||||
try stream.writeAll(", ");
|
try stream.writeAll(", ");
|
||||||
|
|
||||||
|
|
@ -1286,7 +1282,7 @@ const Writer = struct {
|
||||||
var output_type_bits = extra.data.output_type_bits;
|
var output_type_bits = extra.data.output_type_bits;
|
||||||
{
|
{
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
while (i < outputs_len) : (i += 1) {
|
while (i < small.outputs_len) : (i += 1) {
|
||||||
const output = self.code.extraData(Zir.Inst.Asm.Output, extra_i);
|
const output = self.code.extraData(Zir.Inst.Asm.Output, extra_i);
|
||||||
extra_i = output.end;
|
extra_i = output.end;
|
||||||
|
|
||||||
|
|
@ -1298,17 +1294,14 @@ const Writer = struct {
|
||||||
try stream.print("output({f}, \"{f}\", ", .{
|
try stream.print("output({f}, \"{f}\", ", .{
|
||||||
std.zig.fmtIdP(name), std.zig.fmtString(constraint),
|
std.zig.fmtIdP(name), std.zig.fmtString(constraint),
|
||||||
});
|
});
|
||||||
try self.writeFlag(stream, "->", is_type);
|
try self.writeFlag(stream, "-> ", is_type);
|
||||||
try self.writeInstRef(stream, output.data.operand);
|
try self.writeInstRef(stream, output.data.operand);
|
||||||
try stream.writeAll(")");
|
try stream.writeAll("), ");
|
||||||
if (i + 1 < outputs_len) {
|
|
||||||
try stream.writeAll("), ");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
while (i < inputs_len) : (i += 1) {
|
while (i < small.inputs_len) : (i += 1) {
|
||||||
const input = self.code.extraData(Zir.Inst.Asm.Input, extra_i);
|
const input = self.code.extraData(Zir.Inst.Asm.Input, extra_i);
|
||||||
extra_i = input.end;
|
extra_i = input.end;
|
||||||
|
|
||||||
|
|
@ -1318,23 +1311,11 @@ const Writer = struct {
|
||||||
std.zig.fmtIdP(name), std.zig.fmtString(constraint),
|
std.zig.fmtIdP(name), std.zig.fmtString(constraint),
|
||||||
});
|
});
|
||||||
try self.writeInstRef(stream, input.data.operand);
|
try self.writeInstRef(stream, input.data.operand);
|
||||||
try stream.writeAll(")");
|
try stream.writeAll("), ");
|
||||||
if (i + 1 < inputs_len) {
|
|
||||||
try stream.writeAll(", ");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
var i: usize = 0;
|
try self.writeInstRef(stream, extra.data.clobbers);
|
||||||
while (i < clobbers_len) : (i += 1) {
|
|
||||||
const str_index = self.code.extra[extra_i];
|
|
||||||
extra_i += 1;
|
|
||||||
const clobber = self.code.nullTerminatedString(@enumFromInt(str_index));
|
|
||||||
try stream.print("{f}", .{std.zig.fmtIdP(clobber)});
|
|
||||||
if (i + 1 < clobbers_len) {
|
|
||||||
try stream.writeAll(", ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
try stream.writeAll(")) ");
|
try stream.writeAll(")) ");
|
||||||
try self.writeSrcNode(stream, extra.data.src_node);
|
try self.writeSrcNode(stream, extra.data.src_node);
|
||||||
|
|
|
||||||
|
|
@ -9,4 +9,4 @@ export fn foo() void {
|
||||||
|
|
||||||
// error
|
// error
|
||||||
//
|
//
|
||||||
// :4:5: error: asm cannot output to const local 'f'
|
// :6:21: error: asm cannot output to const local 'f'
|
||||||
|
|
|
||||||
21
test/cases/compile_errors/comptime_var_referenced_by_asm.zig
Normal file
21
test/cases/compile_errors/comptime_var_referenced_by_asm.zig
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
export fn foo() void {
|
||||||
|
comptime var a: u32 = 0;
|
||||||
|
_ = asm volatile (""
|
||||||
|
:
|
||||||
|
: [in] "r" (&a),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn bar() void {
|
||||||
|
comptime var a: u32 = 0;
|
||||||
|
_ = asm volatile (""
|
||||||
|
: [out] "=r" (a),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
//
|
||||||
|
// :5:21: error: assembly input contains reference to comptime var
|
||||||
|
// :2:14: note: 'in' points to comptime var declared here
|
||||||
|
// :12:23: error: assembly output contains reference to comptime var
|
||||||
|
// :10:14: note: 'out' points to comptime var declared here
|
||||||
Loading…
Add table
Reference in a new issue