stage2: implement noinline fn

This commit is contained in:
Meghan 2022-07-24 01:56:33 -07:00 committed by GitHub
parent 903bed931d
commit dea437edfb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 47 additions and 7 deletions

View File

@ -1274,6 +1274,7 @@ fn fnProtoExpr(
.is_inferred_error = false,
.is_test = false,
.is_extern = false,
.is_noinline = false,
.noalias_bits = noalias_bits,
});
@ -3389,7 +3390,6 @@ fn fnDecl(
};
defer fn_gz.unstack();
// TODO: support noinline
const is_pub = fn_proto.visib_token != null;
const is_export = blk: {
const maybe_export_token = fn_proto.extern_export_inline_token orelse break :blk false;
@ -3403,6 +3403,10 @@ fn fnDecl(
const maybe_inline_token = fn_proto.extern_export_inline_token orelse break :blk false;
break :blk token_tags[maybe_inline_token] == .keyword_inline;
};
const is_noinline = blk: {
const maybe_noinline_token = fn_proto.extern_export_inline_token orelse break :blk false;
break :blk token_tags[maybe_noinline_token] == .keyword_noinline;
};
const doc_comment_index = try astgen.docCommentAsString(fn_proto.firstToken());
@ -3610,6 +3614,7 @@ fn fnDecl(
.is_inferred_error = false,
.is_test = false,
.is_extern = true,
.is_noinline = is_noinline,
.noalias_bits = noalias_bits,
});
} else func: {
@ -3658,6 +3663,7 @@ fn fnDecl(
.is_inferred_error = is_inferred_error,
.is_test = false,
.is_extern = false,
.is_noinline = is_noinline,
.noalias_bits = noalias_bits,
});
};
@ -4093,6 +4099,7 @@ fn testDecl(
.is_inferred_error = true,
.is_test = true,
.is_extern = false,
.is_noinline = false,
.noalias_bits = 0,
});
@ -10175,6 +10182,7 @@ const GenZir = struct {
is_inferred_error: bool,
is_test: bool,
is_extern: bool,
is_noinline: bool,
}) !Zir.Inst.Ref {
assert(args.src_node != 0);
const astgen = gz.astgen;
@ -10216,10 +10224,9 @@ const GenZir = struct {
}
const body_len = astgen.countBodyLenAfterFixups(body);
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 or args.noalias_bits != 0)
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 or args.noalias_bits != 0 or args.is_noinline)
{
var align_body: []Zir.Inst.Index = &.{};
var addrspace_body: []Zir.Inst.Index = &.{};
@ -10252,6 +10259,7 @@ const GenZir = struct {
.is_inferred_error = args.is_inferred_error,
.is_test = args.is_test,
.is_extern = args.is_extern,
.is_noinline = args.is_noinline,
.has_lib_name = args.lib_name != 0,
.has_any_noalias = args.noalias_bits != 0,

View File

@ -1488,7 +1488,7 @@ pub const Fn = struct {
branch_quota: u32,
state: Analysis,
is_cold: bool = false,
is_noinline: bool = false,
is_noinline: bool,
calls_or_awaits_errorable_fn: bool = false,
/// Any inferred error sets that this function owns, both its own inferred error set and

View File

@ -7252,6 +7252,7 @@ fn zirFunc(
src_locs,
null,
0,
false,
);
}
@ -7382,6 +7383,7 @@ fn funcCommon(
src_locs: Zir.Inst.Func.SrcLocs,
opt_lib_name: ?[]const u8,
noalias_bits: u32,
is_noinline: bool,
) CompileError!Air.Inst.Ref {
const fn_src = LazySrcLoc.nodeOffset(src_node_offset);
const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset };
@ -7577,6 +7579,10 @@ fn funcCommon(
});
}
if (cc_workaround == .Inline and is_noinline) {
return sema.fail(block, cc_src, "'noinline' function cannot have callconv 'Inline'", .{});
}
break :fn_ty try Type.Tag.function.create(sema.arena, .{
.param_types = param_types,
.comptime_params = comptime_params.ptr,
@ -7657,6 +7663,7 @@ fn funcCommon(
.rbrace_column = @truncate(u16, src_locs.columns >> 16),
.param_names = param_names,
.branch_quota = default_branch_quota,
.is_noinline = is_noinline,
};
if (maybe_inferred_error_set_node) |node| {
new_func.inferred_error_sets.prepend(node);
@ -18443,6 +18450,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
const is_var_args = extra.data.bits.is_var_args;
const is_inferred_error = extra.data.bits.is_inferred_error;
const is_extern = extra.data.bits.is_extern;
const is_noinline = extra.data.bits.is_noinline;
return sema.funcCommon(
block,
@ -18460,6 +18468,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
src_locs,
lib_name,
noalias_bits,
is_noinline,
);
}

View File

@ -2736,6 +2736,7 @@ pub const Inst = struct {
is_inferred_error: bool,
is_test: bool,
is_extern: bool,
is_noinline: bool,
has_align_ref: bool,
has_align_body: bool,
has_addrspace_ref: bool,
@ -2748,7 +2749,7 @@ pub const Inst = struct {
has_ret_ty_body: bool,
has_lib_name: bool,
has_any_noalias: bool,
_: u16 = undefined,
_: u15 = undefined,
};
};

View File

@ -699,6 +699,12 @@ pub const Object = struct {
DeclGen.removeFnAttr(llvm_func, "cold");
}
if (func.is_noinline) {
dg.addFnAttr(llvm_func, "noinline");
} else {
DeclGen.removeFnAttr(llvm_func, "noinline");
}
// Remove all the basic blocks of a function in order to start over, generating
// LLVM IR from an empty function body.
while (llvm_func.getFirstBasicBlock()) |bb| {

View File

@ -1984,6 +1984,7 @@ const Writer = struct {
inferred_error_set,
false,
false,
false,
.none,
&.{},
@ -2091,6 +2092,7 @@ const Writer = struct {
extra.data.bits.is_inferred_error,
extra.data.bits.is_var_args,
extra.data.bits.is_extern,
extra.data.bits.is_noinline,
align_ref,
align_body,
addrspace_ref,
@ -2250,6 +2252,7 @@ const Writer = struct {
inferred_error_set: bool,
var_args: bool,
is_extern: bool,
is_noinline: bool,
align_ref: Zir.Inst.Ref,
align_body: []const Zir.Inst.Index,
addrspace_ref: Zir.Inst.Ref,
@ -2273,6 +2276,7 @@ const Writer = struct {
try self.writeFlag(stream, "vargs, ", var_args);
try self.writeFlag(stream, "extern, ", is_extern);
try self.writeFlag(stream, "inferror, ", inferred_error_set);
try self.writeFlag(stream, "noinline, ", is_noinline);
if (noalias_bits != 0) {
try stream.print("noalias=0b{b}, ", .{noalias_bits});

View File

@ -0,0 +1,12 @@
const cc = .Inline;
noinline fn foo() callconv(cc) void {}
comptime {
_ = foo;
}
// error
// backend=stage2
// target=native
//
// :2:28: error: 'noinline' function cannot have callconv 'Inline'