mirror of
https://github.com/ziglang/zig.git
synced 2026-02-04 05:33:39 +00:00
Merge pull request #11752 from ziglang/zir-fancy-fns
stage2: add missing data to ZIR encoding of functions
This commit is contained in:
commit
c3ef4ac15f
328
src/AstGen.zig
328
src/AstGen.zig
@ -73,7 +73,7 @@ fn setExtra(astgen: *AstGen, index: usize, extra: anytype) void {
|
||||
Zir.Inst.Call.Flags => @bitCast(u32, @field(extra, field.name)),
|
||||
Zir.Inst.BuiltinCall.Flags => @bitCast(u32, @field(extra, field.name)),
|
||||
Zir.Inst.SwitchBlock.Bits => @bitCast(u32, @field(extra, field.name)),
|
||||
Zir.Inst.ExtendedFunc.Bits => @bitCast(u32, @field(extra, field.name)),
|
||||
Zir.Inst.FuncFancy.Bits => @bitCast(u32, @field(extra, field.name)),
|
||||
else => @compileError("bad field type"),
|
||||
};
|
||||
i += 1;
|
||||
@ -1205,7 +1205,7 @@ fn fnProtoExpr(
|
||||
break :is_var_args false;
|
||||
};
|
||||
|
||||
const align_inst: Zir.Inst.Ref = if (fn_proto.ast.align_expr == 0) .none else inst: {
|
||||
const align_ref: Zir.Inst.Ref = if (fn_proto.ast.align_expr == 0) .none else inst: {
|
||||
break :inst try expr(&block_scope, scope, align_rl, fn_proto.ast.align_expr);
|
||||
};
|
||||
|
||||
@ -1232,19 +1232,24 @@ fn fnProtoExpr(
|
||||
if (is_inferred_error) {
|
||||
return astgen.failTok(maybe_bang, "function prototype may not have inferred error set", .{});
|
||||
}
|
||||
var ret_gz = block_scope.makeSubBlock(scope);
|
||||
defer ret_gz.unstack();
|
||||
const ret_ty = try expr(&ret_gz, scope, coerced_type_rl, fn_proto.ast.return_type);
|
||||
const ret_br = try ret_gz.addBreak(.break_inline, 0, ret_ty);
|
||||
const ret_ty = try expr(&block_scope, scope, coerced_type_rl, fn_proto.ast.return_type);
|
||||
|
||||
const result = try block_scope.addFunc(.{
|
||||
.src_node = fn_proto.ast.proto_node,
|
||||
|
||||
.cc_ref = cc,
|
||||
.cc_gz = null,
|
||||
.align_ref = align_ref,
|
||||
.align_gz = null,
|
||||
.ret_ref = ret_ty,
|
||||
.ret_gz = null,
|
||||
.section_ref = .none,
|
||||
.section_gz = null,
|
||||
.addrspace_ref = .none,
|
||||
.addrspace_gz = null,
|
||||
|
||||
.param_block = block_inst,
|
||||
.ret_gz = &ret_gz,
|
||||
.ret_br = ret_br,
|
||||
.body_gz = null,
|
||||
.cc = cc,
|
||||
.align_inst = align_inst,
|
||||
.lib_name = 0,
|
||||
.is_var_args = is_var_args,
|
||||
.is_inferred_error = false,
|
||||
@ -2262,7 +2267,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
|
||||
.field_val_named,
|
||||
.func,
|
||||
.func_inferred,
|
||||
.func_extended,
|
||||
.func_fancy,
|
||||
.int,
|
||||
.int_big,
|
||||
.float,
|
||||
@ -3373,9 +3378,8 @@ fn fnDecl(
|
||||
|
||||
const doc_comment_index = try astgen.docCommentAsString(fn_proto.firstToken());
|
||||
|
||||
const has_section_or_addrspace = fn_proto.ast.section_expr != 0 or fn_proto.ast.addrspace_expr != 0;
|
||||
// Alignment is passed in the func instruction in this case.
|
||||
wip_members.nextDecl(is_pub, is_export, false, has_section_or_addrspace);
|
||||
// align, linksection, and addrspace is passed in the func instruction in this case.
|
||||
wip_members.nextDecl(is_pub, is_export, false, false);
|
||||
|
||||
var params_scope = &fn_gz.base;
|
||||
const is_var_args = is_var_args: {
|
||||
@ -3461,17 +3465,49 @@ fn fnDecl(
|
||||
const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1;
|
||||
const is_inferred_error = token_tags[maybe_bang] == .bang;
|
||||
|
||||
const align_inst: Zir.Inst.Ref = if (fn_proto.ast.align_expr == 0) .none else inst: {
|
||||
break :inst try expr(&decl_gz, params_scope, align_rl, fn_proto.ast.align_expr);
|
||||
};
|
||||
const addrspace_inst: Zir.Inst.Ref = if (fn_proto.ast.addrspace_expr == 0) .none else inst: {
|
||||
break :inst try expr(&decl_gz, params_scope, .{ .ty = .address_space_type }, fn_proto.ast.addrspace_expr);
|
||||
};
|
||||
const section_inst: Zir.Inst.Ref = if (fn_proto.ast.section_expr == 0) .none else inst: {
|
||||
break :inst try comptimeExpr(&decl_gz, params_scope, .{ .ty = .const_slice_u8_type }, fn_proto.ast.section_expr);
|
||||
// After creating the function ZIR instruction, it will need to update the break
|
||||
// instructions inside the expression blocks for align, addrspace, cc, and ret_ty
|
||||
// to use the function instruction as the "block" to break from.
|
||||
|
||||
var align_gz = decl_gz.makeSubBlock(params_scope);
|
||||
defer align_gz.unstack();
|
||||
const align_ref: Zir.Inst.Ref = if (fn_proto.ast.align_expr == 0) .none else inst: {
|
||||
const inst = try expr(&decl_gz, params_scope, coerced_align_rl, fn_proto.ast.align_expr);
|
||||
if (align_gz.instructionsSlice().len == 0) {
|
||||
// In this case we will send a len=0 body which can be encoded more efficiently.
|
||||
break :inst inst;
|
||||
}
|
||||
_ = try align_gz.addBreak(.break_inline, 0, inst);
|
||||
break :inst inst;
|
||||
};
|
||||
|
||||
const cc: Zir.Inst.Ref = blk: {
|
||||
var addrspace_gz = decl_gz.makeSubBlock(params_scope);
|
||||
defer addrspace_gz.unstack();
|
||||
const addrspace_ref: Zir.Inst.Ref = if (fn_proto.ast.addrspace_expr == 0) .none else inst: {
|
||||
const inst = try expr(&decl_gz, params_scope, .{ .coerced_ty = .address_space_type }, fn_proto.ast.addrspace_expr);
|
||||
if (addrspace_gz.instructionsSlice().len == 0) {
|
||||
// In this case we will send a len=0 body which can be encoded more efficiently.
|
||||
break :inst inst;
|
||||
}
|
||||
_ = try addrspace_gz.addBreak(.break_inline, 0, inst);
|
||||
break :inst inst;
|
||||
};
|
||||
|
||||
var section_gz = decl_gz.makeSubBlock(params_scope);
|
||||
defer section_gz.unstack();
|
||||
const section_ref: Zir.Inst.Ref = if (fn_proto.ast.section_expr == 0) .none else inst: {
|
||||
const inst = try expr(&decl_gz, params_scope, .{ .coerced_ty = .const_slice_u8_type }, fn_proto.ast.section_expr);
|
||||
if (section_gz.instructionsSlice().len == 0) {
|
||||
// In this case we will send a len=0 body which can be encoded more efficiently.
|
||||
break :inst inst;
|
||||
}
|
||||
_ = try section_gz.addBreak(.break_inline, 0, inst);
|
||||
break :inst inst;
|
||||
};
|
||||
|
||||
var cc_gz = decl_gz.makeSubBlock(params_scope);
|
||||
defer cc_gz.unstack();
|
||||
const cc_ref: Zir.Inst.Ref = blk: {
|
||||
if (fn_proto.ast.callconv_expr != 0) {
|
||||
if (has_inline_keyword) {
|
||||
return astgen.failNode(
|
||||
@ -3480,12 +3516,18 @@ fn fnDecl(
|
||||
.{},
|
||||
);
|
||||
}
|
||||
break :blk try expr(
|
||||
const inst = try expr(
|
||||
&decl_gz,
|
||||
params_scope,
|
||||
.{ .ty = .calling_convention_type },
|
||||
.{ .coerced_ty = .calling_convention_type },
|
||||
fn_proto.ast.callconv_expr,
|
||||
);
|
||||
if (cc_gz.instructionsSlice().len == 0) {
|
||||
// In this case we will send a len=0 body which can be encoded more efficiently.
|
||||
break :blk inst;
|
||||
}
|
||||
_ = try cc_gz.addBreak(.break_inline, 0, inst);
|
||||
break :blk inst;
|
||||
} else if (is_extern) {
|
||||
// note: https://github.com/ziglang/zig/issues/5269
|
||||
break :blk .calling_convention_c;
|
||||
@ -3498,8 +3540,15 @@ fn fnDecl(
|
||||
|
||||
var ret_gz = decl_gz.makeSubBlock(params_scope);
|
||||
defer ret_gz.unstack();
|
||||
const ret_ty = try expr(&ret_gz, params_scope, coerced_type_rl, fn_proto.ast.return_type);
|
||||
const ret_br = try ret_gz.addBreak(.break_inline, 0, ret_ty);
|
||||
const ret_ref: Zir.Inst.Ref = inst: {
|
||||
const inst = try expr(&ret_gz, params_scope, coerced_type_rl, fn_proto.ast.return_type);
|
||||
if (ret_gz.instructionsSlice().len == 0) {
|
||||
// In this case we will send a len=0 body which can be encoded more efficiently.
|
||||
break :inst inst;
|
||||
}
|
||||
_ = try ret_gz.addBreak(.break_inline, 0, inst);
|
||||
break :inst inst;
|
||||
};
|
||||
|
||||
const func_inst: Zir.Inst.Ref = if (body_node == 0) func: {
|
||||
if (!is_extern) {
|
||||
@ -3510,12 +3559,18 @@ fn fnDecl(
|
||||
}
|
||||
break :func try decl_gz.addFunc(.{
|
||||
.src_node = decl_node,
|
||||
.cc_ref = cc_ref,
|
||||
.cc_gz = &cc_gz,
|
||||
.align_ref = align_ref,
|
||||
.align_gz = &align_gz,
|
||||
.ret_ref = ret_ref,
|
||||
.ret_gz = &ret_gz,
|
||||
.ret_br = ret_br,
|
||||
.section_ref = section_ref,
|
||||
.section_gz = §ion_gz,
|
||||
.addrspace_ref = addrspace_ref,
|
||||
.addrspace_gz = &addrspace_gz,
|
||||
.param_block = block_inst,
|
||||
.body_gz = null,
|
||||
.cc = cc,
|
||||
.align_inst = align_inst,
|
||||
.lib_name = lib_name,
|
||||
.is_var_args = is_var_args,
|
||||
.is_inferred_error = false,
|
||||
@ -3549,14 +3604,20 @@ fn fnDecl(
|
||||
|
||||
break :func try decl_gz.addFunc(.{
|
||||
.src_node = decl_node,
|
||||
.cc_ref = cc_ref,
|
||||
.cc_gz = &cc_gz,
|
||||
.align_ref = align_ref,
|
||||
.align_gz = &align_gz,
|
||||
.ret_ref = ret_ref,
|
||||
.ret_gz = &ret_gz,
|
||||
.section_ref = section_ref,
|
||||
.section_gz = §ion_gz,
|
||||
.addrspace_ref = addrspace_ref,
|
||||
.addrspace_gz = &addrspace_gz,
|
||||
.lbrace_line = lbrace_line,
|
||||
.lbrace_column = lbrace_column,
|
||||
.param_block = block_inst,
|
||||
.ret_gz = &ret_gz,
|
||||
.ret_br = ret_br,
|
||||
.body_gz = &fn_gz,
|
||||
.cc = cc,
|
||||
.align_inst = align_inst,
|
||||
.lib_name = lib_name,
|
||||
.is_var_args = is_var_args,
|
||||
.is_inferred_error = is_inferred_error,
|
||||
@ -3582,10 +3643,6 @@ fn fnDecl(
|
||||
wip_members.appendToDecl(fn_name_str_index);
|
||||
wip_members.appendToDecl(block_inst);
|
||||
wip_members.appendToDecl(doc_comment_index);
|
||||
if (has_section_or_addrspace) {
|
||||
wip_members.appendToDecl(@enumToInt(section_inst));
|
||||
wip_members.appendToDecl(@enumToInt(addrspace_inst));
|
||||
}
|
||||
}
|
||||
|
||||
fn globalVarDecl(
|
||||
@ -3979,14 +4036,22 @@ fn testDecl(
|
||||
|
||||
const func_inst = try decl_block.addFunc(.{
|
||||
.src_node = node,
|
||||
|
||||
.cc_ref = .none,
|
||||
.cc_gz = null,
|
||||
.align_ref = .none,
|
||||
.align_gz = null,
|
||||
.ret_ref = .void_type,
|
||||
.ret_gz = null,
|
||||
.section_ref = .none,
|
||||
.section_gz = null,
|
||||
.addrspace_ref = .none,
|
||||
.addrspace_gz = null,
|
||||
|
||||
.lbrace_line = lbrace_line,
|
||||
.lbrace_column = lbrace_column,
|
||||
.param_block = block_inst,
|
||||
.ret_gz = null,
|
||||
.ret_br = 0,
|
||||
.body_gz = &fn_block,
|
||||
.cc = .none,
|
||||
.align_inst = .none,
|
||||
.lib_name = 0,
|
||||
.is_var_args = false,
|
||||
.is_inferred_error = true,
|
||||
@ -9930,17 +9995,34 @@ const GenZir = struct {
|
||||
gz.unstack();
|
||||
}
|
||||
|
||||
/// Supports `body_gz` stacked on `ret_gz` stacked on `gz`. Unstacks `body_gz` and `ret_gz`.
|
||||
/// Must be called with the following stack set up:
|
||||
/// * gz (bottom)
|
||||
/// * align_gz
|
||||
/// * addrspace_gz
|
||||
/// * section_gz
|
||||
/// * cc_gz
|
||||
/// * ret_gz
|
||||
/// * body_gz (top)
|
||||
/// Unstacks all of those except for `gz`.
|
||||
fn addFunc(gz: *GenZir, args: struct {
|
||||
src_node: Ast.Node.Index,
|
||||
lbrace_line: u32 = 0,
|
||||
lbrace_column: u32 = 0,
|
||||
body_gz: ?*GenZir,
|
||||
param_block: Zir.Inst.Index,
|
||||
|
||||
align_gz: ?*GenZir,
|
||||
addrspace_gz: ?*GenZir,
|
||||
section_gz: ?*GenZir,
|
||||
cc_gz: ?*GenZir,
|
||||
ret_gz: ?*GenZir,
|
||||
ret_br: Zir.Inst.Index,
|
||||
cc: Zir.Inst.Ref,
|
||||
align_inst: Zir.Inst.Ref,
|
||||
body_gz: ?*GenZir,
|
||||
|
||||
align_ref: Zir.Inst.Ref,
|
||||
addrspace_ref: Zir.Inst.Ref,
|
||||
section_ref: Zir.Inst.Ref,
|
||||
cc_ref: Zir.Inst.Ref,
|
||||
ret_ref: Zir.Inst.Ref,
|
||||
|
||||
lib_name: u32,
|
||||
is_var_args: bool,
|
||||
is_inferred_error: bool,
|
||||
@ -9950,11 +10032,13 @@ const GenZir = struct {
|
||||
assert(args.src_node != 0);
|
||||
const astgen = gz.astgen;
|
||||
const gpa = astgen.gpa;
|
||||
const ret_ref = if (args.ret_ref == .void_type) .none else args.ret_ref;
|
||||
const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len);
|
||||
|
||||
try astgen.instructions.ensureUnusedCapacity(gpa, 1);
|
||||
|
||||
var body: []Zir.Inst.Index = &[0]Zir.Inst.Index{};
|
||||
var ret_ty: []Zir.Inst.Index = &[0]Zir.Inst.Index{};
|
||||
var ret_body: []Zir.Inst.Index = &[0]Zir.Inst.Index{};
|
||||
var src_locs_buffer: [3]u32 = undefined;
|
||||
var src_locs: []u32 = src_locs_buffer[0..0];
|
||||
if (args.body_gz) |body_gz| {
|
||||
@ -9978,61 +10062,120 @@ const GenZir = struct {
|
||||
|
||||
body = body_gz.instructionsSlice();
|
||||
if (args.ret_gz) |ret_gz|
|
||||
ret_ty = ret_gz.instructionsSliceUpto(body_gz);
|
||||
ret_body = ret_gz.instructionsSliceUpto(body_gz);
|
||||
} else {
|
||||
if (args.ret_gz) |ret_gz|
|
||||
ret_ty = ret_gz.instructionsSlice();
|
||||
ret_body = ret_gz.instructionsSlice();
|
||||
}
|
||||
|
||||
if (args.cc != .none or args.lib_name != 0 or
|
||||
args.is_var_args or args.is_test or args.align_inst != .none or
|
||||
args.is_extern)
|
||||
if (args.cc_ref != .none or args.lib_name != 0 or
|
||||
args.is_var_args or args.is_test or args.is_extern or
|
||||
args.align_ref != .none or args.section_ref != .none or
|
||||
args.addrspace_ref != .none)
|
||||
{
|
||||
var align_body: []Zir.Inst.Index = &.{};
|
||||
var addrspace_body: []Zir.Inst.Index = &.{};
|
||||
var section_body: []Zir.Inst.Index = &.{};
|
||||
var cc_body: []Zir.Inst.Index = &.{};
|
||||
if (args.ret_gz != null) {
|
||||
align_body = args.align_gz.?.instructionsSliceUpto(args.addrspace_gz.?);
|
||||
addrspace_body = args.addrspace_gz.?.instructionsSliceUpto(args.section_gz.?);
|
||||
section_body = args.section_gz.?.instructionsSliceUpto(args.cc_gz.?);
|
||||
cc_body = args.cc_gz.?.instructionsSliceUpto(args.ret_gz.?);
|
||||
}
|
||||
|
||||
try astgen.extra.ensureUnusedCapacity(
|
||||
gpa,
|
||||
@typeInfo(Zir.Inst.ExtendedFunc).Struct.fields.len +
|
||||
ret_ty.len + body.len + src_locs.len +
|
||||
@boolToInt(args.lib_name != 0) +
|
||||
@boolToInt(args.align_inst != .none) +
|
||||
@boolToInt(args.cc != .none),
|
||||
@typeInfo(Zir.Inst.FuncFancy).Struct.fields.len +
|
||||
fancyFnExprExtraLen(align_body, args.align_ref) +
|
||||
fancyFnExprExtraLen(addrspace_body, args.addrspace_ref) +
|
||||
fancyFnExprExtraLen(section_body, args.section_ref) +
|
||||
fancyFnExprExtraLen(cc_body, args.cc_ref) +
|
||||
fancyFnExprExtraLen(ret_body, ret_ref) +
|
||||
body.len + src_locs.len +
|
||||
@boolToInt(args.lib_name != 0),
|
||||
);
|
||||
const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.ExtendedFunc{
|
||||
const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.FuncFancy{
|
||||
.param_block = args.param_block,
|
||||
.ret_body_len = @intCast(u32, ret_ty.len),
|
||||
.body_len = @intCast(u32, body.len),
|
||||
.bits = .{
|
||||
.is_var_args = args.is_var_args,
|
||||
.is_inferred_error = args.is_inferred_error,
|
||||
.has_lib_name = args.lib_name != 0,
|
||||
.has_cc = args.cc != .none,
|
||||
.has_align = args.align_inst != .none,
|
||||
.is_test = args.is_test,
|
||||
.is_extern = args.is_extern,
|
||||
.has_lib_name = args.lib_name != 0,
|
||||
|
||||
.has_align_ref = args.align_ref != .none,
|
||||
.has_addrspace_ref = args.addrspace_ref != .none,
|
||||
.has_section_ref = args.section_ref != .none,
|
||||
.has_cc_ref = args.cc_ref != .none,
|
||||
.has_ret_ty_ref = ret_ref != .none,
|
||||
|
||||
.has_align_body = align_body.len != 0,
|
||||
.has_addrspace_body = addrspace_body.len != 0,
|
||||
.has_section_body = section_body.len != 0,
|
||||
.has_cc_body = cc_body.len != 0,
|
||||
.has_ret_ty_body = ret_body.len != 0,
|
||||
},
|
||||
});
|
||||
if (args.lib_name != 0) {
|
||||
astgen.extra.appendAssumeCapacity(args.lib_name);
|
||||
}
|
||||
if (args.cc != .none) {
|
||||
astgen.extra.appendAssumeCapacity(@enumToInt(args.cc));
|
||||
|
||||
const zir_datas = astgen.instructions.items(.data);
|
||||
if (align_body.len != 0) {
|
||||
astgen.extra.appendAssumeCapacity(@intCast(u32, align_body.len));
|
||||
astgen.extra.appendSliceAssumeCapacity(align_body);
|
||||
zir_datas[align_body[align_body.len - 1]].@"break".block_inst = new_index;
|
||||
} else if (args.align_ref != .none) {
|
||||
astgen.extra.appendAssumeCapacity(@enumToInt(args.align_ref));
|
||||
}
|
||||
if (args.align_inst != .none) {
|
||||
astgen.extra.appendAssumeCapacity(@enumToInt(args.align_inst));
|
||||
if (addrspace_body.len != 0) {
|
||||
astgen.extra.appendAssumeCapacity(@intCast(u32, addrspace_body.len));
|
||||
astgen.extra.appendSliceAssumeCapacity(addrspace_body);
|
||||
zir_datas[addrspace_body[addrspace_body.len - 1]].@"break".block_inst = new_index;
|
||||
} else if (args.addrspace_ref != .none) {
|
||||
astgen.extra.appendAssumeCapacity(@enumToInt(args.addrspace_ref));
|
||||
}
|
||||
astgen.extra.appendSliceAssumeCapacity(ret_ty);
|
||||
if (section_body.len != 0) {
|
||||
astgen.extra.appendAssumeCapacity(@intCast(u32, section_body.len));
|
||||
astgen.extra.appendSliceAssumeCapacity(section_body);
|
||||
zir_datas[section_body[section_body.len - 1]].@"break".block_inst = new_index;
|
||||
} else if (args.section_ref != .none) {
|
||||
astgen.extra.appendAssumeCapacity(@enumToInt(args.section_ref));
|
||||
}
|
||||
if (cc_body.len != 0) {
|
||||
astgen.extra.appendAssumeCapacity(@intCast(u32, cc_body.len));
|
||||
astgen.extra.appendSliceAssumeCapacity(cc_body);
|
||||
zir_datas[cc_body[cc_body.len - 1]].@"break".block_inst = new_index;
|
||||
} else if (args.cc_ref != .none) {
|
||||
astgen.extra.appendAssumeCapacity(@enumToInt(args.cc_ref));
|
||||
}
|
||||
if (ret_body.len != 0) {
|
||||
astgen.extra.appendAssumeCapacity(@intCast(u32, ret_body.len));
|
||||
astgen.extra.appendSliceAssumeCapacity(ret_body);
|
||||
zir_datas[ret_body[ret_body.len - 1]].@"break".block_inst = new_index;
|
||||
} else if (ret_ref != .none) {
|
||||
astgen.extra.appendAssumeCapacity(@enumToInt(ret_ref));
|
||||
}
|
||||
|
||||
astgen.extra.appendSliceAssumeCapacity(body);
|
||||
astgen.extra.appendSliceAssumeCapacity(src_locs);
|
||||
// order is important when unstacking
|
||||
|
||||
// Order is important when unstacking.
|
||||
if (args.body_gz) |body_gz| body_gz.unstack();
|
||||
if (args.ret_gz) |ret_gz| ret_gz.unstack();
|
||||
if (args.ret_gz != null) {
|
||||
args.ret_gz.?.unstack();
|
||||
args.cc_gz.?.unstack();
|
||||
args.section_gz.?.unstack();
|
||||
args.addrspace_gz.?.unstack();
|
||||
args.align_gz.?.unstack();
|
||||
}
|
||||
|
||||
try gz.instructions.ensureUnusedCapacity(gpa, 1);
|
||||
|
||||
const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len);
|
||||
if (args.ret_br != 0) {
|
||||
astgen.instructions.items(.data)[args.ret_br].@"break".block_inst = new_index;
|
||||
}
|
||||
astgen.instructions.appendAssumeCapacity(.{
|
||||
.tag = .func_extended,
|
||||
.tag = .func_fancy,
|
||||
.data = .{ .pl_node = .{
|
||||
.src_node = gz.nodeIndexToRelative(args.src_node),
|
||||
.payload_index = payload_index,
|
||||
@ -10044,27 +10187,40 @@ const GenZir = struct {
|
||||
try astgen.extra.ensureUnusedCapacity(
|
||||
gpa,
|
||||
@typeInfo(Zir.Inst.Func).Struct.fields.len +
|
||||
ret_ty.len + body.len + src_locs.len,
|
||||
@maximum(ret_body.len, @boolToInt(ret_ref != .none)) +
|
||||
body.len + src_locs.len,
|
||||
);
|
||||
const ret_body_len = if (ret_body.len != 0)
|
||||
@intCast(u32, ret_body.len)
|
||||
else
|
||||
@boolToInt(ret_ref != .none);
|
||||
|
||||
const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.Func{
|
||||
.param_block = args.param_block,
|
||||
.ret_body_len = @intCast(u32, ret_ty.len),
|
||||
.ret_body_len = ret_body_len,
|
||||
.body_len = @intCast(u32, body.len),
|
||||
});
|
||||
astgen.extra.appendSliceAssumeCapacity(ret_ty);
|
||||
const zir_datas = astgen.instructions.items(.data);
|
||||
if (ret_body.len != 0) {
|
||||
astgen.extra.appendSliceAssumeCapacity(ret_body);
|
||||
zir_datas[ret_body[ret_body.len - 1]].@"break".block_inst = new_index;
|
||||
} else if (ret_ref != .none) {
|
||||
astgen.extra.appendAssumeCapacity(@enumToInt(ret_ref));
|
||||
}
|
||||
astgen.extra.appendSliceAssumeCapacity(body);
|
||||
astgen.extra.appendSliceAssumeCapacity(src_locs);
|
||||
// order is important when unstacking
|
||||
|
||||
// Order is important when unstacking.
|
||||
if (args.body_gz) |body_gz| body_gz.unstack();
|
||||
if (args.ret_gz) |ret_gz| ret_gz.unstack();
|
||||
if (args.cc_gz) |cc_gz| cc_gz.unstack();
|
||||
if (args.section_gz) |section_gz| section_gz.unstack();
|
||||
if (args.addrspace_gz) |addrspace_gz| addrspace_gz.unstack();
|
||||
if (args.align_gz) |align_gz| align_gz.unstack();
|
||||
|
||||
try gz.instructions.ensureUnusedCapacity(gpa, 1);
|
||||
|
||||
const tag: Zir.Inst.Tag = if (args.is_inferred_error) .func_inferred else .func;
|
||||
const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len);
|
||||
if (args.ret_br != 0) {
|
||||
astgen.instructions.items(.data)[args.ret_br].@"break".block_inst = new_index;
|
||||
}
|
||||
astgen.instructions.appendAssumeCapacity(.{
|
||||
.tag = tag,
|
||||
.data = .{ .pl_node = .{
|
||||
@ -10077,6 +10233,12 @@ const GenZir = struct {
|
||||
}
|
||||
}
|
||||
|
||||
fn fancyFnExprExtraLen(body: []Zir.Inst.Index, ref: Zir.Inst.Ref) usize {
|
||||
// In the case of non-empty body, there is one for the body length,
|
||||
// and then one for each instruction.
|
||||
return body.len + @boolToInt(ref != .none);
|
||||
}
|
||||
|
||||
fn addVar(gz: *GenZir, args: struct {
|
||||
align_inst: Zir.Inst.Ref,
|
||||
lib_name: u32,
|
||||
|
||||
@ -1595,9 +1595,9 @@ pub const Fn = struct {
|
||||
switch (zir_tags[func.zir_body_inst]) {
|
||||
.func => return false,
|
||||
.func_inferred => return true,
|
||||
.func_extended => {
|
||||
.func_fancy => {
|
||||
const inst_data = zir.instructions.items(.data)[func.zir_body_inst].pl_node;
|
||||
const extra = zir.extraData(Zir.Inst.ExtendedFunc, inst_data.payload_index);
|
||||
const extra = zir.extraData(Zir.Inst.FuncFancy, inst_data.payload_index);
|
||||
return extra.data.bits.is_inferred_error;
|
||||
},
|
||||
else => unreachable,
|
||||
|
||||
343
src/Sema.zig
343
src/Sema.zig
@ -747,7 +747,7 @@ fn analyzeBodyInner(
|
||||
.field_call_bind => try sema.zirFieldCallBind(block, inst),
|
||||
.func => try sema.zirFunc(block, inst, false),
|
||||
.func_inferred => try sema.zirFunc(block, inst, true),
|
||||
.func_extended => try sema.zirFuncExtended(block, inst),
|
||||
.func_fancy => try sema.zirFuncFancy(block, inst),
|
||||
.import => try sema.zirImport(block, inst),
|
||||
.indexable_ptr_len => try sema.zirIndexablePtrLen(block, inst),
|
||||
.int => try sema.zirInt(block, inst),
|
||||
@ -5190,7 +5190,10 @@ fn analyzeCall(
|
||||
// on parameters, we must now do the same for the return type as we just did with
|
||||
// each of the parameters, resolving the return type and providing it to the child
|
||||
// `Sema` so that it can be used for the `ret_ptr` instruction.
|
||||
const ret_ty_inst = try sema.resolveBody(&child_block, fn_info.ret_ty_body, module_fn.zir_body_inst);
|
||||
const ret_ty_inst = if (fn_info.ret_ty_body.len != 0)
|
||||
try sema.resolveBody(&child_block, fn_info.ret_ty_body, module_fn.zir_body_inst)
|
||||
else
|
||||
try sema.resolveInst(fn_info.ret_ty_ref);
|
||||
const ret_ty_src = func_src; // TODO better source location
|
||||
const bare_return_type = try sema.analyzeAsType(&child_block, ret_ty_src, ret_ty_inst);
|
||||
// Create a fresh inferred error set type for inline/comptime calls.
|
||||
@ -6506,9 +6509,34 @@ fn zirFunc(
|
||||
|
||||
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
|
||||
const extra = sema.code.extraData(Zir.Inst.Func, inst_data.payload_index);
|
||||
const target = sema.mod.getTarget();
|
||||
const ret_ty_src = inst_data.src(); // TODO better source location
|
||||
|
||||
var extra_index = extra.end;
|
||||
const ret_ty_body = sema.code.extra[extra_index..][0..extra.data.ret_body_len];
|
||||
extra_index += ret_ty_body.len;
|
||||
|
||||
const ret_ty: Type = switch (extra.data.ret_body_len) {
|
||||
0 => Type.void,
|
||||
1 => blk: {
|
||||
const ret_ty_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
|
||||
extra_index += 1;
|
||||
if (sema.resolveType(block, ret_ty_src, ret_ty_ref)) |ret_ty| {
|
||||
break :blk ret_ty;
|
||||
} else |err| switch (err) {
|
||||
error.GenericPoison => {
|
||||
break :blk Type.initTag(.generic_poison);
|
||||
},
|
||||
else => |e| return e,
|
||||
}
|
||||
},
|
||||
else => blk: {
|
||||
const ret_ty_body = sema.code.extra[extra_index..][0..extra.data.ret_body_len];
|
||||
extra_index += ret_ty_body.len;
|
||||
|
||||
const ret_ty_val = try sema.resolveGenericBody(block, ret_ty_src, ret_ty_body, inst, Type.type);
|
||||
var buffer: Value.ToTypeBuffer = undefined;
|
||||
break :blk try ret_ty_val.toType(&buffer).copy(sema.arena);
|
||||
},
|
||||
};
|
||||
|
||||
var src_locs: Zir.Inst.Func.SrcLocs = undefined;
|
||||
const has_body = extra.data.body_len != 0;
|
||||
@ -6526,9 +6554,11 @@ fn zirFunc(
|
||||
block,
|
||||
inst_data.src_node,
|
||||
inst,
|
||||
ret_ty_body,
|
||||
0,
|
||||
target_util.defaultAddressSpace(target, .function),
|
||||
FuncLinkSection.default,
|
||||
cc,
|
||||
Value.@"null",
|
||||
ret_ty,
|
||||
false,
|
||||
inferred_error_set,
|
||||
false,
|
||||
@ -6538,6 +6568,44 @@ fn zirFunc(
|
||||
);
|
||||
}
|
||||
|
||||
// TODO this function and its callsites along with funcCommon need to be reworked
|
||||
// to handle when callconv, align, linksection, addrspace depend on comptime values
|
||||
// (thus triggering error.GenericPoison)
|
||||
fn resolveGenericBody(
|
||||
sema: *Sema,
|
||||
block: *Block,
|
||||
src: LazySrcLoc,
|
||||
body: []const Zir.Inst.Index,
|
||||
func_inst: Zir.Inst.Index,
|
||||
dest_ty: Type,
|
||||
) !Value {
|
||||
assert(body.len != 0);
|
||||
|
||||
const err = err: {
|
||||
// Make sure any nested param instructions don't clobber our work.
|
||||
const prev_params = block.params;
|
||||
block.params = .{};
|
||||
defer {
|
||||
block.params.deinit(sema.gpa);
|
||||
block.params = prev_params;
|
||||
}
|
||||
const uncasted = sema.resolveBody(block, body, func_inst) catch |err| break :err err;
|
||||
const result = sema.coerce(block, dest_ty, uncasted, src) catch |err| break :err err;
|
||||
const val = sema.resolveConstValue(block, src, result) catch |err| break :err err;
|
||||
return val;
|
||||
};
|
||||
switch (err) {
|
||||
error.GenericPoison => {
|
||||
if (dest_ty.tag() == .type) {
|
||||
return Value.initTag(.generic_poison_type);
|
||||
} else {
|
||||
return Value.initTag(.generic_poison);
|
||||
}
|
||||
},
|
||||
else => |e| return e,
|
||||
}
|
||||
}
|
||||
|
||||
/// Given a library name, examines if the library name should end up in
|
||||
/// `link.File.Options.system_libs` table (for example, libc is always
|
||||
/// specified via dedicated flag `link.File.Options.link_libc` instead),
|
||||
@ -6601,14 +6669,27 @@ fn handleExternLibName(
|
||||
return sema.gpa.dupeZ(u8, lib_name);
|
||||
}
|
||||
|
||||
const FuncLinkSection = union(enum) {
|
||||
generic,
|
||||
default,
|
||||
explicit: [*:0]const u8,
|
||||
};
|
||||
|
||||
fn funcCommon(
|
||||
sema: *Sema,
|
||||
block: *Block,
|
||||
src_node_offset: i32,
|
||||
func_inst: Zir.Inst.Index,
|
||||
ret_ty_body: []const Zir.Inst.Index,
|
||||
cc: std.builtin.CallingConvention,
|
||||
align_val: Value,
|
||||
/// null means generic poison
|
||||
alignment: ?u32,
|
||||
/// null means generic poison
|
||||
address_space: ?std.builtin.AddressSpace,
|
||||
/// outer null means generic poison; inner null means default link section
|
||||
section: FuncLinkSection,
|
||||
/// null means generic poison
|
||||
cc: ?std.builtin.CallingConvention,
|
||||
/// this might be Type.generic_poison
|
||||
bare_return_type: Type,
|
||||
var_args: bool,
|
||||
inferred_error_set: bool,
|
||||
is_extern: bool,
|
||||
@ -6618,42 +6699,15 @@ fn funcCommon(
|
||||
) CompileError!Air.Inst.Ref {
|
||||
const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset };
|
||||
|
||||
// The return type body might be a type expression that depends on generic parameters.
|
||||
// In such case we need to use a generic_poison value for the return type and mark
|
||||
// the function as generic.
|
||||
var is_generic = false;
|
||||
const bare_return_type: Type = ret_ty: {
|
||||
if (ret_ty_body.len == 0) break :ret_ty Type.void;
|
||||
|
||||
const err = err: {
|
||||
// Make sure any nested param instructions don't clobber our work.
|
||||
const prev_params = block.params;
|
||||
block.params = .{};
|
||||
defer {
|
||||
block.params.deinit(sema.gpa);
|
||||
block.params = prev_params;
|
||||
}
|
||||
if (sema.resolveBody(block, ret_ty_body, func_inst)) |ret_ty_inst| {
|
||||
if (sema.analyzeAsType(block, ret_ty_src, ret_ty_inst)) |ret_ty| {
|
||||
break :ret_ty ret_ty;
|
||||
} else |err| break :err err;
|
||||
} else |err| break :err err;
|
||||
// Check for generic params.
|
||||
for (block.params.items) |param| {
|
||||
if (param.ty.tag() == .generic_poison) is_generic = true;
|
||||
}
|
||||
};
|
||||
switch (err) {
|
||||
error.GenericPoison => {
|
||||
// The type is not available until the generic instantiation.
|
||||
is_generic = true;
|
||||
break :ret_ty Type.initTag(.generic_poison);
|
||||
},
|
||||
else => |e| return e,
|
||||
}
|
||||
};
|
||||
|
||||
const mod = sema.mod;
|
||||
var is_generic = bare_return_type.tag() == .generic_poison or
|
||||
alignment == null or
|
||||
address_space == null or
|
||||
section == .generic or
|
||||
cc == null;
|
||||
// Check for generic params.
|
||||
for (block.params.items) |param| {
|
||||
if (param.ty.tag() == .generic_poison) is_generic = true;
|
||||
}
|
||||
|
||||
const new_func: *Module.Fn = new_func: {
|
||||
if (!has_body) break :new_func undefined;
|
||||
@ -6670,36 +6724,28 @@ fn funcCommon(
|
||||
errdefer if (maybe_inferred_error_set_node) |node| sema.gpa.destroy(node);
|
||||
// Note: no need to errdefer since this will still be in its default state at the end of the function.
|
||||
|
||||
const target = mod.getTarget();
|
||||
|
||||
const target = sema.mod.getTarget();
|
||||
const fn_ty: Type = fn_ty: {
|
||||
const alignment: u32 = if (align_val.tag() == .null_value) 0 else a: {
|
||||
const alignment = @intCast(u32, align_val.toUnsignedInt(target));
|
||||
if (alignment == target_util.defaultFunctionAlignment(target)) {
|
||||
break :a 0;
|
||||
} else {
|
||||
break :a alignment;
|
||||
}
|
||||
};
|
||||
|
||||
// Hot path for some common function types.
|
||||
// TODO can we eliminate some of these Type tag values? seems unnecessarily complicated.
|
||||
if (!is_generic and block.params.items.len == 0 and !var_args and
|
||||
alignment == 0 and !inferred_error_set)
|
||||
if (!is_generic and block.params.items.len == 0 and !var_args and !inferred_error_set and
|
||||
alignment.? == 0 and
|
||||
address_space.? == target_util.defaultAddressSpace(target, .function) and
|
||||
section == .default)
|
||||
{
|
||||
if (bare_return_type.zigTypeTag() == .NoReturn and cc == .Unspecified) {
|
||||
if (bare_return_type.zigTypeTag() == .NoReturn and cc.? == .Unspecified) {
|
||||
break :fn_ty Type.initTag(.fn_noreturn_no_args);
|
||||
}
|
||||
|
||||
if (bare_return_type.zigTypeTag() == .Void and cc == .Unspecified) {
|
||||
if (bare_return_type.zigTypeTag() == .Void and cc.? == .Unspecified) {
|
||||
break :fn_ty Type.initTag(.fn_void_no_args);
|
||||
}
|
||||
|
||||
if (bare_return_type.zigTypeTag() == .NoReturn and cc == .Naked) {
|
||||
if (bare_return_type.zigTypeTag() == .NoReturn and cc.? == .Naked) {
|
||||
break :fn_ty Type.initTag(.fn_naked_noreturn_no_args);
|
||||
}
|
||||
|
||||
if (bare_return_type.zigTypeTag() == .Void and cc == .C) {
|
||||
if (bare_return_type.zigTypeTag() == .Void and cc.? == .C) {
|
||||
break :fn_ty Type.initTag(.fn_ccc_void_no_args);
|
||||
}
|
||||
}
|
||||
@ -6745,17 +6791,35 @@ fn funcCommon(
|
||||
});
|
||||
};
|
||||
|
||||
// stage1 bug workaround
|
||||
const cc_workaround = cc orelse undefined;
|
||||
const align_workaround = alignment orelse @as(u32, undefined);
|
||||
|
||||
break :fn_ty try Type.Tag.function.create(sema.arena, .{
|
||||
.param_types = param_types,
|
||||
.comptime_params = comptime_params.ptr,
|
||||
.return_type = return_type,
|
||||
.cc = cc,
|
||||
.alignment = alignment,
|
||||
.cc = cc_workaround,
|
||||
.cc_is_generic = cc == null,
|
||||
.alignment = align_workaround,
|
||||
.align_is_generic = alignment == null,
|
||||
.section_is_generic = section == .generic,
|
||||
.addrspace_is_generic = address_space == null,
|
||||
.is_var_args = var_args,
|
||||
.is_generic = is_generic,
|
||||
});
|
||||
};
|
||||
|
||||
if (sema.owner_decl.owns_tv) {
|
||||
switch (section) {
|
||||
.generic => sema.owner_decl.@"linksection" = undefined,
|
||||
.default => sema.owner_decl.@"linksection" = null,
|
||||
.explicit => |s| sema.owner_decl.@"linksection" = s,
|
||||
}
|
||||
if (alignment) |a| sema.owner_decl.@"align" = a;
|
||||
if (address_space) |a| sema.owner_decl.@"addrspace" = a;
|
||||
}
|
||||
|
||||
if (is_extern) {
|
||||
const new_extern_fn = try sema.gpa.create(Module.ExternFn);
|
||||
errdefer sema.gpa.destroy(new_extern_fn);
|
||||
@ -16750,16 +16814,20 @@ fn zirVarExtended(
|
||||
return result;
|
||||
}
|
||||
|
||||
fn zirFuncExtended(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
|
||||
fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
|
||||
const src = inst_data.src();
|
||||
const extra = sema.code.extraData(Zir.Inst.ExtendedFunc, inst_data.payload_index);
|
||||
const extra = sema.code.extraData(Zir.Inst.FuncFancy, inst_data.payload_index);
|
||||
const target = sema.mod.getTarget();
|
||||
|
||||
const cc_src: LazySrcLoc = .{ .node_offset_fn_type_cc = inst_data.src_node };
|
||||
const align_src: LazySrcLoc = src; // TODO add a LazySrcLoc that points at align
|
||||
const addrspace_src: LazySrcLoc = src; // TODO add a LazySrcLoc that points at addrspace
|
||||
const section_src: LazySrcLoc = src; // TODO add a LazySrcLoc that points at section
|
||||
const cc_src: LazySrcLoc = .{ .node_offset_fn_type_cc = inst_data.src_node };
|
||||
const ret_src: LazySrcLoc = src; // TODO add a LazySrcLoc that points at the return type
|
||||
|
||||
var extra_index: usize = extra.end;
|
||||
|
||||
@ -16769,22 +16837,135 @@ fn zirFuncExtended(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
|
||||
break :blk lib_name;
|
||||
} else null;
|
||||
|
||||
const cc: std.builtin.CallingConvention = if (extra.data.bits.has_cc) blk: {
|
||||
const cc_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
|
||||
const @"align": ?u32 = if (extra.data.bits.has_align_body) blk: {
|
||||
const body_len = sema.code.extra[extra_index];
|
||||
extra_index += 1;
|
||||
const cc_tv = try sema.resolveInstConst(block, cc_src, cc_ref);
|
||||
break :blk cc_tv.val.toEnum(std.builtin.CallingConvention);
|
||||
} else .Unspecified;
|
||||
const body = sema.code.extra[extra_index..][0..body_len];
|
||||
extra_index += body.len;
|
||||
|
||||
const align_val: Value = if (extra.data.bits.has_align) blk: {
|
||||
const val = try sema.resolveGenericBody(block, align_src, body, inst, Type.u16);
|
||||
if (val.tag() == .generic_poison) {
|
||||
break :blk null;
|
||||
}
|
||||
const alignment = @intCast(u32, val.toUnsignedInt(target));
|
||||
if (alignment == target_util.defaultFunctionAlignment(target)) {
|
||||
break :blk 0;
|
||||
} else {
|
||||
break :blk alignment;
|
||||
}
|
||||
} else if (extra.data.bits.has_align_ref) blk: {
|
||||
const align_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
|
||||
extra_index += 1;
|
||||
const align_tv = try sema.resolveInstConst(block, align_src, align_ref);
|
||||
break :blk align_tv.val;
|
||||
} else Value.@"null";
|
||||
const align_tv = sema.resolveInstConst(block, align_src, align_ref) catch |err| switch (err) {
|
||||
error.GenericPoison => {
|
||||
break :blk null;
|
||||
},
|
||||
else => |e| return e,
|
||||
};
|
||||
const alignment = @intCast(u32, align_tv.val.toUnsignedInt(target));
|
||||
if (alignment == target_util.defaultFunctionAlignment(target)) {
|
||||
break :blk 0;
|
||||
} else {
|
||||
break :blk alignment;
|
||||
}
|
||||
} else 0;
|
||||
|
||||
const ret_ty_body = sema.code.extra[extra_index..][0..extra.data.ret_body_len];
|
||||
extra_index += ret_ty_body.len;
|
||||
const @"addrspace": ?std.builtin.AddressSpace = if (extra.data.bits.has_addrspace_body) blk: {
|
||||
const body_len = sema.code.extra[extra_index];
|
||||
extra_index += 1;
|
||||
const body = sema.code.extra[extra_index..][0..body_len];
|
||||
extra_index += body.len;
|
||||
|
||||
const addrspace_ty = try sema.getBuiltinType(block, addrspace_src, "AddressSpace");
|
||||
const val = try sema.resolveGenericBody(block, addrspace_src, body, inst, addrspace_ty);
|
||||
if (val.tag() == .generic_poison) {
|
||||
break :blk null;
|
||||
}
|
||||
break :blk val.toEnum(std.builtin.AddressSpace);
|
||||
} else if (extra.data.bits.has_addrspace_ref) blk: {
|
||||
const addrspace_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
|
||||
extra_index += 1;
|
||||
const addrspace_tv = sema.resolveInstConst(block, addrspace_src, addrspace_ref) catch |err| switch (err) {
|
||||
error.GenericPoison => {
|
||||
break :blk null;
|
||||
},
|
||||
else => |e| return e,
|
||||
};
|
||||
break :blk addrspace_tv.val.toEnum(std.builtin.AddressSpace);
|
||||
} else target_util.defaultAddressSpace(target, .function);
|
||||
|
||||
const @"linksection": FuncLinkSection = if (extra.data.bits.has_section_body) blk: {
|
||||
const body_len = sema.code.extra[extra_index];
|
||||
extra_index += 1;
|
||||
const body = sema.code.extra[extra_index..][0..body_len];
|
||||
extra_index += body.len;
|
||||
|
||||
const val = try sema.resolveGenericBody(block, section_src, body, inst, Type.initTag(.const_slice_u8));
|
||||
if (val.tag() == .generic_poison) {
|
||||
break :blk FuncLinkSection{ .generic = {} };
|
||||
}
|
||||
_ = val;
|
||||
return sema.fail(block, section_src, "TODO implement linksection on functions", .{});
|
||||
} else if (extra.data.bits.has_section_ref) blk: {
|
||||
const section_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
|
||||
extra_index += 1;
|
||||
const section_tv = sema.resolveInstConst(block, section_src, section_ref) catch |err| switch (err) {
|
||||
error.GenericPoison => {
|
||||
break :blk FuncLinkSection{ .generic = {} };
|
||||
},
|
||||
else => |e| return e,
|
||||
};
|
||||
_ = section_tv;
|
||||
return sema.fail(block, section_src, "TODO implement linksection on functions", .{});
|
||||
} else FuncLinkSection{ .default = {} };
|
||||
|
||||
const cc: ?std.builtin.CallingConvention = if (extra.data.bits.has_cc_body) blk: {
|
||||
const body_len = sema.code.extra[extra_index];
|
||||
extra_index += 1;
|
||||
const body = sema.code.extra[extra_index..][0..body_len];
|
||||
extra_index += body.len;
|
||||
|
||||
const cc_ty = try sema.getBuiltinType(block, addrspace_src, "CallingConvention");
|
||||
const val = try sema.resolveGenericBody(block, cc_src, body, inst, cc_ty);
|
||||
if (val.tag() == .generic_poison) {
|
||||
break :blk null;
|
||||
}
|
||||
break :blk val.toEnum(std.builtin.CallingConvention);
|
||||
} else if (extra.data.bits.has_cc_ref) blk: {
|
||||
const cc_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
|
||||
extra_index += 1;
|
||||
const cc_tv = sema.resolveInstConst(block, cc_src, cc_ref) catch |err| switch (err) {
|
||||
error.GenericPoison => {
|
||||
break :blk null;
|
||||
},
|
||||
else => |e| return e,
|
||||
};
|
||||
break :blk cc_tv.val.toEnum(std.builtin.CallingConvention);
|
||||
} else std.builtin.CallingConvention.Unspecified;
|
||||
|
||||
const ret_ty: Type = if (extra.data.bits.has_ret_ty_body) blk: {
|
||||
const body_len = sema.code.extra[extra_index];
|
||||
extra_index += 1;
|
||||
const body = sema.code.extra[extra_index..][0..body_len];
|
||||
extra_index += body.len;
|
||||
|
||||
const val = try sema.resolveGenericBody(block, ret_src, body, inst, Type.type);
|
||||
var buffer: Value.ToTypeBuffer = undefined;
|
||||
const ty = try val.toType(&buffer).copy(sema.arena);
|
||||
break :blk ty;
|
||||
} else if (extra.data.bits.has_ret_ty_ref) blk: {
|
||||
const ret_ty_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
|
||||
extra_index += 1;
|
||||
const ret_ty_tv = sema.resolveInstConst(block, ret_src, ret_ty_ref) catch |err| switch (err) {
|
||||
error.GenericPoison => {
|
||||
break :blk Type.initTag(.generic_poison);
|
||||
},
|
||||
else => |e| return e,
|
||||
};
|
||||
var buffer: Value.ToTypeBuffer = undefined;
|
||||
const ty = try ret_ty_tv.val.toType(&buffer).copy(sema.arena);
|
||||
break :blk ty;
|
||||
} else Type.void;
|
||||
|
||||
var src_locs: Zir.Inst.Func.SrcLocs = undefined;
|
||||
const has_body = extra.data.body_len != 0;
|
||||
@ -16801,9 +16982,11 @@ fn zirFuncExtended(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
|
||||
block,
|
||||
inst_data.src_node,
|
||||
inst,
|
||||
ret_ty_body,
|
||||
@"align",
|
||||
@"addrspace",
|
||||
@"linksection",
|
||||
cc,
|
||||
align_val,
|
||||
ret_ty,
|
||||
is_var_args,
|
||||
is_inferred_error,
|
||||
is_extern,
|
||||
|
||||
264
src/Zir.zig
264
src/Zir.zig
@ -74,7 +74,7 @@ pub fn extraData(code: Zir, comptime T: type, index: usize) struct { data: T, en
|
||||
Inst.Call.Flags => @bitCast(Inst.Call.Flags, code.extra[i]),
|
||||
Inst.BuiltinCall.Flags => @bitCast(Inst.BuiltinCall.Flags, code.extra[i]),
|
||||
Inst.SwitchBlock.Bits => @bitCast(Inst.SwitchBlock.Bits, code.extra[i]),
|
||||
Inst.ExtendedFunc.Bits => @bitCast(Inst.ExtendedFunc.Bits, code.extra[i]),
|
||||
Inst.FuncFancy.Bits => @bitCast(Inst.FuncFancy.Bits, code.extra[i]),
|
||||
else => @compileError("bad field type"),
|
||||
};
|
||||
i += 1;
|
||||
@ -424,8 +424,8 @@ pub const Inst = struct {
|
||||
func_inferred,
|
||||
/// Represents a function declaration or function prototype, depending on
|
||||
/// whether body_len is 0.
|
||||
/// Uses the `pl_node` union field. `payload_index` points to a `ExtendedFunc`.
|
||||
func_extended,
|
||||
/// Uses the `pl_node` union field. `payload_index` points to a `FuncFancy`.
|
||||
func_fancy,
|
||||
/// Implements the `@import` builtin.
|
||||
/// Uses the `str_tok` field.
|
||||
import,
|
||||
@ -1062,7 +1062,7 @@ pub const Inst = struct {
|
||||
.field_val_named,
|
||||
.func,
|
||||
.func_inferred,
|
||||
.func_extended,
|
||||
.func_fancy,
|
||||
.has_decl,
|
||||
.int,
|
||||
.int_big,
|
||||
@ -1346,7 +1346,7 @@ pub const Inst = struct {
|
||||
.field_val_named,
|
||||
.func,
|
||||
.func_inferred,
|
||||
.func_extended,
|
||||
.func_fancy,
|
||||
.has_decl,
|
||||
.int,
|
||||
.int_big,
|
||||
@ -1599,7 +1599,7 @@ pub const Inst = struct {
|
||||
.field_call_bind = .pl_node,
|
||||
.func = .pl_node,
|
||||
.func_inferred = .pl_node,
|
||||
.func_extended = .pl_node,
|
||||
.func_fancy = .pl_node,
|
||||
.import = .str_tok,
|
||||
.int = .int,
|
||||
.int_big = .str,
|
||||
@ -2606,29 +2606,100 @@ pub const Inst = struct {
|
||||
};
|
||||
|
||||
/// Trailing:
|
||||
/// 0. lib_name: u32, // null terminated string index, if has_lib_name is set
|
||||
/// 1. cc: Ref, // if has_cc is set
|
||||
/// 2. align: Ref, // if has_align is set
|
||||
/// 3. return_type: Index // for each ret_body_len
|
||||
/// 4. body: Index // for each body_len
|
||||
/// 5. src_locs: Func.SrcLocs // if body_len != 0
|
||||
pub const ExtendedFunc = struct {
|
||||
/// if (ret_body_len == 1) {
|
||||
/// 0. return_type: Ref
|
||||
/// }
|
||||
/// if (ret_body_len > 1) {
|
||||
/// 1. return_type: Index // for each ret_body_len
|
||||
/// }
|
||||
/// 2. body: Index // for each body_len
|
||||
/// 3. src_locs: SrcLocs // if body_len != 0
|
||||
pub const Func = struct {
|
||||
/// If this is 0 it means a void return type.
|
||||
/// If this is 1 it means return_type is a simple Ref
|
||||
ret_body_len: u32,
|
||||
/// Points to the block that contains the param instructions for this function.
|
||||
param_block: Index,
|
||||
body_len: u32,
|
||||
|
||||
pub const SrcLocs = struct {
|
||||
/// Line index in the source file relative to the parent decl.
|
||||
lbrace_line: u32,
|
||||
/// Line index in the source file relative to the parent decl.
|
||||
rbrace_line: u32,
|
||||
/// lbrace_column is least significant bits u16
|
||||
/// rbrace_column is most significant bits u16
|
||||
columns: u32,
|
||||
};
|
||||
};
|
||||
|
||||
/// Trailing:
|
||||
/// 0. lib_name: u32, // null terminated string index, if has_lib_name is set
|
||||
/// if (has_align_ref and !has_align_body) {
|
||||
/// 1. align: Ref,
|
||||
/// }
|
||||
/// if (has_align_body) {
|
||||
/// 2. align_body_len: u32
|
||||
/// 3. align_body: u32 // for each align_body_len
|
||||
/// }
|
||||
/// if (has_addrspace_ref and !has_addrspace_body) {
|
||||
/// 4. addrspace: Ref,
|
||||
/// }
|
||||
/// if (has_addrspace_body) {
|
||||
/// 5. addrspace_body_len: u32
|
||||
/// 6. addrspace_body: u32 // for each addrspace_body_len
|
||||
/// }
|
||||
/// if (has_section_ref and !has_section_body) {
|
||||
/// 7. section: Ref,
|
||||
/// }
|
||||
/// if (has_section_body) {
|
||||
/// 8. section_body_len: u32
|
||||
/// 9. section_body: u32 // for each section_body_len
|
||||
/// }
|
||||
/// if (has_cc_ref and !has_cc_body) {
|
||||
/// 10. cc: Ref,
|
||||
/// }
|
||||
/// if (has_cc_body) {
|
||||
/// 11. cc_body_len: u32
|
||||
/// 12. cc_body: u32 // for each cc_body_len
|
||||
/// }
|
||||
/// if (has_ret_ty_ref and !has_ret_ty_body) {
|
||||
/// 13. ret_ty: Ref,
|
||||
/// }
|
||||
/// if (has_ret_ty_body) {
|
||||
/// 14. ret_ty_body_len: u32
|
||||
/// 15. ret_ty_body: u32 // for each ret_ty_body_len
|
||||
/// }
|
||||
/// 16. body: Index // for each body_len
|
||||
/// 17. src_locs: Func.SrcLocs // if body_len != 0
|
||||
pub const FuncFancy = struct {
|
||||
/// Points to the block that contains the param instructions for this function.
|
||||
param_block: Index,
|
||||
body_len: u32,
|
||||
bits: Bits,
|
||||
|
||||
/// If both has_cc_ref and has_cc_body are false, it means auto calling convention.
|
||||
/// If both has_align_ref and has_align_body are false, it means default alignment.
|
||||
/// If both has_ret_ty_ref and has_ret_ty_body are false, it means void return type.
|
||||
/// If both has_section_ref and has_section_body are false, it means default section.
|
||||
/// If both has_addrspace_ref and has_addrspace_body are false, it means default addrspace.
|
||||
pub const Bits = packed struct {
|
||||
is_var_args: bool,
|
||||
is_inferred_error: bool,
|
||||
has_lib_name: bool,
|
||||
has_cc: bool,
|
||||
has_align: bool,
|
||||
is_test: bool,
|
||||
is_extern: bool,
|
||||
_: u25 = undefined,
|
||||
has_align_ref: bool,
|
||||
has_align_body: bool,
|
||||
has_addrspace_ref: bool,
|
||||
has_addrspace_body: bool,
|
||||
has_section_ref: bool,
|
||||
has_section_body: bool,
|
||||
has_cc_ref: bool,
|
||||
has_cc_body: bool,
|
||||
has_ret_ty_ref: bool,
|
||||
has_ret_ty_body: bool,
|
||||
has_lib_name: bool,
|
||||
_: u17 = undefined,
|
||||
};
|
||||
};
|
||||
|
||||
@ -2650,28 +2721,6 @@ pub const Inst = struct {
|
||||
};
|
||||
};
|
||||
|
||||
/// Trailing:
|
||||
/// 0. return_type: Index // for each ret_body_len
|
||||
/// 1. body: Index // for each body_len
|
||||
/// 2. src_locs: SrcLocs // if body_len != 0
|
||||
pub const Func = struct {
|
||||
/// If this is 0 it means a void return type.
|
||||
ret_body_len: u32,
|
||||
/// Points to the block that contains the param instructions for this function.
|
||||
param_block: Index,
|
||||
body_len: u32,
|
||||
|
||||
pub const SrcLocs = struct {
|
||||
/// Line index in the source file relative to the parent decl.
|
||||
lbrace_line: u32,
|
||||
/// Line index in the source file relative to the parent decl.
|
||||
rbrace_line: u32,
|
||||
/// lbrace_column is least significant bits u16
|
||||
/// rbrace_column is most significant bits u16
|
||||
columns: u32,
|
||||
};
|
||||
};
|
||||
|
||||
/// This data is stored inside extra, with trailing operands according to `operands_len`.
|
||||
/// Each operand is a `Ref`.
|
||||
pub const MultiOp = struct {
|
||||
@ -3473,7 +3522,7 @@ pub fn declIterator(zir: Zir, decl_inst: u32) DeclIterator {
|
||||
switch (tags[decl_inst]) {
|
||||
// Functions are allowed and yield no iterations.
|
||||
// There is one case matching this in the extended instruction set below.
|
||||
.func, .func_inferred, .func_extended => return declIteratorInner(zir, 0, 0),
|
||||
.func, .func_inferred, .func_fancy => return declIteratorInner(zir, 0, 0),
|
||||
|
||||
.extended => {
|
||||
const extended = datas[decl_inst].extended;
|
||||
@ -3579,18 +3628,77 @@ fn findDeclsInner(
|
||||
|
||||
const inst_data = datas[inst].pl_node;
|
||||
const extra = zir.extraData(Inst.Func, inst_data.payload_index);
|
||||
const body = zir.extra[extra.end..][0..extra.data.body_len];
|
||||
var extra_index: usize = extra.end;
|
||||
switch (extra.data.ret_body_len) {
|
||||
0 => {},
|
||||
1 => extra_index += 1,
|
||||
else => {
|
||||
const body = zir.extra[extra_index..][0..extra.data.ret_body_len];
|
||||
extra_index += body.len;
|
||||
try zir.findDeclsBody(list, body);
|
||||
},
|
||||
}
|
||||
const body = zir.extra[extra_index..][0..extra.data.body_len];
|
||||
return zir.findDeclsBody(list, body);
|
||||
},
|
||||
.func_extended => {
|
||||
.func_fancy => {
|
||||
try list.append(inst);
|
||||
|
||||
const inst_data = datas[inst].pl_node;
|
||||
const extra = zir.extraData(Inst.ExtendedFunc, inst_data.payload_index);
|
||||
const extra = zir.extraData(Inst.FuncFancy, inst_data.payload_index);
|
||||
var extra_index: usize = extra.end;
|
||||
extra_index += @boolToInt(extra.data.bits.has_lib_name);
|
||||
extra_index += @boolToInt(extra.data.bits.has_cc);
|
||||
extra_index += @boolToInt(extra.data.bits.has_align);
|
||||
|
||||
if (extra.data.bits.has_align_body) {
|
||||
const body_len = zir.extra[extra_index];
|
||||
extra_index += 1;
|
||||
const body = zir.extra[extra_index..][0..body_len];
|
||||
try zir.findDeclsBody(list, body);
|
||||
extra_index += body.len;
|
||||
} else if (extra.data.bits.has_align_ref) {
|
||||
extra_index += 1;
|
||||
}
|
||||
|
||||
if (extra.data.bits.has_addrspace_body) {
|
||||
const body_len = zir.extra[extra_index];
|
||||
extra_index += 1;
|
||||
const body = zir.extra[extra_index..][0..body_len];
|
||||
try zir.findDeclsBody(list, body);
|
||||
extra_index += body.len;
|
||||
} else if (extra.data.bits.has_addrspace_ref) {
|
||||
extra_index += 1;
|
||||
}
|
||||
|
||||
if (extra.data.bits.has_section_body) {
|
||||
const body_len = zir.extra[extra_index];
|
||||
extra_index += 1;
|
||||
const body = zir.extra[extra_index..][0..body_len];
|
||||
try zir.findDeclsBody(list, body);
|
||||
extra_index += body.len;
|
||||
} else if (extra.data.bits.has_section_ref) {
|
||||
extra_index += 1;
|
||||
}
|
||||
|
||||
if (extra.data.bits.has_cc_body) {
|
||||
const body_len = zir.extra[extra_index];
|
||||
extra_index += 1;
|
||||
const body = zir.extra[extra_index..][0..body_len];
|
||||
try zir.findDeclsBody(list, body);
|
||||
extra_index += body.len;
|
||||
} else if (extra.data.bits.has_cc_ref) {
|
||||
extra_index += 1;
|
||||
}
|
||||
|
||||
if (extra.data.bits.has_ret_ty_body) {
|
||||
const body_len = zir.extra[extra_index];
|
||||
extra_index += 1;
|
||||
const body = zir.extra[extra_index..][0..body_len];
|
||||
try zir.findDeclsBody(list, body);
|
||||
extra_index += body.len;
|
||||
} else if (extra.data.bits.has_ret_ty_ref) {
|
||||
extra_index += 1;
|
||||
}
|
||||
|
||||
const body = zir.extra[extra_index..][0..extra.data.body_len];
|
||||
return zir.findDeclsBody(list, body);
|
||||
},
|
||||
@ -3715,6 +3823,7 @@ pub const FnInfo = struct {
|
||||
param_body_inst: Inst.Index,
|
||||
ret_ty_body: []const Inst.Index,
|
||||
body: []const Inst.Index,
|
||||
ret_ty_ref: Zir.Inst.Ref,
|
||||
total_params_len: u32,
|
||||
};
|
||||
|
||||
@ -3724,38 +3833,84 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {
|
||||
const info: struct {
|
||||
param_block: Inst.Index,
|
||||
body: []const Inst.Index,
|
||||
ret_ty_ref: Inst.Ref,
|
||||
ret_ty_body: []const Inst.Index,
|
||||
} = switch (tags[fn_inst]) {
|
||||
.func, .func_inferred => blk: {
|
||||
const inst_data = datas[fn_inst].pl_node;
|
||||
const extra = zir.extraData(Inst.Func, inst_data.payload_index);
|
||||
var extra_index: usize = extra.end;
|
||||
|
||||
const ret_ty_body = zir.extra[extra_index..][0..extra.data.ret_body_len];
|
||||
extra_index += ret_ty_body.len;
|
||||
var extra_index: usize = extra.end;
|
||||
var ret_ty_ref: Inst.Ref = .none;
|
||||
var ret_ty_body: []const Inst.Index = &.{};
|
||||
|
||||
switch (extra.data.ret_body_len) {
|
||||
0 => {
|
||||
ret_ty_ref = .void_type;
|
||||
},
|
||||
1 => {
|
||||
ret_ty_ref = @intToEnum(Inst.Ref, zir.extra[extra_index]);
|
||||
extra_index += 1;
|
||||
},
|
||||
else => {
|
||||
ret_ty_body = zir.extra[extra_index..][0..extra.data.ret_body_len];
|
||||
extra_index += ret_ty_body.len;
|
||||
},
|
||||
}
|
||||
|
||||
const body = zir.extra[extra_index..][0..extra.data.body_len];
|
||||
extra_index += body.len;
|
||||
|
||||
break :blk .{
|
||||
.param_block = extra.data.param_block,
|
||||
.ret_ty_ref = ret_ty_ref,
|
||||
.ret_ty_body = ret_ty_body,
|
||||
.body = body,
|
||||
};
|
||||
},
|
||||
.func_extended => blk: {
|
||||
.func_fancy => blk: {
|
||||
const inst_data = datas[fn_inst].pl_node;
|
||||
const extra = zir.extraData(Inst.ExtendedFunc, inst_data.payload_index);
|
||||
const extra = zir.extraData(Inst.FuncFancy, inst_data.payload_index);
|
||||
|
||||
var extra_index: usize = extra.end;
|
||||
var ret_ty_ref: Inst.Ref = .void_type;
|
||||
var ret_ty_body: []const Inst.Index = &.{};
|
||||
|
||||
extra_index += @boolToInt(extra.data.bits.has_lib_name);
|
||||
extra_index += @boolToInt(extra.data.bits.has_cc);
|
||||
extra_index += @boolToInt(extra.data.bits.has_align);
|
||||
const ret_ty_body = zir.extra[extra_index..][0..extra.data.ret_body_len];
|
||||
extra_index += ret_ty_body.len;
|
||||
if (extra.data.bits.has_align_body) {
|
||||
extra_index += zir.extra[extra_index] + 1;
|
||||
} else if (extra.data.bits.has_align_ref) {
|
||||
extra_index += 1;
|
||||
}
|
||||
if (extra.data.bits.has_addrspace_body) {
|
||||
extra_index += zir.extra[extra_index] + 1;
|
||||
} else if (extra.data.bits.has_addrspace_ref) {
|
||||
extra_index += 1;
|
||||
}
|
||||
if (extra.data.bits.has_section_body) {
|
||||
extra_index += zir.extra[extra_index] + 1;
|
||||
} else if (extra.data.bits.has_section_ref) {
|
||||
extra_index += 1;
|
||||
}
|
||||
if (extra.data.bits.has_cc_body) {
|
||||
extra_index += zir.extra[extra_index] + 1;
|
||||
} else if (extra.data.bits.has_cc_ref) {
|
||||
extra_index += 1;
|
||||
}
|
||||
if (extra.data.bits.has_ret_ty_body) {
|
||||
const body_len = zir.extra[extra_index];
|
||||
extra_index += 1;
|
||||
ret_ty_body = zir.extra[extra_index..][0..body_len];
|
||||
extra_index += ret_ty_body.len;
|
||||
} else if (extra.data.bits.has_ret_ty_ref) {
|
||||
ret_ty_ref = @intToEnum(Inst.Ref, zir.extra[extra_index]);
|
||||
extra_index += 1;
|
||||
}
|
||||
const body = zir.extra[extra_index..][0..extra.data.body_len];
|
||||
extra_index += body.len;
|
||||
break :blk .{
|
||||
.param_block = extra.data.param_block,
|
||||
.ret_ty_ref = ret_ty_ref,
|
||||
.ret_ty_body = ret_ty_body,
|
||||
.body = body,
|
||||
};
|
||||
@ -3778,6 +3933,7 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {
|
||||
.param_body = param_body,
|
||||
.param_body_inst = info.param_block,
|
||||
.ret_ty_body = info.ret_ty_body,
|
||||
.ret_ty_ref = info.ret_ty_ref,
|
||||
.body = info.body,
|
||||
.total_params_len = total_params_len,
|
||||
};
|
||||
|
||||
@ -426,7 +426,7 @@ const Writer = struct {
|
||||
|
||||
.func => try self.writeFunc(stream, inst, false),
|
||||
.func_inferred => try self.writeFunc(stream, inst, true),
|
||||
.func_extended => try self.writeFuncExtended(stream, inst),
|
||||
.func_fancy => try self.writeFuncFancy(stream, inst),
|
||||
|
||||
.@"unreachable" => try self.writeUnreachable(stream, inst),
|
||||
|
||||
@ -1915,10 +1915,24 @@ const Writer = struct {
|
||||
const inst_data = self.code.instructions.items(.data)[inst].pl_node;
|
||||
const src = inst_data.src();
|
||||
const extra = self.code.extraData(Zir.Inst.Func, inst_data.payload_index);
|
||||
var extra_index = extra.end;
|
||||
|
||||
const ret_ty_body = self.code.extra[extra_index..][0..extra.data.ret_body_len];
|
||||
extra_index += ret_ty_body.len;
|
||||
var extra_index = extra.end;
|
||||
var ret_ty_ref: Zir.Inst.Ref = .none;
|
||||
var ret_ty_body: []const Zir.Inst.Index = &.{};
|
||||
|
||||
switch (extra.data.ret_body_len) {
|
||||
0 => {
|
||||
ret_ty_ref = .void_type;
|
||||
},
|
||||
1 => {
|
||||
ret_ty_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
|
||||
extra_index += 1;
|
||||
},
|
||||
else => {
|
||||
ret_ty_body = self.code.extra[extra_index..][0..extra.data.ret_body_len];
|
||||
extra_index += ret_ty_body.len;
|
||||
},
|
||||
}
|
||||
|
||||
const body = self.code.extra[extra_index..][0..extra.data.body_len];
|
||||
extra_index += body.len;
|
||||
@ -1929,43 +1943,96 @@ const Writer = struct {
|
||||
}
|
||||
return self.writeFuncCommon(
|
||||
stream,
|
||||
ret_ty_body,
|
||||
inferred_error_set,
|
||||
false,
|
||||
false,
|
||||
|
||||
.none,
|
||||
&.{},
|
||||
.none,
|
||||
&.{},
|
||||
.none,
|
||||
&.{},
|
||||
.none,
|
||||
&.{},
|
||||
ret_ty_ref,
|
||||
ret_ty_body,
|
||||
|
||||
body,
|
||||
src,
|
||||
src_locs,
|
||||
);
|
||||
}
|
||||
|
||||
fn writeFuncExtended(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
|
||||
fn writeFuncFancy(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
|
||||
const inst_data = self.code.instructions.items(.data)[inst].pl_node;
|
||||
const extra = self.code.extraData(Zir.Inst.ExtendedFunc, inst_data.payload_index);
|
||||
const extra = self.code.extraData(Zir.Inst.FuncFancy, inst_data.payload_index);
|
||||
const src = inst_data.src();
|
||||
|
||||
var extra_index: usize = extra.end;
|
||||
var align_ref: Zir.Inst.Ref = .none;
|
||||
var align_body: []const Zir.Inst.Index = &.{};
|
||||
var addrspace_ref: Zir.Inst.Ref = .none;
|
||||
var addrspace_body: []const Zir.Inst.Index = &.{};
|
||||
var section_ref: Zir.Inst.Ref = .none;
|
||||
var section_body: []const Zir.Inst.Index = &.{};
|
||||
var cc_ref: Zir.Inst.Ref = .none;
|
||||
var cc_body: []const Zir.Inst.Index = &.{};
|
||||
var ret_ty_ref: Zir.Inst.Ref = .none;
|
||||
var ret_ty_body: []const Zir.Inst.Index = &.{};
|
||||
|
||||
if (extra.data.bits.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)});
|
||||
}
|
||||
try self.writeFlag(stream, "test, ", extra.data.bits.is_test);
|
||||
const cc: Zir.Inst.Ref = if (!extra.data.bits.has_cc) .none else blk: {
|
||||
const cc = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
|
||||
extra_index += 1;
|
||||
break :blk cc;
|
||||
};
|
||||
const align_inst: Zir.Inst.Ref = if (!extra.data.bits.has_align) .none else blk: {
|
||||
const align_inst = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
|
||||
extra_index += 1;
|
||||
break :blk align_inst;
|
||||
};
|
||||
|
||||
const ret_ty_body = self.code.extra[extra_index..][0..extra.data.ret_body_len];
|
||||
extra_index += ret_ty_body.len;
|
||||
if (extra.data.bits.has_align_body) {
|
||||
const body_len = self.code.extra[extra_index];
|
||||
extra_index += 1;
|
||||
align_body = self.code.extra[extra_index..][0..body_len];
|
||||
extra_index += align_body.len;
|
||||
} else if (extra.data.bits.has_align_ref) {
|
||||
align_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
|
||||
extra_index += 1;
|
||||
}
|
||||
if (extra.data.bits.has_addrspace_body) {
|
||||
const body_len = self.code.extra[extra_index];
|
||||
extra_index += 1;
|
||||
addrspace_body = self.code.extra[extra_index..][0..body_len];
|
||||
extra_index += addrspace_body.len;
|
||||
} else if (extra.data.bits.has_addrspace_ref) {
|
||||
addrspace_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
|
||||
extra_index += 1;
|
||||
}
|
||||
if (extra.data.bits.has_section_body) {
|
||||
const body_len = self.code.extra[extra_index];
|
||||
extra_index += 1;
|
||||
section_body = self.code.extra[extra_index..][0..body_len];
|
||||
extra_index += section_body.len;
|
||||
} else if (extra.data.bits.has_section_ref) {
|
||||
section_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
|
||||
extra_index += 1;
|
||||
}
|
||||
if (extra.data.bits.has_cc_body) {
|
||||
const body_len = self.code.extra[extra_index];
|
||||
extra_index += 1;
|
||||
cc_body = self.code.extra[extra_index..][0..body_len];
|
||||
extra_index += cc_body.len;
|
||||
} else if (extra.data.bits.has_cc_ref) {
|
||||
cc_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
|
||||
extra_index += 1;
|
||||
}
|
||||
if (extra.data.bits.has_ret_ty_body) {
|
||||
const body_len = self.code.extra[extra_index];
|
||||
extra_index += 1;
|
||||
ret_ty_body = self.code.extra[extra_index..][0..body_len];
|
||||
extra_index += ret_ty_body.len;
|
||||
} else if (extra.data.bits.has_ret_ty_ref) {
|
||||
ret_ty_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
|
||||
extra_index += 1;
|
||||
}
|
||||
|
||||
const body = self.code.extra[extra_index..][0..extra.data.body_len];
|
||||
extra_index += body.len;
|
||||
@ -1976,12 +2043,19 @@ const Writer = struct {
|
||||
}
|
||||
return self.writeFuncCommon(
|
||||
stream,
|
||||
ret_ty_body,
|
||||
extra.data.bits.is_inferred_error,
|
||||
extra.data.bits.is_var_args,
|
||||
extra.data.bits.is_extern,
|
||||
cc,
|
||||
align_inst,
|
||||
align_ref,
|
||||
align_body,
|
||||
addrspace_ref,
|
||||
addrspace_body,
|
||||
section_ref,
|
||||
section_body,
|
||||
cc_ref,
|
||||
cc_body,
|
||||
ret_ty_ref,
|
||||
ret_ty_body,
|
||||
body,
|
||||
src,
|
||||
src_locs,
|
||||
@ -2126,30 +2200,33 @@ const Writer = struct {
|
||||
fn writeFuncCommon(
|
||||
self: *Writer,
|
||||
stream: anytype,
|
||||
ret_ty_body: []const Zir.Inst.Index,
|
||||
inferred_error_set: bool,
|
||||
var_args: bool,
|
||||
is_extern: bool,
|
||||
cc: Zir.Inst.Ref,
|
||||
align_inst: Zir.Inst.Ref,
|
||||
align_ref: Zir.Inst.Ref,
|
||||
align_body: []const Zir.Inst.Index,
|
||||
addrspace_ref: Zir.Inst.Ref,
|
||||
addrspace_body: []const Zir.Inst.Index,
|
||||
section_ref: Zir.Inst.Ref,
|
||||
section_body: []const Zir.Inst.Index,
|
||||
cc_ref: Zir.Inst.Ref,
|
||||
cc_body: []const Zir.Inst.Index,
|
||||
ret_ty_ref: Zir.Inst.Ref,
|
||||
ret_ty_body: []const Zir.Inst.Index,
|
||||
body: []const Zir.Inst.Index,
|
||||
src: LazySrcLoc,
|
||||
src_locs: Zir.Inst.Func.SrcLocs,
|
||||
) !void {
|
||||
if (ret_ty_body.len == 0) {
|
||||
try stream.writeAll("ret_ty=void");
|
||||
} else {
|
||||
try stream.writeAll("ret_ty=");
|
||||
try self.writeBracedBody(stream, ret_ty_body);
|
||||
}
|
||||
try self.writeOptionalInstRefOrBody(stream, "align=", align_ref, align_body);
|
||||
try self.writeOptionalInstRefOrBody(stream, "addrspace=", addrspace_ref, addrspace_body);
|
||||
try self.writeOptionalInstRefOrBody(stream, "section=", section_ref, section_body);
|
||||
try self.writeOptionalInstRefOrBody(stream, "cc=", cc_ref, cc_body);
|
||||
try self.writeOptionalInstRefOrBody(stream, "ret_ty=", ret_ty_ref, ret_ty_body);
|
||||
try self.writeFlag(stream, "vargs, ", var_args);
|
||||
try self.writeFlag(stream, "extern, ", is_extern);
|
||||
try self.writeFlag(stream, "inferror, ", inferred_error_set);
|
||||
|
||||
try self.writeOptionalInstRef(stream, ", cc=", cc);
|
||||
try self.writeOptionalInstRef(stream, ", align=", align_inst);
|
||||
try self.writeFlag(stream, ", vargs", var_args);
|
||||
try self.writeFlag(stream, ", extern", is_extern);
|
||||
try self.writeFlag(stream, ", inferror", inferred_error_set);
|
||||
|
||||
try stream.writeAll(", body=");
|
||||
try stream.writeAll("body=");
|
||||
try self.writeBracedBody(stream, body);
|
||||
try stream.writeAll(") ");
|
||||
if (body.len != 0) {
|
||||
@ -2199,6 +2276,24 @@ const Writer = struct {
|
||||
try self.writeInstRef(stream, inst);
|
||||
}
|
||||
|
||||
fn writeOptionalInstRefOrBody(
|
||||
self: *Writer,
|
||||
stream: anytype,
|
||||
prefix: []const u8,
|
||||
ref: Zir.Inst.Ref,
|
||||
body: []const Zir.Inst.Index,
|
||||
) !void {
|
||||
if (body.len != 0) {
|
||||
try stream.writeAll(prefix);
|
||||
try self.writeBracedBody(stream, body);
|
||||
try stream.writeAll(", ");
|
||||
} else if (ref != .none) {
|
||||
try stream.writeAll(prefix);
|
||||
try self.writeInstRef(stream, ref);
|
||||
try stream.writeAll(", ");
|
||||
}
|
||||
}
|
||||
|
||||
fn writeFlag(
|
||||
self: *Writer,
|
||||
stream: anytype,
|
||||
|
||||
@ -6120,6 +6120,10 @@ pub const Type = extern union {
|
||||
cc: std.builtin.CallingConvention,
|
||||
is_var_args: bool,
|
||||
is_generic: bool,
|
||||
align_is_generic: bool = false,
|
||||
cc_is_generic: bool = false,
|
||||
section_is_generic: bool = false,
|
||||
addrspace_is_generic: bool = false,
|
||||
|
||||
pub fn paramIsComptime(self: @This(), i: usize) bool {
|
||||
assert(i < self.param_types.len);
|
||||
|
||||
@ -334,25 +334,44 @@ fn simple4() align(4) i32 {
|
||||
return 0x19;
|
||||
}
|
||||
|
||||
test "generic function with align param" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
test "function align expression depends on generic parameter" {
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
|
||||
// function alignment is a compile error on wasm32/wasm64
|
||||
if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest;
|
||||
if (native_arch == .thumb) return error.SkipZigTest;
|
||||
|
||||
try expect(whyWouldYouEverDoThis(1) == 0x1);
|
||||
try expect(whyWouldYouEverDoThis(4) == 0x1);
|
||||
try expect(whyWouldYouEverDoThis(8) == 0x1);
|
||||
const S = struct {
|
||||
fn doTheTest() !void {
|
||||
try expect(foobar(1) == 2);
|
||||
try expect(foobar(4) == 5);
|
||||
try expect(foobar(8) == 9);
|
||||
}
|
||||
|
||||
fn foobar(comptime align_bytes: u8) align(align_bytes) u8 {
|
||||
return align_bytes + 1;
|
||||
}
|
||||
};
|
||||
try S.doTheTest();
|
||||
comptime try S.doTheTest();
|
||||
}
|
||||
|
||||
fn whyWouldYouEverDoThis(comptime align_bytes: u8) align(align_bytes) u8 {
|
||||
_ = align_bytes;
|
||||
return 0x1;
|
||||
test "function callconv expression depends on generic parameter" {
|
||||
if (builtin.zig_backend == .stage1) return error.SkipZigTest;
|
||||
|
||||
const S = struct {
|
||||
fn doTheTest() !void {
|
||||
try expect(foobar(.C, 1) == 2);
|
||||
try expect(foobar(.Unspecified, 2) == 3);
|
||||
}
|
||||
|
||||
fn foobar(comptime cc: std.builtin.CallingConvention, arg: u8) callconv(cc) u8 {
|
||||
return arg + 1;
|
||||
}
|
||||
};
|
||||
try S.doTheTest();
|
||||
comptime try S.doTheTest();
|
||||
}
|
||||
|
||||
test "runtime known array index has best alignment possible" {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user