authorgravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2022-07-24 01:56:33-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-07-24 11:56:33+03:00
logdea437edfb124b8a4cf4f2e09330ef4282991cc9
treecff1a5c5f9b89c4f8f94def8006f7d07f9757dbc
parent903bed931dddc8b3f7ad1fa87e57eca13375dd32
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

stage2: implement `noinline fn`


7 files changed, 47 insertions(+), 7 deletions(-)

src/AstGen.zig+13-5
...@@ -1274,6 +1274,7 @@ fn fnProtoExpr(...@@ -1274,6 +1274,7 @@ fn fnProtoExpr(
1274 .is_inferred_error = false,1274 .is_inferred_error = false,
1275 .is_test = false,1275 .is_test = false,
1276 .is_extern = false,1276 .is_extern = false,
1277 .is_noinline = false,
1277 .noalias_bits = noalias_bits,1278 .noalias_bits = noalias_bits,
1278 });1279 });
12791280
...@@ -3389,7 +3390,6 @@ fn fnDecl(...@@ -3389,7 +3390,6 @@ fn fnDecl(
3389 };3390 };
3390 defer fn_gz.unstack();3391 defer fn_gz.unstack();
33913392
3392 // TODO: support noinline
3393 const is_pub = fn_proto.visib_token != null;3393 const is_pub = fn_proto.visib_token != null;
3394 const is_export = blk: {3394 const is_export = blk: {
3395 const maybe_export_token = fn_proto.extern_export_inline_token orelse break :blk false;3395 const maybe_export_token = fn_proto.extern_export_inline_token orelse break :blk false;
...@@ -3403,6 +3403,10 @@ fn fnDecl(...@@ -3403,6 +3403,10 @@ fn fnDecl(
3403 const maybe_inline_token = fn_proto.extern_export_inline_token orelse break :blk false;3403 const maybe_inline_token = fn_proto.extern_export_inline_token orelse break :blk false;
3404 break :blk token_tags[maybe_inline_token] == .keyword_inline;3404 break :blk token_tags[maybe_inline_token] == .keyword_inline;
3405 };3405 };
3406 const is_noinline = blk: {
3407 const maybe_noinline_token = fn_proto.extern_export_inline_token orelse break :blk false;
3408 break :blk token_tags[maybe_noinline_token] == .keyword_noinline;
3409 };
34063410
3407 const doc_comment_index = try astgen.docCommentAsString(fn_proto.firstToken());3411 const doc_comment_index = try astgen.docCommentAsString(fn_proto.firstToken());
34083412
...@@ -3610,6 +3614,7 @@ fn fnDecl(...@@ -3610,6 +3614,7 @@ fn fnDecl(
3610 .is_inferred_error = false,3614 .is_inferred_error = false,
3611 .is_test = false,3615 .is_test = false,
3612 .is_extern = true,3616 .is_extern = true,
3617 .is_noinline = is_noinline,
3613 .noalias_bits = noalias_bits,3618 .noalias_bits = noalias_bits,
3614 });3619 });
3615 } else func: {3620 } else func: {
...@@ -3658,6 +3663,7 @@ fn fnDecl(...@@ -3658,6 +3663,7 @@ fn fnDecl(
3658 .is_inferred_error = is_inferred_error,3663 .is_inferred_error = is_inferred_error,
3659 .is_test = false,3664 .is_test = false,
3660 .is_extern = false,3665 .is_extern = false,
3666 .is_noinline = is_noinline,
3661 .noalias_bits = noalias_bits,3667 .noalias_bits = noalias_bits,
3662 });3668 });
3663 };3669 };
...@@ -4093,6 +4099,7 @@ fn testDecl(...@@ -4093,6 +4099,7 @@ fn testDecl(
4093 .is_inferred_error = true,4099 .is_inferred_error = true,
4094 .is_test = true,4100 .is_test = true,
4095 .is_extern = false,4101 .is_extern = false,
4102 .is_noinline = false,
4096 .noalias_bits = 0,4103 .noalias_bits = 0,
4097 });4104 });
40984105
...@@ -10175,6 +10182,7 @@ const GenZir = struct {...@@ -10175,6 +10182,7 @@ const GenZir = struct {
10175 is_inferred_error: bool,10182 is_inferred_error: bool,
10176 is_test: bool,10183 is_test: bool,
10177 is_extern: bool,10184 is_extern: bool,
10185 is_noinline: bool,
10178 }) !Zir.Inst.Ref {10186 }) !Zir.Inst.Ref {
10179 assert(args.src_node != 0);10187 assert(args.src_node != 0);
10180 const astgen = gz.astgen;10188 const astgen = gz.astgen;
...@@ -10216,10 +10224,9 @@ const GenZir = struct {...@@ -10216,10 +10224,9 @@ const GenZir = struct {
10216 }10224 }
10217 const body_len = astgen.countBodyLenAfterFixups(body);10225 const body_len = astgen.countBodyLenAfterFixups(body);
1021810226
10219 if (args.cc_ref != .none or args.lib_name != 0 or10227 if (args.cc_ref != .none or args.lib_name != 0 or args.is_var_args or args.is_test or
10220 args.is_var_args or args.is_test or args.is_extern or10228 args.is_extern or args.align_ref != .none or args.section_ref != .none or
10221 args.align_ref != .none or args.section_ref != .none or10229 args.addrspace_ref != .none or args.noalias_bits != 0 or args.is_noinline)
10222 args.addrspace_ref != .none or args.noalias_bits != 0)
10223 {10230 {
10224 var align_body: []Zir.Inst.Index = &.{};10231 var align_body: []Zir.Inst.Index = &.{};
10225 var addrspace_body: []Zir.Inst.Index = &.{};10232 var addrspace_body: []Zir.Inst.Index = &.{};
...@@ -10252,6 +10259,7 @@ const GenZir = struct {...@@ -10252,6 +10259,7 @@ const GenZir = struct {
10252 .is_inferred_error = args.is_inferred_error,10259 .is_inferred_error = args.is_inferred_error,
10253 .is_test = args.is_test,10260 .is_test = args.is_test,
10254 .is_extern = args.is_extern,10261 .is_extern = args.is_extern,
10262 .is_noinline = args.is_noinline,
10255 .has_lib_name = args.lib_name != 0,10263 .has_lib_name = args.lib_name != 0,
10256 .has_any_noalias = args.noalias_bits != 0,10264 .has_any_noalias = args.noalias_bits != 0,
1025710265
src/Module.zig+1-1
...@@ -1488,7 +1488,7 @@ pub const Fn = struct {...@@ -1488,7 +1488,7 @@ pub const Fn = struct {
1488 branch_quota: u32,1488 branch_quota: u32,
1489 state: Analysis,1489 state: Analysis,
1490 is_cold: bool = false,1490 is_cold: bool = false,
1491 is_noinline: bool = false,1491 is_noinline: bool,
1492 calls_or_awaits_errorable_fn: bool = false,1492 calls_or_awaits_errorable_fn: bool = false,
14931493
1494 /// Any inferred error sets that this function owns, both its own inferred error set and1494 /// Any inferred error sets that this function owns, both its own inferred error set and
src/Sema.zig+9
...@@ -7252,6 +7252,7 @@ fn zirFunc(...@@ -7252,6 +7252,7 @@ fn zirFunc(
7252 src_locs,7252 src_locs,
7253 null,7253 null,
7254 0,7254 0,
7255 false,
7255 );7256 );
7256}7257}
72577258
...@@ -7382,6 +7383,7 @@ fn funcCommon(...@@ -7382,6 +7383,7 @@ fn funcCommon(
7382 src_locs: Zir.Inst.Func.SrcLocs,7383 src_locs: Zir.Inst.Func.SrcLocs,
7383 opt_lib_name: ?[]const u8,7384 opt_lib_name: ?[]const u8,
7384 noalias_bits: u32,7385 noalias_bits: u32,
7386 is_noinline: bool,
7385) CompileError!Air.Inst.Ref {7387) CompileError!Air.Inst.Ref {
7386 const fn_src = LazySrcLoc.nodeOffset(src_node_offset);7388 const fn_src = LazySrcLoc.nodeOffset(src_node_offset);
7387 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset };7389 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset };
...@@ -7577,6 +7579,10 @@ fn funcCommon(...@@ -7577,6 +7579,10 @@ fn funcCommon(
7577 });7579 });
7578 }7580 }
75797581
7582 if (cc_workaround == .Inline and is_noinline) {
7583 return sema.fail(block, cc_src, "'noinline' function cannot have callconv 'Inline'", .{});
7584 }
7585
7580 break :fn_ty try Type.Tag.function.create(sema.arena, .{7586 break :fn_ty try Type.Tag.function.create(sema.arena, .{
7581 .param_types = param_types,7587 .param_types = param_types,
7582 .comptime_params = comptime_params.ptr,7588 .comptime_params = comptime_params.ptr,
...@@ -7657,6 +7663,7 @@ fn funcCommon(...@@ -7657,6 +7663,7 @@ fn funcCommon(
7657 .rbrace_column = @truncate(u16, src_locs.columns >> 16),7663 .rbrace_column = @truncate(u16, src_locs.columns >> 16),
7658 .param_names = param_names,7664 .param_names = param_names,
7659 .branch_quota = default_branch_quota,7665 .branch_quota = default_branch_quota,
7666 .is_noinline = is_noinline,
7660 };7667 };
7661 if (maybe_inferred_error_set_node) |node| {7668 if (maybe_inferred_error_set_node) |node| {
7662 new_func.inferred_error_sets.prepend(node);7669 new_func.inferred_error_sets.prepend(node);
...@@ -18443,6 +18450,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -18443,6 +18450,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
18443 const is_var_args = extra.data.bits.is_var_args;18450 const is_var_args = extra.data.bits.is_var_args;
18444 const is_inferred_error = extra.data.bits.is_inferred_error;18451 const is_inferred_error = extra.data.bits.is_inferred_error;
18445 const is_extern = extra.data.bits.is_extern;18452 const is_extern = extra.data.bits.is_extern;
18453 const is_noinline = extra.data.bits.is_noinline;
1844618454
18447 return sema.funcCommon(18455 return sema.funcCommon(
18448 block,18456 block,
...@@ -18460,6 +18468,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -18460,6 +18468,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
18460 src_locs,18468 src_locs,
18461 lib_name,18469 lib_name,
18462 noalias_bits,18470 noalias_bits,
18471 is_noinline,
18463 );18472 );
18464}18473}
1846518474
src/Zir.zig+2-1
...@@ -2736,6 +2736,7 @@ pub const Inst = struct {...@@ -2736,6 +2736,7 @@ pub const Inst = struct {
2736 is_inferred_error: bool,2736 is_inferred_error: bool,
2737 is_test: bool,2737 is_test: bool,
2738 is_extern: bool,2738 is_extern: bool,
2739 is_noinline: bool,
2739 has_align_ref: bool,2740 has_align_ref: bool,
2740 has_align_body: bool,2741 has_align_body: bool,
2741 has_addrspace_ref: bool,2742 has_addrspace_ref: bool,
...@@ -2748,7 +2749,7 @@ pub const Inst = struct {...@@ -2748,7 +2749,7 @@ pub const Inst = struct {
2748 has_ret_ty_body: bool,2749 has_ret_ty_body: bool,
2749 has_lib_name: bool,2750 has_lib_name: bool,
2750 has_any_noalias: bool,2751 has_any_noalias: bool,
2751 _: u16 = undefined,2752 _: u15 = undefined,
2752 };2753 };
2753 };2754 };
27542755
src/codegen/llvm.zig+6
...@@ -699,6 +699,12 @@ pub const Object = struct {...@@ -699,6 +699,12 @@ pub const Object = struct {
699 DeclGen.removeFnAttr(llvm_func, "cold");699 DeclGen.removeFnAttr(llvm_func, "cold");
700 }700 }
701701
702 if (func.is_noinline) {
703 dg.addFnAttr(llvm_func, "noinline");
704 } else {
705 DeclGen.removeFnAttr(llvm_func, "noinline");
706 }
707
702 // Remove all the basic blocks of a function in order to start over, generating708 // Remove all the basic blocks of a function in order to start over, generating
703 // LLVM IR from an empty function body.709 // LLVM IR from an empty function body.
704 while (llvm_func.getFirstBasicBlock()) |bb| {710 while (llvm_func.getFirstBasicBlock()) |bb| {
src/print_zir.zig+4
...@@ -1984,6 +1984,7 @@ const Writer = struct {...@@ -1984,6 +1984,7 @@ const Writer = struct {
1984 inferred_error_set,1984 inferred_error_set,
1985 false,1985 false,
1986 false,1986 false,
1987 false,
19871988
1988 .none,1989 .none,
1989 &.{},1990 &.{},
...@@ -2091,6 +2092,7 @@ const Writer = struct {...@@ -2091,6 +2092,7 @@ const Writer = struct {
2091 extra.data.bits.is_inferred_error,2092 extra.data.bits.is_inferred_error,
2092 extra.data.bits.is_var_args,2093 extra.data.bits.is_var_args,
2093 extra.data.bits.is_extern,2094 extra.data.bits.is_extern,
2095 extra.data.bits.is_noinline,
2094 align_ref,2096 align_ref,
2095 align_body,2097 align_body,
2096 addrspace_ref,2098 addrspace_ref,
...@@ -2250,6 +2252,7 @@ const Writer = struct {...@@ -2250,6 +2252,7 @@ const Writer = struct {
2250 inferred_error_set: bool,2252 inferred_error_set: bool,
2251 var_args: bool,2253 var_args: bool,
2252 is_extern: bool,2254 is_extern: bool,
2255 is_noinline: bool,
2253 align_ref: Zir.Inst.Ref,2256 align_ref: Zir.Inst.Ref,
2254 align_body: []const Zir.Inst.Index,2257 align_body: []const Zir.Inst.Index,
2255 addrspace_ref: Zir.Inst.Ref,2258 addrspace_ref: Zir.Inst.Ref,
...@@ -2273,6 +2276,7 @@ const Writer = struct {...@@ -2273,6 +2276,7 @@ const Writer = struct {
2273 try self.writeFlag(stream, "vargs, ", var_args);2276 try self.writeFlag(stream, "vargs, ", var_args);
2274 try self.writeFlag(stream, "extern, ", is_extern);2277 try self.writeFlag(stream, "extern, ", is_extern);
2275 try self.writeFlag(stream, "inferror, ", inferred_error_set);2278 try self.writeFlag(stream, "inferror, ", inferred_error_set);
2279 try self.writeFlag(stream, "noinline, ", is_noinline);
22762280
2277 if (noalias_bits != 0) {2281 if (noalias_bits != 0) {
2278 try stream.print("noalias=0b{b}, ", .{noalias_bits});2282 try stream.print("noalias=0b{b}, ", .{noalias_bits});
test/cases/compile_errors/noinline_fn_cc_inline.zig created+12
...@@ -0,0 +1,12 @@
1const cc = .Inline;
2noinline fn foo() callconv(cc) void {}
3
4comptime {
5 _ = foo;
6}
7
8// error
9// backend=stage2
10// target=native
11//
12// :2:28: error: 'noinline' function cannot have callconv 'Inline'