Commit a1486e1e1e
Changed files (4)
src/AstGen.zig
@@ -7194,21 +7194,19 @@ fn asmExpr(
const node_tags = tree.nodes.items(.tag);
const token_tags = tree.tokens.items(.tag);
- const asm_source = switch (node_tags[full.ast.template]) {
- .string_literal => try astgen.strLitAsString(main_tokens[full.ast.template]),
- .multiline_string_literal => try astgen.strLitNodeAsString(full.ast.template),
- else => blk: {
- // stage1 allows this, and until we do another design iteration on inline assembly
- // in stage2 to improve support for the various needed use cases, we allow inline
- // assembly templates to be an expression. Once stage2 addresses the real world needs
- // of people using inline assembly (primarily OS developers) then we can re-institute
- // the rule into AstGen that assembly code must use string literal syntax.
- //return astgen.failNode(full.ast.template, "assembly code must use string literal syntax", .{}),
- // We still need to trigger all the expr() calls here to avoid errors for unused things.
- // So we pass 0 as the asm source and stage2 Sema will notice this and
- // report the error.
- _ = try comptimeExpr(gz, scope, .none, full.ast.template);
- break :blk IndexSlice{ .index = 0, .len = 0 };
+ const TagAndTmpl = struct { tag: Zir.Inst.Extended, tmpl: u32 };
+ const tag_and_tmpl: TagAndTmpl = switch (node_tags[full.ast.template]) {
+ .string_literal => .{
+ .tag = .@"asm",
+ .tmpl = (try astgen.strLitAsString(main_tokens[full.ast.template])).index,
+ },
+ .multiline_string_literal => .{
+ .tag = .@"asm",
+ .tmpl = (try astgen.strLitNodeAsString(full.ast.template)).index,
+ },
+ else => .{
+ .tag = .asm_expr,
+ .tmpl = @enumToInt(try comptimeExpr(gz, scope, .none, full.ast.template)),
},
};
@@ -7312,8 +7310,9 @@ fn asmExpr(
}
const result = try gz.addAsm(.{
+ .tag = tag_and_tmpl.tag,
.node = node,
- .asm_source = asm_source.index,
+ .asm_source = tag_and_tmpl.tmpl,
.is_volatile = full.volatile_token != null,
.output_type_bits = output_type_bits,
.outputs = outputs,
@@ -11314,6 +11313,7 @@ const GenZir = struct {
fn addAsm(
gz: *GenZir,
args: struct {
+ tag: Zir.Inst.Extended,
/// Absolute node index. This function does the conversion to offset from Decl.
node: Ast.Node.Index,
asm_source: u32,
@@ -11360,7 +11360,7 @@ const GenZir = struct {
astgen.instructions.appendAssumeCapacity(.{
.tag = .extended,
.data = .{ .extended = .{
- .opcode = .@"asm",
+ .opcode = args.tag,
.small = small,
.operand = payload_index,
} },
src/print_zir.zig
@@ -469,7 +469,8 @@ const Writer = struct {
try stream.print(":{d}:{d}", .{ inst_data.line + 1, inst_data.column + 1 });
},
- .@"asm" => try self.writeAsm(stream, extended),
+ .@"asm" => try self.writeAsm(stream, extended, false),
+ .asm_expr => try self.writeAsm(stream, extended, true),
.variable => try self.writeVarExtended(stream, extended),
.alloc => try self.writeAllocExtended(stream, extended),
@@ -1062,17 +1063,27 @@ const Writer = struct {
try self.writeSrc(stream, inst_data.src());
}
- fn writeAsm(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
+ fn writeAsm(
+ self: *Writer,
+ stream: anytype,
+ extended: Zir.Inst.Extended.InstData,
+ tmpl_is_expr: bool,
+ ) !void {
const extra = self.code.extraData(Zir.Inst.Asm, extended.operand);
const src = LazySrcLoc.nodeOffset(extra.data.src_node);
const outputs_len = @truncate(u5, extended.small);
const inputs_len = @truncate(u5, extended.small >> 5);
const clobbers_len = @truncate(u5, extended.small >> 10);
const is_volatile = @truncate(u1, extended.small >> 15) != 0;
- const asm_source = self.code.nullTerminatedString(extra.data.asm_source);
try self.writeFlag(stream, "volatile, ", is_volatile);
- try stream.print("\"{}\", ", .{std.zig.fmtEscapes(asm_source)});
+ if (tmpl_is_expr) {
+ try self.writeInstRef(stream, @intToEnum(Zir.Inst.Ref, extra.data.asm_source));
+ try stream.writeAll(", ");
+ } else {
+ const asm_source = self.code.nullTerminatedString(extra.data.asm_source);
+ try stream.print("\"{}\", ", .{std.zig.fmtEscapes(asm_source)});
+ }
try stream.writeAll(", ");
var extra_i: usize = extra.end;
src/Sema.zig
@@ -953,7 +953,8 @@ fn analyzeBodyInner(
.frame_address => try sema.zirFrameAddress( block, extended),
.alloc => try sema.zirAllocExtended( block, extended),
.builtin_extern => try sema.zirBuiltinExtern( block, extended),
- .@"asm" => try sema.zirAsm( block, extended),
+ .@"asm" => try sema.zirAsm( block, extended, false),
+ .asm_expr => try sema.zirAsm( block, extended, true),
.typeof_peer => try sema.zirTypeofPeer( block, extended),
.compile_log => try sema.zirCompileLog( block, extended),
.add_with_overflow => try sema.zirOverflowArithmetic(block, extended, extended.opcode),
@@ -13846,6 +13847,7 @@ fn zirAsm(
sema: *Sema,
block: *Block,
extended: Zir.Inst.Extended.InstData,
+ tmpl_is_expr: bool,
) CompileError!Air.Inst.Ref {
const tracy = trace(@src());
defer tracy.end();
@@ -13859,13 +13861,11 @@ fn zirAsm(
const is_volatile = @truncate(u1, extended.small >> 15) != 0;
const is_global_assembly = sema.func == null;
- if (extra.data.asm_source == 0) {
- // This can move to become an AstGen error after inline assembly improvements land
- // and stage1 code matches stage2 code.
- return sema.fail(block, src, "assembly code must use string literal syntax", .{});
- }
-
- const asm_source = sema.code.nullTerminatedString(extra.data.asm_source);
+ const asm_source: []const u8 = if (tmpl_is_expr) blk: {
+ const tmpl = @intToEnum(Zir.Inst.Ref, extra.data.asm_source);
+ const s: []const u8 = try sema.resolveConstString(block, src, tmpl, "assembly code must be comptime-known");
+ break :blk s;
+ } else sema.code.nullTerminatedString(extra.data.asm_source);
if (is_global_assembly) {
if (outputs_len != 0) {
src/Zir.zig
@@ -1883,6 +1883,11 @@ pub const Inst = struct {
/// * 0bX0000000_00000000 - is volatile
/// `operand` is payload index to `Asm`.
@"asm",
+ /// Same as `asm` except the assembly template is not a string literal but a comptime
+ /// expression.
+ /// The `asm_source` field of the Asm is not a null-terminated string
+ /// but instead a Ref.
+ asm_expr,
/// Log compile time variables and emit an error message.
/// `operand` is payload index to `NodeMultiOp`.
/// `small` is `operands_len`.