aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-04-23 18:28:46 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-04-23 18:35:21 -0700
commitb40a8efb9a72e69cd7e9061fc4c08d5e705b0fbd (patch)
treeb62377262318b6f6d76a0b75d43dff106e553a2f
parent183ee0965fac6322651666834776d9832cc95ddd (diff)
downloadzig-b40a8efb9a72e69cd7e9061fc4c08d5e705b0fbd.tar.gz
zig-b40a8efb9a72e69cd7e9061fc4c08d5e705b0fbd.zip
stage2: implement `anyframe`, `anyframe->T` and fix assembly
* AstGen: implement `anyframe_literal` and `anyframe_type`. * Introduce `makeSubBlock` to avoid redundant AstGen code for GenZir scopes. Allows adding/removing a field without possibility of accidentally introducing a bug of forgetting to set the new field. * Add to GenZir `nosuspend_node` and `suspend_node` in preparation for implementing `suspend` blocks and `nosuspend` blocks. * AstGen: fix assembly to support clobbers, multiple outputs, and outputs without `->` syntax. - `asm` and `asm_volatile` move to `Extended` enum with `small` being repurposed for a few things. This frees up 2 ZIR tags, 1 of which is used in this commit and 1 is leftover. * AstGen: fix `simple_types` incorrectly having multiple conflicting values for "undefined" and "null". - Also add "anyframe" to `simple_types`. * Add `anyframe_type` to type.zig, value.zig and `Zir.Inst.Ref`. - Also add i128 and u128 types to `Zir.Inst.Ref` and `simple_types`. * Sema/Zir: Fix incorrect math causing the function body to be messed up for Extended-encoded functions. * Zir: support `i32` fields for "extra" payloads.
-rw-r--r--src/AstGen.zig418
-rw-r--r--src/Module.zig97
-rw-r--r--src/Sema.zig85
-rw-r--r--src/Zir.zig210
-rw-r--r--src/type.zig44
-rw-r--r--src/value.zig23
6 files changed, 513 insertions, 364 deletions
diff --git a/src/AstGen.zig b/src/AstGen.zig
index 9b957a8d4f..7e3eff48ea 100644
--- a/src/AstGen.zig
+++ b/src/AstGen.zig
@@ -723,8 +723,12 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn
},
.enum_literal => return simpleStrTok(gz, scope, rl, main_tokens[node], node, .enum_literal),
.error_value => return simpleStrTok(gz, scope, rl, node_datas[node].rhs, node, .error_value),
- .anyframe_literal => return astgen.failNode(node, "async and related features are not yet supported", .{}),
- .anyframe_type => return astgen.failNode(node, "async and related features are not yet supported", .{}),
+ .anyframe_literal => return rvalue(gz, scope, rl, .anyframe_type, node),
+ .anyframe_type => {
+ const return_type = try typeExpr(gz, scope, node_datas[node].rhs);
+ const result = try gz.addUnNode(.anyframe_type, return_type, node);
+ return rvalue(gz, scope, rl, result, node);
+ },
.@"catch" => {
const catch_token = main_tokens[node];
const payload_token: ?ast.TokenIndex = if (token_tags[catch_token + 1] == .pipe)
@@ -1546,18 +1550,10 @@ fn labeledBlockExpr(
const block_inst = try gz.addBlock(zir_tag, block_node);
try gz.instructions.append(astgen.gpa, block_inst);
- var block_scope: GenZir = .{
- .parent = parent_scope,
- .decl_node_index = gz.decl_node_index,
- .astgen = gz.astgen,
- .force_comptime = gz.force_comptime,
- .ref_start_index = gz.ref_start_index,
- .instructions = .{},
- // TODO @as here is working around a stage1 miscompilation bug :(
- .label = @as(?GenZir.Label, GenZir.Label{
- .token = label_token,
- .block_inst = block_inst,
- }),
+ var block_scope = gz.makeSubBlock(parent_scope);
+ block_scope.label = GenZir.Label{
+ .token = label_token,
+ .block_inst = block_inst,
};
block_scope.setBreakResultLoc(rl);
defer block_scope.instructions.deinit(astgen.gpa);
@@ -1695,10 +1691,9 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner
.array_type_sentinel,
.elem_type,
.indexable_ptr_len,
+ .anyframe_type,
.as,
.as_node,
- .@"asm",
- .asm_volatile,
.bit_and,
.bitcast,
.bitcast_result_ptr,
@@ -2095,13 +2090,7 @@ fn varDecl(
// Detect whether the initialization expression actually uses the
// result location pointer.
- var init_scope: GenZir = .{
- .parent = scope,
- .decl_node_index = gz.decl_node_index,
- .force_comptime = gz.force_comptime,
- .ref_start_index = gz.ref_start_index,
- .astgen = astgen,
- };
+ var init_scope = gz.makeSubBlock(scope);
defer init_scope.instructions.deinit(gpa);
var resolve_inferred_alloc: Zir.Inst.Ref = .none;
@@ -3778,14 +3767,7 @@ fn tryExpr(
return astgen.failNode(node, "invalid 'try' outside function scope", .{});
};
- var block_scope: GenZir = .{
- .parent = scope,
- .decl_node_index = parent_gz.decl_node_index,
- .astgen = astgen,
- .force_comptime = parent_gz.force_comptime,
- .ref_start_index = parent_gz.ref_start_index,
- .instructions = .{},
- };
+ var block_scope = parent_gz.makeSubBlock(scope);
block_scope.setBreakResultLoc(rl);
defer block_scope.instructions.deinit(astgen.gpa);
@@ -3811,28 +3793,14 @@ fn tryExpr(
try parent_gz.instructions.append(astgen.gpa, block);
try block_scope.setBlockBody(block);
- var then_scope: GenZir = .{
- .parent = scope,
- .decl_node_index = parent_gz.decl_node_index,
- .astgen = astgen,
- .force_comptime = block_scope.force_comptime,
- .ref_start_index = parent_gz.ref_start_index,
- .instructions = .{},
- };
+ var then_scope = parent_gz.makeSubBlock(scope);
defer then_scope.instructions.deinit(astgen.gpa);
const err_code = try then_scope.addUnNode(err_ops[1], operand, node);
try genDefers(&then_scope, &fn_block.base, scope, err_code);
const then_result = try then_scope.addUnNode(.ret_node, err_code, node);
- var else_scope: GenZir = .{
- .parent = scope,
- .decl_node_index = parent_gz.decl_node_index,
- .astgen = astgen,
- .force_comptime = block_scope.force_comptime,
- .ref_start_index = parent_gz.ref_start_index,
- .instructions = .{},
- };
+ var else_scope = parent_gz.makeSubBlock(scope);
defer else_scope.instructions.deinit(astgen.gpa);
block_scope.break_count += 1;
@@ -3878,14 +3846,7 @@ fn orelseCatchExpr(
const astgen = parent_gz.astgen;
const tree = &astgen.file.tree;
- var block_scope: GenZir = .{
- .parent = scope,
- .decl_node_index = parent_gz.decl_node_index,
- .astgen = astgen,
- .force_comptime = parent_gz.force_comptime,
- .ref_start_index = parent_gz.ref_start_index,
- .instructions = .{},
- };
+ var block_scope = parent_gz.makeSubBlock(scope);
block_scope.setBreakResultLoc(rl);
defer block_scope.instructions.deinit(astgen.gpa);
@@ -3906,14 +3867,7 @@ fn orelseCatchExpr(
try parent_gz.instructions.append(astgen.gpa, block);
try block_scope.setBlockBody(block);
- var then_scope: GenZir = .{
- .parent = scope,
- .decl_node_index = parent_gz.decl_node_index,
- .astgen = astgen,
- .force_comptime = block_scope.force_comptime,
- .ref_start_index = parent_gz.ref_start_index,
- .instructions = .{},
- };
+ var then_scope = parent_gz.makeSubBlock(scope);
defer then_scope.instructions.deinit(astgen.gpa);
var err_val_scope: Scope.LocalVal = undefined;
@@ -3939,14 +3893,7 @@ fn orelseCatchExpr(
// instructions into place until we know whether to keep store_to_block_ptr
// instructions or not.
- var else_scope: GenZir = .{
- .parent = scope,
- .decl_node_index = parent_gz.decl_node_index,
- .astgen = astgen,
- .force_comptime = block_scope.force_comptime,
- .ref_start_index = parent_gz.ref_start_index,
- .instructions = .{},
- };
+ var else_scope = parent_gz.makeSubBlock(scope);
defer else_scope.instructions.deinit(astgen.gpa);
// This could be a pointer or value depending on `unwrap_op`.
@@ -4140,13 +4087,7 @@ fn boolBinOp(
const lhs = try expr(gz, scope, bool_rl, node_datas[node].lhs);
const bool_br = try gz.addBoolBr(zir_tag, lhs);
- var rhs_scope: GenZir = .{
- .parent = scope,
- .decl_node_index = gz.decl_node_index,
- .astgen = gz.astgen,
- .force_comptime = gz.force_comptime,
- .ref_start_index = gz.ref_start_index,
- };
+ var rhs_scope = gz.makeSubBlock(scope);
defer rhs_scope.instructions.deinit(gz.astgen.gpa);
const rhs = try expr(&rhs_scope, &rhs_scope.base, bool_rl, node_datas[node].rhs);
_ = try rhs_scope.addBreak(.break_inline, bool_br, rhs);
@@ -4167,14 +4108,7 @@ fn ifExpr(
const tree = &astgen.file.tree;
const token_tags = tree.tokens.items(.tag);
- var block_scope: GenZir = .{
- .parent = scope,
- .decl_node_index = parent_gz.decl_node_index,
- .astgen = astgen,
- .force_comptime = parent_gz.force_comptime,
- .ref_start_index = parent_gz.ref_start_index,
- .instructions = .{},
- };
+ var block_scope = parent_gz.makeSubBlock(scope);
block_scope.setBreakResultLoc(rl);
defer block_scope.instructions.deinit(astgen.gpa);
@@ -4218,14 +4152,7 @@ fn ifExpr(
try parent_gz.instructions.append(astgen.gpa, block);
try block_scope.setBlockBody(block);
- var then_scope: GenZir = .{
- .parent = scope,
- .decl_node_index = parent_gz.decl_node_index,
- .astgen = astgen,
- .force_comptime = block_scope.force_comptime,
- .ref_start_index = parent_gz.ref_start_index,
- .instructions = .{},
- };
+ var then_scope = parent_gz.makeSubBlock(scope);
defer then_scope.instructions.deinit(astgen.gpa);
var payload_val_scope: Scope.LocalVal = undefined;
@@ -4273,14 +4200,7 @@ fn ifExpr(
// instructions into place until we know whether to keep store_to_block_ptr
// instructions or not.
- var else_scope: GenZir = .{
- .parent = scope,
- .decl_node_index = parent_gz.decl_node_index,
- .astgen = astgen,
- .force_comptime = block_scope.force_comptime,
- .ref_start_index = parent_gz.ref_start_index,
- .instructions = .{},
- };
+ var else_scope = parent_gz.makeSubBlock(scope);
defer else_scope.instructions.deinit(astgen.gpa);
const else_node = if_full.ast.else_expr;
@@ -4424,25 +4344,11 @@ fn whileExpr(
const loop_block = try parent_gz.addBlock(loop_tag, node);
try parent_gz.instructions.append(astgen.gpa, loop_block);
- var loop_scope: GenZir = .{
- .parent = scope,
- .decl_node_index = parent_gz.decl_node_index,
- .astgen = astgen,
- .force_comptime = parent_gz.force_comptime,
- .ref_start_index = parent_gz.ref_start_index,
- .instructions = .{},
- };
+ var loop_scope = parent_gz.makeSubBlock(scope);
loop_scope.setBreakResultLoc(rl);
defer loop_scope.instructions.deinit(astgen.gpa);
- var continue_scope: GenZir = .{
- .parent = &loop_scope.base,
- .decl_node_index = parent_gz.decl_node_index,
- .astgen = astgen,
- .force_comptime = loop_scope.force_comptime,
- .ref_start_index = parent_gz.ref_start_index,
- .instructions = .{},
- };
+ var continue_scope = parent_gz.makeSubBlock(&loop_scope.base);
defer continue_scope.instructions.deinit(astgen.gpa);
const payload_is_ref = if (while_full.payload_token) |payload_token|
@@ -4505,14 +4411,7 @@ fn whileExpr(
});
}
- var then_scope: GenZir = .{
- .parent = &continue_scope.base,
- .decl_node_index = parent_gz.decl_node_index,
- .astgen = astgen,
- .force_comptime = continue_scope.force_comptime,
- .ref_start_index = parent_gz.ref_start_index,
- .instructions = .{},
- };
+ var then_scope = parent_gz.makeSubBlock(&continue_scope.base);
defer then_scope.instructions.deinit(astgen.gpa);
var payload_val_scope: Scope.LocalVal = undefined;
@@ -4557,14 +4456,7 @@ fn whileExpr(
loop_scope.break_count += 1;
const then_result = try expr(&then_scope, then_sub_scope, loop_scope.break_result_loc, while_full.ast.then_expr);
- var else_scope: GenZir = .{
- .parent = &continue_scope.base,
- .decl_node_index = parent_gz.decl_node_index,
- .astgen = astgen,
- .force_comptime = continue_scope.force_comptime,
- .ref_start_index = parent_gz.ref_start_index,
- .instructions = .{},
- };
+ var else_scope = parent_gz.makeSubBlock(&continue_scope.base);
defer else_scope.instructions.deinit(astgen.gpa);
const else_node = while_full.ast.else_expr;
@@ -4659,25 +4551,11 @@ fn forExpr(
const loop_block = try parent_gz.addBlock(loop_tag, node);
try parent_gz.instructions.append(astgen.gpa, loop_block);
- var loop_scope: GenZir = .{
- .parent = scope,
- .decl_node_index = parent_gz.decl_node_index,
- .astgen = astgen,
- .force_comptime = parent_gz.force_comptime,
- .ref_start_index = parent_gz.ref_start_index,
- .instructions = .{},
- };
+ var loop_scope = parent_gz.makeSubBlock(scope);
loop_scope.setBreakResultLoc(rl);
defer loop_scope.instructions.deinit(astgen.gpa);
- var cond_scope: GenZir = .{
- .parent = &loop_scope.base,
- .decl_node_index = parent_gz.decl_node_index,
- .astgen = astgen,
- .force_comptime = loop_scope.force_comptime,
- .ref_start_index = parent_gz.ref_start_index,
- .instructions = .{},
- };
+ var cond_scope = parent_gz.makeSubBlock(&loop_scope.base);
defer cond_scope.instructions.deinit(astgen.gpa);
// check condition i < array_expr.len
@@ -4714,14 +4592,7 @@ fn forExpr(
});
}
- var then_scope: GenZir = .{
- .parent = &cond_scope.base,
- .decl_node_index = parent_gz.decl_node_index,
- .astgen = astgen,
- .force_comptime = cond_scope.force_comptime,
- .ref_start_index = parent_gz.ref_start_index,
- .instructions = .{},
- };
+ var then_scope = parent_gz.makeSubBlock(&cond_scope.base);
defer then_scope.instructions.deinit(astgen.gpa);
var payload_val_scope: Scope.LocalVal = undefined;
@@ -4773,14 +4644,7 @@ fn forExpr(
loop_scope.break_count += 1;
const then_result = try expr(&then_scope, then_sub_scope, loop_scope.break_result_loc, for_full.ast.then_expr);
- var else_scope: GenZir = .{
- .parent = &cond_scope.base,
- .decl_node_index = parent_gz.decl_node_index,
- .astgen = astgen,
- .force_comptime = cond_scope.force_comptime,
- .ref_start_index = parent_gz.ref_start_index,
- .instructions = .{},
- };
+ var else_scope = parent_gz.makeSubBlock(&cond_scope.base);
defer else_scope.instructions.deinit(astgen.gpa);
const else_node = for_full.ast.else_expr;
@@ -5076,14 +4940,7 @@ fn switchExpr(
var multi_cases_payload = ArrayListUnmanaged(u32){};
defer multi_cases_payload.deinit(gpa);
- var block_scope: GenZir = .{
- .parent = scope,
- .decl_node_index = parent_gz.decl_node_index,
- .astgen = astgen,
- .force_comptime = parent_gz.force_comptime,
- .ref_start_index = parent_gz.ref_start_index,
- .instructions = .{},
- };
+ var block_scope = parent_gz.makeSubBlock(scope);
block_scope.setBreakResultLoc(rl);
defer block_scope.instructions.deinit(gpa);
@@ -5091,14 +4948,7 @@ fn switchExpr(
const switch_block = try parent_gz.addBlock(undefined, switch_node);
// We re-use this same scope for all cases, including the special prong, if any.
- var case_scope: GenZir = .{
- .parent = &block_scope.base,
- .decl_node_index = parent_gz.decl_node_index,
- .astgen = astgen,
- .force_comptime = parent_gz.force_comptime,
- .ref_start_index = parent_gz.ref_start_index,
- .instructions = .{},
- };
+ var case_scope = parent_gz.makeSubBlock(&block_scope.base);
defer case_scope.instructions.deinit(gpa);
// Do the else/`_` first because it goes first in the payload.
@@ -5846,57 +5696,109 @@ fn asmExpr(
const tree = &astgen.file.tree;
const main_tokens = tree.nodes.items(.main_token);
const node_datas = tree.nodes.items(.data);
+ const token_tags = tree.tokens.items(.tag);
const asm_source = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, full.ast.template);
// See https://github.com/ziglang/zig/issues/215 and related issues discussing
- // possible inline assembly improvements. Until this is settled, I am avoiding
- // potentially wasting time implementing status quo assembly that is not used by
- // any of the standard library.
- if (full.outputs.len > 1) {
- return astgen.failNode(node, "TODO more than 1 asm output", .{});
+ // possible inline assembly improvements. Until then here is status quo AstGen
+ // for assembly syntax. It's used by std lib crypto aesni.zig.
+
+ if (full.outputs.len > 32) {
+ return astgen.failNode(full.outputs[32], "too many asm outputs", .{});
}
- const output: struct {
- ty: Zir.Inst.Ref = .none,
- constraint: u32 = 0,
- } = if (full.outputs.len == 0) .{} else blk: {
- const output_node = full.outputs[0];
- const out_type_node = node_datas[output_node].lhs;
- if (out_type_node == 0) {
- return astgen.failNode(out_type_node, "TODO asm with non -> output", .{});
+ var outputs_buffer: [32]Zir.Inst.Asm.Output = undefined;
+ const outputs = outputs_buffer[0..full.outputs.len];
+
+ var output_type_bits: u32 = 0;
+
+ for (full.outputs) |output_node, i| {
+ const symbolic_name = main_tokens[output_node];
+ const name = try gz.identAsString(symbolic_name);
+ const constraint_token = symbolic_name + 2;
+ const constraint = (try gz.strLitAsString(constraint_token)).index;
+ const has_arrow = token_tags[symbolic_name + 4] == .arrow;
+ if (has_arrow) {
+ output_type_bits |= @as(u32, 1) << @intCast(u5, i);
+ const out_type_node = node_datas[output_node].lhs;
+ const out_type_inst = try typeExpr(gz, scope, out_type_node);
+ outputs[i] = .{
+ .name = name,
+ .constraint = constraint,
+ .operand = out_type_inst,
+ };
+ } else {
+ const ident_token = symbolic_name + 4;
+ const str_index = try gz.identAsString(ident_token);
+ // TODO this needs extra code for local variables. Have a look at #215 and related
+ // issues and decide how to handle outputs. Do we want this to be identifiers?
+ // Or maybe we want to force this to be expressions with a pointer type.
+ // Until that is figured out this is only hooked up for referencing Decls.
+ const operand = try gz.addStrTok(.decl_ref, str_index, ident_token);
+ outputs[i] = .{
+ .name = name,
+ .constraint = constraint,
+ .operand = operand,
+ };
}
- const constraint_token = main_tokens[output_node] + 2;
- break :blk .{
- .ty = try typeExpr(gz, scope, out_type_node),
- .constraint = (try gz.strLitAsString(constraint_token)).index,
- };
- };
+ }
- const constraints = try arena.alloc(u32, full.inputs.len);
- const args = try arena.alloc(Zir.Inst.Ref, full.inputs.len);
+ if (full.inputs.len > 32) {
+ return astgen.failNode(full.inputs[32], "too many asm inputs", .{});
+ }
+ var inputs_buffer: [32]Zir.Inst.Asm.Input = undefined;
+ const inputs = inputs_buffer[0..full.inputs.len];
+
+ for (full.inputs) |input_node, i| {
+ const symbolic_name = main_tokens[input_node];
+ const name = try gz.identAsString(symbolic_name);
+ const constraint_token = symbolic_name + 2;
+ const constraint = (try gz.strLitAsString(constraint_token)).index;
+ const has_arrow = token_tags[symbolic_name + 4] == .arrow;
+ const operand = try expr(gz, scope, .{ .ty = .usize_type }, node_datas[input_node].lhs);
+ inputs[i] = .{
+ .name = name,
+ .constraint = constraint,
+ .operand = operand,
+ };
+ }
- for (full.inputs) |input, i| {
- const constraint_token = main_tokens[input] + 2;
- constraints[i] = (try gz.strLitAsString(constraint_token)).index;
- args[i] = try expr(gz, scope, .{ .ty = .usize_type }, node_datas[input].lhs);
+ var clobbers_buffer: [32]u32 = undefined;
+ var clobber_i: usize = 0;
+ if (full.first_clobber) |first_clobber| clobbers: {
+ // asm ("foo" ::: "a", "b")
+ // asm ("foo" ::: "a", "b",)
+ var tok_i = first_clobber;
+ while (true) : (tok_i += 1) {
+ if (clobber_i >= clobbers_buffer.len) {
+ return astgen.failTok(tok_i, "too many asm clobbers", .{});
+ }
+ clobbers_buffer[clobber_i] = (try gz.strLitAsString(tok_i)).index;
+ clobber_i += 1;
+ tok_i += 1;
+ switch (token_tags[tok_i]) {
+ .r_paren => break :clobbers,
+ .comma => {
+ if (token_tags[tok_i + 1] == .r_paren) {
+ break :clobbers;
+ } else {
+ continue;
+ }
+ },
+ else => unreachable,
+ }
+ }
}
- const tag: Zir.Inst.Tag = if (full.volatile_token != null) .asm_volatile else .@"asm";
- const result = try gz.addPlNode(tag, node, Zir.Inst.Asm{
+ const result = try gz.addAsm(.{
+ .node = node,
.asm_source = asm_source,
- .output_type = output.ty,
- .args_len = @intCast(u32, full.inputs.len),
- .clobbers_len = 0, // TODO implement asm clobbers
+ .is_volatile = full.volatile_token != null,
+ .output_type_bits = output_type_bits,
+ .outputs = outputs,
+ .inputs = inputs,
+ .clobbers = clobbers_buffer[0..clobber_i],
});
-
- try astgen.extra.ensureCapacity(astgen.gpa, astgen.extra.items.len +
- args.len + constraints.len + @boolToInt(output.ty != .none));
- if (output.ty != .none) {
- astgen.extra.appendAssumeCapacity(output.constraint);
- }
- astgen.appendRefsAssumeCapacity(args);
- astgen.extra.appendSliceAssumeCapacity(constraints);
-
return rvalue(gz, scope, rl, result, node);
}
@@ -5982,14 +5884,7 @@ fn asRlPtr(
// as well as the store instruction, instead passing the result as an rvalue.
const astgen = parent_gz.astgen;
- var as_scope: GenZir = .{
- .parent = scope,
- .decl_node_index = parent_gz.decl_node_index,
- .astgen = astgen,
- .force_comptime = parent_gz.force_comptime,
- .ref_start_index = parent_gz.ref_start_index,
- .instructions = .{},
- };
+ var as_scope = parent_gz.makeSubBlock(scope);
defer as_scope.instructions.deinit(astgen.gpa);
as_scope.rl_ptr = try as_scope.addBin(.coerce_result_ptr, dest_type, result_ptr);
@@ -6701,14 +6596,8 @@ fn cImport(
const astgen = gz.astgen;
const gpa = astgen.gpa;
- var block_scope: GenZir = .{
- .parent = scope,
- .decl_node_index = gz.decl_node_index,
- .astgen = astgen,
- .force_comptime = true,
- .ref_start_index = gz.ref_start_index,
- .instructions = .{},
- };
+ var block_scope = gz.makeSubBlock(scope);
+ block_scope.force_comptime = true;
defer block_scope.instructions.deinit(gpa);
const block_inst = try gz.addBlock(.c_import, node);
@@ -6802,43 +6691,44 @@ fn callExpr(
}
pub const simple_types = std.ComptimeStringMap(Zir.Inst.Ref, .{
- .{ "u8", .u8_type },
- .{ "i8", .i8_type },
- .{ "u16", .u16_type },
- .{ "i16", .i16_type },
- .{ "u32", .u32_type },
- .{ "i32", .i32_type },
- .{ "u64", .u64_type },
- .{ "i64", .i64_type },
- .{ "usize", .usize_type },
- .{ "isize", .isize_type },
- .{ "c_short", .c_short_type },
- .{ "c_ushort", .c_ushort_type },
+ .{ "anyerror", .anyerror_type },
+ .{ "anyframe", .anyframe_type },
+ .{ "bool", .bool_type },
.{ "c_int", .c_int_type },
- .{ "c_uint", .c_uint_type },
.{ "c_long", .c_long_type },
- .{ "c_ulong", .c_ulong_type },
+ .{ "c_longdouble", .c_longdouble_type },
.{ "c_longlong", .c_longlong_type },
+ .{ "c_short", .c_short_type },
+ .{ "c_uint", .c_uint_type },
+ .{ "c_ulong", .c_ulong_type },
.{ "c_ulonglong", .c_ulonglong_type },
- .{ "c_longdouble", .c_longdouble_type },
+ .{ "c_ushort", .c_ushort_type },
+ .{ "c_void", .c_void_type },
+ .{ "comptime_float", .comptime_float_type },
+ .{ "comptime_int", .comptime_int_type },
+ .{ "f128", .f128_type },
.{ "f16", .f16_type },
.{ "f32", .f32_type },
.{ "f64", .f64_type },
- .{ "f128", .f128_type },
- .{ "c_void", .c_void_type },
- .{ "bool", .bool_type },
- .{ "void", .void_type },
- .{ "type", .type_type },
- .{ "anyerror", .anyerror_type },
- .{ "comptime_int", .comptime_int_type },
- .{ "comptime_float", .comptime_float_type },
+ .{ "false", .bool_false },
+ .{ "i16", .i16_type },
+ .{ "i32", .i32_type },
+ .{ "i64", .i64_type },
+ .{ "i128", .i128_type },
+ .{ "i8", .i8_type },
+ .{ "isize", .isize_type },
.{ "noreturn", .noreturn_type },
- .{ "null", .null_type },
- .{ "undefined", .undefined_type },
- .{ "undefined", .undef },
.{ "null", .null_value },
.{ "true", .bool_true },
- .{ "false", .bool_false },
+ .{ "type", .type_type },
+ .{ "u16", .u16_type },
+ .{ "u32", .u32_type },
+ .{ "u64", .u64_type },
+ .{ "u128", .u128_type },
+ .{ "u8", .u8_type },
+ .{ "undefined", .undef },
+ .{ "usize", .usize_type },
+ .{ "void", .void_type },
});
fn nodeMayNeedMemoryLocation(tree: *const ast.Tree, start_node: ast.Node.Index) bool {
diff --git a/src/Module.zig b/src/Module.zig
index 502f94367a..4e69d301f3 100644
--- a/src/Module.zig
+++ b/src/Module.zig
@@ -1085,6 +1085,21 @@ pub const Scope = struct {
/// a result location pointer.
labeled_store_to_block_ptr_list: ArrayListUnmanaged(Zir.Inst.Index) = .{},
+ suspend_node: ast.Node.Index = 0,
+ nosuspend_node: ast.Node.Index = 0,
+
+ pub fn makeSubBlock(gz: *GenZir, scope: *Scope) GenZir {
+ return .{
+ .force_comptime = gz.force_comptime,
+ .ref_start_index = gz.ref_start_index,
+ .decl_node_index = gz.decl_node_index,
+ .parent = scope,
+ .astgen = gz.astgen,
+ .suspend_node = gz.suspend_node,
+ .nosuspend_node = gz.nosuspend_node,
+ };
+ }
+
pub const Label = struct {
token: ast.TokenIndex,
block_inst: Zir.Inst.Index,
@@ -1674,9 +1689,9 @@ pub const Scope = struct {
@as(usize, @boolToInt(args.type_inst != .none)) +
@as(usize, @boolToInt(args.align_inst != .none)),
);
- const payload_index = gz.astgen.addExtra(Zir.Inst.AllocExtended{
+ const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.AllocExtended{
.src_node = gz.nodeIndexToRelative(args.node),
- }) catch unreachable; // ensureUnusedCapacity above
+ });
if (args.type_inst != .none) {
astgen.extra.appendAssumeCapacity(@enumToInt(args.type_inst));
}
@@ -1703,6 +1718,64 @@ pub const Scope = struct {
return gz.indexToRef(new_index);
}
+ pub fn addAsm(
+ gz: *GenZir,
+ args: struct {
+ /// Absolute node index. This function does the conversion to offset from Decl.
+ node: ast.Node.Index,
+ asm_source: Zir.Inst.Ref,
+ output_type_bits: u32,
+ is_volatile: bool,
+ outputs: []const Zir.Inst.Asm.Output,
+ inputs: []const Zir.Inst.Asm.Input,
+ clobbers: []const u32,
+ },
+ ) !Zir.Inst.Ref {
+ const astgen = gz.astgen;
+ const gpa = astgen.gpa;
+
+ try gz.instructions.ensureUnusedCapacity(gpa, 1);
+ try astgen.instructions.ensureUnusedCapacity(gpa, 1);
+ try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Asm).Struct.fields.len +
+ args.outputs.len * @typeInfo(Zir.Inst.Asm.Output).Struct.fields.len +
+ args.inputs.len * @typeInfo(Zir.Inst.Asm.Input).Struct.fields.len +
+ args.clobbers.len);
+
+ const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Asm{
+ .src_node = gz.nodeIndexToRelative(args.node),
+ .asm_source = args.asm_source,
+ .output_type_bits = args.output_type_bits,
+ });
+ for (args.outputs) |output| {
+ _ = gz.astgen.addExtraAssumeCapacity(output);
+ }
+ for (args.inputs) |input| {
+ _ = gz.astgen.addExtraAssumeCapacity(input);
+ }
+ gz.astgen.extra.appendSliceAssumeCapacity(args.clobbers);
+
+ // * 0b00000000_000XXXXX - `outputs_len`.
+ // * 0b000000XX_XXX00000 - `inputs_len`.
+ // * 0b0XXXXX00_00000000 - `clobbers_len`.
+ // * 0bX0000000_00000000 - is volatile
+ const small: u16 = @intCast(u16, args.outputs.len) |
+ @intCast(u16, args.inputs.len << 5) |
+ @intCast(u16, args.clobbers.len << 10) |
+ (@as(u16, @boolToInt(args.is_volatile)) << 15);
+
+ const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len);
+ astgen.instructions.appendAssumeCapacity(.{
+ .tag = .extended,
+ .data = .{ .extended = .{
+ .opcode = .@"asm",
+ .small = small,
+ .operand = payload_index,
+ } },
+ });
+ gz.instructions.appendAssumeCapacity(new_index);
+ return gz.indexToRef(new_index);
+ }
+
/// Note that this returns a `Zir.Inst.Index` not a ref.
/// Does *not* append the block instruction to the scope.
/// Leaves the `payload_index` field undefined.
@@ -2209,6 +2282,18 @@ pub const SrcLoc = struct {
const token_starts = tree.tokens.items(.start);
return token_starts[tok_index];
},
+
+ .node_offset_anyframe_type => |node_off| {
+ const tree = src_loc.file_scope.tree;
+ const node_datas = tree.nodes.items(.data);
+ const node_tags = tree.nodes.items(.tag);
+ const parent_node = src_loc.declRelativeToNodeIndex(node_off);
+ const node = node_datas[parent_node].rhs;
+ const main_tokens = tree.nodes.items(.main_token);
+ const tok_index = main_tokens[node];
+ const token_starts = tree.tokens.items(.start);
+ return token_starts[tok_index];
+ },
}
}
};
@@ -2368,6 +2453,12 @@ pub const LazySrcLoc = union(enum) {
/// the return type node.
/// The Decl is determined contextually.
node_offset_fn_type_ret_ty: i32,
+ /// The source location points to the type expression of an `anyframe->T`
+ /// expression, found by taking this AST node index offset from the containing
+ /// Decl AST node, which points to a `anyframe->T` expression AST node. Next, navigate
+ /// to the type expression.
+ /// The Decl is determined contextually.
+ node_offset_anyframe_type: i32,
/// Upgrade to a `SrcLoc` based on the `Decl` or file in the provided scope.
pub fn toSrcLoc(lazy: LazySrcLoc, scope: *Scope) SrcLoc {
@@ -2407,6 +2498,7 @@ pub const LazySrcLoc = union(enum) {
.node_offset_switch_range,
.node_offset_fn_type_cc,
.node_offset_fn_type_ret_ty,
+ .node_offset_anyframe_type,
=> .{
.file_scope = scope.getFileScope(),
.parent_decl_node = scope.srcDecl().?.src_node,
@@ -2453,6 +2545,7 @@ pub const LazySrcLoc = union(enum) {
.node_offset_switch_range,
.node_offset_fn_type_cc,
.node_offset_fn_type_ret_ty,
+ .node_offset_anyframe_type,
=> .{
.file_scope = decl.getFileScope(),
.parent_decl_node = decl.src_node,
diff --git a/src/Sema.zig b/src/Sema.zig
index 6b9bf5cc1e..fd9bc39fd9 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -138,14 +138,13 @@ pub fn analyzeBody(
.alloc_inferred_comptime => try sema.zirAllocInferredComptime(block, inst),
.alloc_mut => try sema.zirAllocMut(block, inst),
.alloc_comptime => try sema.zirAllocComptime(block, inst),
+ .anyframe_type => try sema.zirAnyframeType(block, inst),
.array_cat => try sema.zirArrayCat(block, inst),
.array_mul => try sema.zirArrayMul(block, inst),
.array_type => try sema.zirArrayType(block, inst),
.array_type_sentinel => try sema.zirArrayTypeSentinel(block, inst),
.as => try sema.zirAs(block, inst),
.as_node => try sema.zirAsNode(block, inst),
- .@"asm" => try sema.zirAsm(block, inst, false),
- .asm_volatile => try sema.zirAsm(block, inst, true),
.bit_and => try sema.zirBitwise(block, inst, .bit_and),
.bit_not => try sema.zirBitNot(block, inst),
.bit_or => try sema.zirBitwise(block, inst, .bit_or),
@@ -518,6 +517,7 @@ fn zirExtended(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerErro
.frame_address => return sema.zirFrameAddress( block, extended),
.alloc => return sema.zirAllocExtended( block, extended),
.builtin_extern => return sema.zirBuiltinExtern( block, extended),
+ .@"asm" => return sema.zirAsm( block, extended),
.c_undef => return sema.zirCUndef( block, extended),
.c_include => return sema.zirCInclude( block, extended),
.c_define => return sema.zirCDefine( block, extended),
@@ -2173,6 +2173,19 @@ fn zirArrayTypeSentinel(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index)
return sema.mod.constType(sema.arena, .unneeded, array_ty);
}
+fn zirAnyframeType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+ const tracy = trace(@src());
+ defer tracy.end();
+
+ const inst_data = sema.code.instructions.items(.data)[inst].un_node;
+ const src = inst_data.src();
+ const operand_src: LazySrcLoc = .{ .node_offset_anyframe_type = inst_data.src_node };
+ const return_type = try sema.resolveType(block, operand_src, inst_data.operand);
+ const anyframe_type = try Type.Tag.anyframe_T.create(sema.arena, return_type);
+
+ return sema.mod.constType(sema.arena, src, anyframe_type);
+}
+
fn zirErrorUnionType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
const tracy = trace(@src());
defer tracy.end();
@@ -4394,42 +4407,62 @@ fn zirLoad(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*I
fn zirAsm(
sema: *Sema,
block: *Scope.Block,
- inst: Zir.Inst.Index,
- is_volatile: bool,
+ extended: Zir.Inst.Extended.InstData,
) InnerError!*Inst {
const tracy = trace(@src());
defer tracy.end();
- const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
- const src = inst_data.src();
- const asm_source_src: LazySrcLoc = .{ .node_offset_asm_source = inst_data.src_node };
- const ret_ty_src: LazySrcLoc = .{ .node_offset_asm_ret_ty = inst_data.src_node };
- const extra = sema.code.extraData(Zir.Inst.Asm, inst_data.payload_index);
+ const extra = sema.code.extraData(Zir.Inst.Asm, extended.operand);
+ const src: LazySrcLoc = .{ .node_offset = extra.data.src_node };
+ const asm_source_src: LazySrcLoc = .{ .node_offset_asm_source = extra.data.src_node };
+ const ret_ty_src: LazySrcLoc = .{ .node_offset_asm_ret_ty = extra.data.src_node };
const asm_source = try sema.resolveConstString(block, asm_source_src, extra.data.asm_source);
+ 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;
+
+ if (outputs_len > 1) {
+ return sema.mod.fail(&block.base, src, "TODO implement Sema for asm with more than 1 output", .{});
+ }
var extra_i = extra.end;
+ var output_type_bits = extra.data.output_type_bits;
+
const Output = struct { constraint: []const u8, ty: Type };
- const output: ?Output = if (extra.data.output_type != .none) blk: {
- const constraint = sema.code.nullTerminatedString(sema.code.extra[extra_i]);
- extra_i += 1;
+ const output: ?Output = if (outputs_len == 0) null else blk: {
+ const output = sema.code.extraData(Zir.Inst.Asm.Output, extra_i);
+ extra_i = output.end;
+
+ const is_type = @truncate(u1, output_type_bits) != 0;
+ output_type_bits >>= 1;
+
+ if (!is_type) {
+ return sema.mod.fail(&block.base, src, "TODO implement Sema for asm with non `->` output", .{});
+ }
+
+ const constraint = sema.code.nullTerminatedString(output.data.constraint);
break :blk Output{
.constraint = constraint,
- .ty = try sema.resolveType(block, ret_ty_src, extra.data.output_type),
+ .ty = try sema.resolveType(block, ret_ty_src, output.data.operand),
};
- } else null;
+ };
- const args = try sema.arena.alloc(*Inst, extra.data.args_len);
- const inputs = try sema.arena.alloc([]const u8, extra.data.args_len);
- const clobbers = try sema.arena.alloc([]const u8, extra.data.clobbers_len);
+ const args = try sema.arena.alloc(*Inst, inputs_len);
+ const inputs = try sema.arena.alloc([]const u8, inputs_len);
- for (args) |*arg| {
- arg.* = try sema.resolveInst(@intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]));
- extra_i += 1;
- }
- for (inputs) |*name| {
- name.* = sema.code.nullTerminatedString(sema.code.extra[extra_i]);
- extra_i += 1;
+ for (args) |*arg, arg_i| {
+ const input = sema.code.extraData(Zir.Inst.Asm.Input, extra_i);
+ extra_i = input.end;
+
+ const name = sema.code.nullTerminatedString(input.data.name);
+ _ = name; // TODO: use the name
+
+ arg.* = try sema.resolveInst(input.data.operand);
+ inputs[arg_i] = sema.code.nullTerminatedString(input.data.constraint);
}
+
+ const clobbers = try sema.arena.alloc([]const u8, clobbers_len);
for (clobbers) |*name| {
name.* = sema.code.nullTerminatedString(sema.code.extra[extra_i]);
extra_i += 1;
@@ -5408,7 +5441,7 @@ fn zirFuncExtended(
var extra_index: usize = extra.end;
if (small.has_lib_name) {
- const lib_name = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
+ const lib_name = sema.code.nullTerminatedString(sema.code.extra[extra_index]);
extra_index += 1;
return sema.mod.fail(&block.base, src, "TODO: implement Sema func lib name", .{});
}
@@ -5428,7 +5461,7 @@ fn zirFuncExtended(
} else .Unspecified;
const param_types = sema.code.refSlice(extra_index, extra.data.param_types_len);
- extra_index += 1;
+ extra_index += param_types.len;
const body = sema.code.extra[extra_index..][0..extra.data.body_len];
diff --git a/src/Zir.zig b/src/Zir.zig
index 898b3089f8..dfa845ce13 100644
--- a/src/Zir.zig
+++ b/src/Zir.zig
@@ -60,7 +60,8 @@ pub fn extraData(code: Zir, comptime T: type, index: usize) struct { data: T, en
@field(result, field.name) = switch (field.field_type) {
u32 => code.extra[i],
Inst.Ref => @intToEnum(Inst.Ref, code.extra[i]),
- else => unreachable,
+ i32 => @bitCast(i32, code.extra[i]),
+ else => @compileError("bad field type"),
};
i += 1;
}
@@ -165,18 +166,15 @@ pub const Inst = struct {
/// error if the indexable object is not indexable.
/// Uses the `un_node` field. The AST node is the for loop node.
indexable_ptr_len,
+ /// Create a `anyframe->T` type.
+ /// Uses the `un_node` field.
+ anyframe_type,
/// Type coercion. No source location attached.
/// Uses the `bin` field.
as,
/// Type coercion to the function's return type.
/// Uses the `pl_node` field. Payload is `As`. AST node could be many things.
as_node,
- /// Inline assembly. Non-volatile.
- /// Uses the `pl_node` union field. Payload is `Asm`. AST node is the assembly node.
- @"asm",
- /// Inline assembly with the volatile attribute.
- /// Uses the `pl_node` union field. Payload is `Asm`. AST node is the assembly node.
- asm_volatile,
/// Bitwise AND. `&`
bit_and,
/// Bitcast a value to a different type.
@@ -967,10 +965,9 @@ pub const Inst = struct {
.array_type_sentinel,
.elem_type,
.indexable_ptr_len,
+ .anyframe_type,
.as,
.as_node,
- .@"asm",
- .asm_volatile,
.bit_and,
.bitcast,
.bitcast_result_ptr,
@@ -1259,6 +1256,14 @@ pub const Inst = struct {
/// The `@extern` builtin.
/// `operand` is payload index to `BinNode`.
builtin_extern,
+ /// Inline assembly.
+ /// `small`:
+ /// * 0b00000000_000XXXXX - `outputs_len`.
+ /// * 0b000000XX_XXX00000 - `inputs_len`.
+ /// * 0b0XXXXX00_00000000 - `clobbers_len`.
+ /// * 0bX0000000_00000000 - is volatile
+ /// `operand` is payload index to `Asm`.
+ @"asm",
/// `operand` is payload index to `UnNode`.
c_undef,
/// `operand` is payload index to `UnNode`.
@@ -1313,6 +1318,8 @@ pub const Inst = struct {
i32_type,
u64_type,
i64_type,
+ u128_type,
+ i128_type,
usize_type,
isize_type,
c_short_type,
@@ -1336,17 +1343,10 @@ pub const Inst = struct {
comptime_int_type,
comptime_float_type,
noreturn_type,
+ anyframe_type,
null_type,
undefined_type,
- fn_noreturn_no_args_type,
- fn_void_no_args_type,
- fn_naked_noreturn_no_args_type,
- fn_ccc_void_no_args_type,
- single_const_pointer_to_comptime_int_type,
- const_slice_u8_type,
enum_literal_type,
- manyptr_u8_type,
- manyptr_const_u8_type,
atomic_ordering_type,
atomic_rmw_op_type,
calling_convention_type,
@@ -1355,6 +1355,14 @@ pub const Inst = struct {
call_options_type,
export_options_type,
extern_options_type,
+ manyptr_u8_type,
+ manyptr_const_u8_type,
+ fn_noreturn_no_args_type,
+ fn_void_no_args_type,
+ fn_naked_noreturn_no_args_type,
+ fn_ccc_void_no_args_type,
+ single_const_pointer_to_comptime_int_type,
+ const_slice_u8_type,
/// `undefined` (untyped)
undef,
@@ -1418,6 +1426,14 @@ pub const Inst = struct {
.ty = Type.initTag(.type),
.val = Value.initTag(.i64_type),
},
+ .u128_type = .{
+ .ty = Type.initTag(.type),
+ .val = Value.initTag(.u128_type),
+ },
+ .i128_type = .{
+ .ty = Type.initTag(.type),
+ .val = Value.initTag(.i128_type),
+ },
.usize_type = .{
.ty = Type.initTag(.type),
.val = Value.initTag(.usize_type),
@@ -1510,6 +1526,10 @@ pub const Inst = struct {
.ty = Type.initTag(.type),
.val = Value.initTag(.noreturn_type),
},
+ .anyframe_type = .{
+ .ty = Type.initTag(.type),
+ .val = Value.initTag(.anyframe_type),
+ },
.null_type = .{
.ty = Type.initTag(.type),
.val = Value.initTag(.null_type),
@@ -1806,17 +1826,35 @@ pub const Inst = struct {
}
};
- /// Stored in extra. Trailing is:
- /// * output_constraint: u32 // index into string_bytes (null terminated) if output is present
- /// * arg: Ref // for every args_len.
- /// * constraint: u32 // index into string_bytes (null terminated) for every args_len.
- /// * clobber: u32 // index into string_bytes (null terminated) for every clobbers_len.
+ /// Trailing:
+ /// 0. Output for every outputs_len
+ /// 1. Input for every inputs_len
+ /// 2. clobber: u32 // index into string_bytes (null terminated) for every clobbers_len.
pub const Asm = struct {
+ src_node: i32,
asm_source: Ref,
- /// May be omitted.
- output_type: Ref,
- args_len: u32,
- clobbers_len: u32,
+ /// 1 bit for each outputs_len: whether it uses `-> T` or not.
+ /// 0b0 - operand is a pointer to where to store the output.
+ /// 0b1 - operand is a type; asm expression has the output as the result.
+ /// 0b0X is the first output, 0bX0 is the second, etc.
+ output_type_bits: u32,
+
+ pub const Output = struct {
+ /// index into string_bytes (null terminated)
+ name: u32,
+ /// index into string_bytes (null terminated)
+ constraint: u32,
+ /// How to interpret this is determined by `output_type_bits`.
+ operand: Ref,
+ };
+
+ pub const Input = struct {
+ /// index into string_bytes (null terminated)
+ name: u32,
+ /// index into string_bytes (null terminated)
+ constraint: u32,
+ operand: Ref,
+ };
};
/// Trailing:
@@ -2298,6 +2336,7 @@ const Writer = struct {
.alloc_mut,
.alloc_comptime,
.indexable_ptr_len,
+ .anyframe_type,
.bit_not,
.bool_not,
.negate,
@@ -2430,10 +2469,6 @@ const Writer = struct {
.builtin_async_call,
=> try self.writePlNode(stream, inst),
- .@"asm",
- .asm_volatile,
- => try self.writePlNodeAsm(stream, inst),
-
.error_set_decl => try self.writePlNodeErrorSetDecl(stream, inst),
.add_with_overflow,
@@ -2603,7 +2638,9 @@ const Writer = struct {
.builtin_src,
=> try self.writeExtNode(stream, extended),
- .func,
+ .@"asm" => try self.writeAsm(stream, extended),
+ .func => try self.writeFuncExtended(stream, extended),
+
.alloc,
.builtin_extern,
.c_undef,
@@ -2794,49 +2831,74 @@ const Writer = struct {
try self.writeSrc(stream, inst_data.src());
}
- fn writePlNodeAsm(self: *Writer, stream: anytype, inst: Inst.Index) !void {
- const inst_data = self.code.instructions.items(.data)[inst].pl_node;
- const extra = self.code.extraData(Inst.Asm, inst_data.payload_index);
- var extra_i: usize = extra.end;
+ fn writeAsm(self: *Writer, stream: anytype, extended: Inst.Extended.InstData) !void {
+ const extra = self.code.extraData(Inst.Asm, extended.operand);
+ const src: LazySrcLoc = .{ .node_offset = 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;
- if (extra.data.output_type != .none) {
- const constraint_str_index = self.code.extra[extra_i];
- extra_i += 1;
- const constraint = self.code.nullTerminatedString(constraint_str_index);
- try stream.print("\"{}\"->", .{std.zig.fmtEscapes(constraint)});
- try self.writeInstRef(stream, extra.data.output_type);
- try stream.writeAll(", ");
- }
+ try self.writeFlag(stream, "volatile, ", is_volatile);
+ try self.writeInstRef(stream, extra.data.asm_source);
+ try stream.writeAll(", ");
+
+ var extra_i: usize = extra.end;
+ var output_type_bits = extra.data.output_type_bits;
{
var i: usize = 0;
- while (i < extra.data.args_len) : (i += 1) {
- const arg = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_i]);
- extra_i += 1;
- try self.writeInstRef(stream, arg);
- try stream.writeAll(", ");
+ while (i < outputs_len) : (i += 1) {
+ const output = self.code.extraData(Inst.Asm.Output, extra_i);
+ extra_i = output.end;
+
+ const is_type = @truncate(u1, output_type_bits) != 0;
+ output_type_bits >>= 1;
+
+ const name = self.code.nullTerminatedString(output.data.name);
+ const constraint = self.code.nullTerminatedString(output.data.constraint);
+ try stream.print("output({}, \"{}\", ", .{
+ std.zig.fmtId(name), std.zig.fmtEscapes(constraint),
+ });
+ try self.writeFlag(stream, "->", is_type);
+ try self.writeInstRef(stream, output.data.operand);
+ try stream.writeAll(")");
+ if (i + 1 < outputs_len) {
+ try stream.writeAll("), ");
+ }
}
}
{
var i: usize = 0;
- while (i < extra.data.args_len) : (i += 1) {
- const str_index = self.code.extra[extra_i];
- extra_i += 1;
- const constraint = self.code.nullTerminatedString(str_index);
- try stream.print("\"{}\", ", .{std.zig.fmtEscapes(constraint)});
+ while (i < inputs_len) : (i += 1) {
+ const input = self.code.extraData(Inst.Asm.Input, extra_i);
+ extra_i = input.end;
+
+ const name = self.code.nullTerminatedString(input.data.name);
+ const constraint = self.code.nullTerminatedString(input.data.constraint);
+ try stream.print("input({}, \"{}\", ", .{
+ std.zig.fmtId(name), std.zig.fmtEscapes(constraint),
+ });
+ try self.writeInstRef(stream, input.data.operand);
+ try stream.writeAll(")");
+ if (i + 1 < inputs_len) {
+ try stream.writeAll(", ");
+ }
}
}
{
var i: usize = 0;
- while (i < extra.data.clobbers_len) : (i += 1) {
+ while (i < clobbers_len) : (i += 1) {
const str_index = self.code.extra[extra_i];
extra_i += 1;
const clobber = self.code.nullTerminatedString(str_index);
- try stream.print("{}, ", .{std.zig.fmtId(clobber)});
+ try stream.print("{}", .{std.zig.fmtId(clobber)});
+ if (i + 1 < clobbers_len) {
+ try stream.writeAll(", ");
+ }
}
}
- try self.writeInstRef(stream, extra.data.asm_source);
try stream.writeAll(") ");
- try self.writeSrc(stream, inst_data.src());
+ try self.writeSrc(stream, src);
}
fn writePlNodeOverflowArithmetic(self: *Writer, stream: anytype, inst: Inst.Index) !void {
@@ -3467,6 +3529,40 @@ const Writer = struct {
);
}
+ fn writeFuncExtended(self: *Writer, stream: anytype, extended: Inst.Extended.InstData) !void {
+ const extra = self.code.extraData(Inst.ExtendedFunc, extended.operand);
+ const src: LazySrcLoc = .{ .node_offset = extra.data.src_node };
+ const small = @bitCast(Inst.ExtendedFunc.Small, extended.small);
+
+ var extra_index: usize = extra.end;
+ if (small.has_lib_name) {
+ const lib_name = self.code.nullTerminatedString(self.code.extra[extra_index]);
+ extra_index += 1;
+ try stream.print("lib_name=\"{}\", ", .{std.zig.fmtEscapes(lib_name)});
+ }
+ const cc: Inst.Ref = if (!small.has_cc) .none else blk: {
+ const cc = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
+ extra_index += 1;
+ break :blk cc;
+ };
+
+ const param_types = self.code.refSlice(extra_index, extra.data.param_types_len);
+ extra_index += param_types.len;
+
+ const body = self.code.extra[extra_index..][0..extra.data.body_len];
+
+ return self.writeFuncCommon(
+ stream,
+ param_types,
+ extra.data.return_type,
+ small.is_inferred_error,
+ small.is_var_args,
+ cc,
+ body,
+ src,
+ );
+ }
+
fn writeBoolBr(self: *Writer, stream: anytype, inst: Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[inst].bool_br;
const extra = self.code.extraData(Inst.Block, inst_data.payload_index);
diff --git a/src/type.zig b/src/type.zig
index 5bcf06cb5d..18dd453814 100644
--- a/src/type.zig
+++ b/src/type.zig
@@ -95,6 +95,8 @@ pub const Type = extern union {
.anyerror_void_error_union, .error_union => return .ErrorUnion,
+ .anyframe_T, .@"anyframe" => return .AnyFrame,
+
.empty_struct,
.empty_struct_literal,
.@"struct",
@@ -620,6 +622,7 @@ pub const Type = extern union {
.call_options,
.export_options,
.extern_options,
+ .@"anyframe",
=> unreachable,
.array_u8,
@@ -637,6 +640,7 @@ pub const Type = extern union {
.optional,
.optional_single_mut_pointer,
.optional_single_const_pointer,
+ .anyframe_T,
=> return self.copyPayloadShallow(allocator, Payload.ElemType),
.int_signed,
@@ -754,6 +758,7 @@ pub const Type = extern union {
.void,
.type,
.anyerror,
+ .@"anyframe",
.comptime_int,
.comptime_float,
.noreturn,
@@ -820,6 +825,12 @@ pub const Type = extern union {
continue;
},
+ .anyframe_T => {
+ const return_type = ty.castTag(.anyframe_T).?.data;
+ try writer.print("anyframe->", .{});
+ ty = return_type;
+ continue;
+ },
.array_u8 => {
const len = ty.castTag(.array_u8).?.data;
return writer.print("[{d}]u8", .{len});
@@ -994,6 +1005,7 @@ pub const Type = extern union {
.void => return Value.initTag(.void_type),
.type => return Value.initTag(.type_type),
.anyerror => return Value.initTag(.anyerror_type),
+ .@"anyframe" => return Value.initTag(.anyframe_type),
.comptime_int => return Value.initTag(.comptime_int_type),
.comptime_float => return Value.initTag(.comptime_float_type),
.noreturn => return Value.initTag(.noreturn_type),
@@ -1075,6 +1087,8 @@ pub const Type = extern union {
.call_options,
.export_options,
.extern_options,
+ .@"anyframe",
+ .anyframe_T,
=> true,
.@"struct" => {
@@ -1223,6 +1237,8 @@ pub const Type = extern union {
.pointer,
.manyptr_u8,
.manyptr_const_u8,
+ .@"anyframe",
+ .anyframe_T,
=> return @divExact(target.cpu.arch.ptrBitWidth(), 8),
.c_short => return @divExact(CType.short.sizeInBits(target), 8),
@@ -1388,7 +1404,11 @@ pub const Type = extern union {
.i64, .u64 => return 8,
.u128, .i128 => return 16,
- .isize, .usize => return @divExact(target.cpu.arch.ptrBitWidth(), 8),
+ .isize,
+ .usize,
+ .@"anyframe",
+ .anyframe_T,
+ => return @divExact(target.cpu.arch.ptrBitWidth(), 8),
.const_slice,
.mut_slice,
@@ -1536,7 +1556,11 @@ pub const Type = extern union {
.i64, .u64, .f64 => 64,
.u128, .i128, .f128 => 128,
- .isize, .usize => target.cpu.arch.ptrBitWidth(),
+ .isize,
+ .usize,
+ .@"anyframe",
+ .anyframe_T,
+ => target.cpu.arch.ptrBitWidth(),
.const_slice,
.mut_slice,
@@ -2256,6 +2280,8 @@ pub const Type = extern union {
.call_options,
.export_options,
.extern_options,
+ .@"anyframe",
+ .anyframe_T,
=> return null,
.@"struct" => {
@@ -2666,9 +2692,10 @@ pub const Type = extern union {
comptime_int,
comptime_float,
noreturn,
+ @"anyframe",
+ @"null",
+ @"undefined",
enum_literal,
- manyptr_u8,
- manyptr_const_u8,
atomic_ordering,
atomic_rmw_op,
calling_convention,
@@ -2677,15 +2704,15 @@ pub const Type = extern union {
call_options,
export_options,
extern_options,
- @"null",
- @"undefined",
+ manyptr_u8,
+ manyptr_const_u8,
fn_noreturn_no_args,
fn_void_no_args,
fn_naked_noreturn_no_args,
fn_ccc_void_no_args,
single_const_pointer_to_comptime_int,
- anyerror_void_error_union,
const_slice_u8,
+ anyerror_void_error_union,
/// This is a special type for variadic parameters of a function call.
/// Casts to it will validate that the type can be passed to a c calling convetion function.
var_args_param,
@@ -2719,6 +2746,7 @@ pub const Type = extern union {
optional_single_mut_pointer,
optional_single_const_pointer,
error_union,
+ anyframe_T,
error_set,
error_set_single,
empty_struct,
@@ -2790,6 +2818,7 @@ pub const Type = extern union {
.call_options,
.export_options,
.extern_options,
+ .@"anyframe",
=> @compileError("Type Tag " ++ @tagName(t) ++ " has no payload"),
.array_u8,
@@ -2807,6 +2836,7 @@ pub const Type = extern union {
.optional,
.optional_single_mut_pointer,
.optional_single_const_pointer,
+ .anyframe_T,
=> Payload.ElemType,
.int_signed,
diff --git a/src/value.zig b/src/value.zig
index e1ca79332c..d2d7be3007 100644
--- a/src/value.zig
+++ b/src/value.zig
@@ -55,17 +55,10 @@ pub const Value = extern union {
comptime_int_type,
comptime_float_type,
noreturn_type,
+ anyframe_type,
null_type,
undefined_type,
- fn_noreturn_no_args_type,
- fn_void_no_args_type,
- fn_naked_noreturn_no_args_type,
- fn_ccc_void_no_args_type,
- single_const_pointer_to_comptime_int_type,
- const_slice_u8_type,
enum_literal_type,
- manyptr_u8_type,
- manyptr_const_u8_type,
atomic_ordering_type,
atomic_rmw_op_type,
calling_convention_type,
@@ -74,6 +67,14 @@ pub const Value = extern union {
call_options_type,
export_options_type,
extern_options_type,
+ manyptr_u8_type,
+ manyptr_const_u8_type,
+ fn_noreturn_no_args_type,
+ fn_void_no_args_type,
+ fn_naked_noreturn_no_args_type,
+ fn_ccc_void_no_args_type,
+ single_const_pointer_to_comptime_int_type,
+ const_slice_u8_type,
undef,
zero,
@@ -166,6 +167,7 @@ pub const Value = extern union {
.fn_naked_noreturn_no_args_type,
.fn_ccc_void_no_args_type,
.single_const_pointer_to_comptime_int_type,
+ .anyframe_type,
.const_slice_u8_type,
.enum_literal_type,
.undef,
@@ -334,6 +336,7 @@ pub const Value = extern union {
.fn_naked_noreturn_no_args_type,
.fn_ccc_void_no_args_type,
.single_const_pointer_to_comptime_int_type,
+ .anyframe_type,
.const_slice_u8_type,
.enum_literal_type,
.undef,
@@ -502,6 +505,7 @@ pub const Value = extern union {
.fn_naked_noreturn_no_args_type => return out_stream.writeAll("fn() callconv(.Naked) noreturn"),
.fn_ccc_void_no_args_type => return out_stream.writeAll("fn() callconv(.C) void"),
.single_const_pointer_to_comptime_int_type => return out_stream.writeAll("*const comptime_int"),
+ .anyframe_type => return out_stream.writeAll("anyframe"),
.const_slice_u8_type => return out_stream.writeAll("[]const u8"),
.enum_literal_type => return out_stream.writeAll("@Type(.EnumLiteral)"),
.manyptr_u8_type => return out_stream.writeAll("[*]u8"),
@@ -633,6 +637,7 @@ pub const Value = extern union {
.fn_naked_noreturn_no_args_type => Type.initTag(.fn_naked_noreturn_no_args),
.fn_ccc_void_no_args_type => Type.initTag(.fn_ccc_void_no_args),
.single_const_pointer_to_comptime_int_type => Type.initTag(.single_const_pointer_to_comptime_int),
+ .anyframe_type => Type.initTag(.@"anyframe"),
.const_slice_u8_type => Type.initTag(.const_slice_u8),
.enum_literal_type => Type.initTag(.enum_literal),
.manyptr_u8_type => Type.initTag(.manyptr_u8),
@@ -1070,6 +1075,7 @@ pub const Value = extern union {
.fn_naked_noreturn_no_args_type,
.fn_ccc_void_no_args_type,
.single_const_pointer_to_comptime_int_type,
+ .anyframe_type,
.const_slice_u8_type,
.enum_literal_type,
.ty,
@@ -1338,6 +1344,7 @@ pub const Value = extern union {
.fn_naked_noreturn_no_args_type,
.fn_ccc_void_no_args_type,
.single_const_pointer_to_comptime_int_type,
+ .anyframe_type,
.const_slice_u8_type,
.enum_literal_type,
.manyptr_u8_type,