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.
This commit is contained in:
Andrew Kelley 2021-04-23 18:28:46 -07:00
parent 183ee0965f
commit b40a8efb9a
6 changed files with 515 additions and 366 deletions

View File

@ -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,
}
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,
};
};
const constraints = try arena.alloc(u32, full.inputs.len);
const args = try arena.alloc(Zir.Inst.Ref, full.inputs.len);
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);
}
const tag: Zir.Inst.Tag = if (full.volatile_token != null) .asm_volatile else .@"asm";
const result = try gz.addPlNode(tag, node, Zir.Inst.Asm{
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 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_longlong", .c_longlong_type },
.{ "c_ulonglong", .c_ulonglong_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_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 {

View File

@ -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,

View File

@ -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];

View File

@ -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);

View File

@ -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,

View File

@ -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,