From bac24c662805f41467fa9c8d7e08682ebde8267f Mon Sep 17 00:00:00 2001 From: Meghan Denny Date: Wed, 20 Jul 2022 16:05:40 -0700 Subject: [PATCH 1/2] stage2: implement `noinline fn` --- src/AstGen.zig | 18 +++++++++++++----- src/Module.zig | 2 +- src/Sema.zig | 9 +++++++++ src/Zir.zig | 3 ++- src/codegen/llvm.zig | 6 ++++++ src/print_zir.zig | 4 ++++ 6 files changed, 35 insertions(+), 7 deletions(-) diff --git a/src/AstGen.zig b/src/AstGen.zig index af0fac04f14b..e445c6b2a244 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -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, }); @@ -10170,6 +10177,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; @@ -10211,10 +10219,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 = &.{}; @@ -10247,6 +10254,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, diff --git a/src/Module.zig b/src/Module.zig index 5f441790b76e..024f4bf6e313 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -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 diff --git a/src/Sema.zig b/src/Sema.zig index 8023e60c7d13..a79d57216ed4 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -7229,6 +7229,7 @@ fn zirFunc( src_locs, null, 0, + false, ); } @@ -7359,6 +7360,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 }; @@ -7554,6 +7556,10 @@ fn funcCommon( }); } + if (cc_workaround == .Inline and is_noinline) { + return sema.fail(block, cc_src, "callconv(.Inline) and noinline are incompatible together", .{}); + } + break :fn_ty try Type.Tag.function.create(sema.arena, .{ .param_types = param_types, .comptime_params = comptime_params.ptr, @@ -7634,6 +7640,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); @@ -18194,6 +18201,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, @@ -18211,6 +18219,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A src_locs, lib_name, noalias_bits, + is_noinline, ); } diff --git a/src/Zir.zig b/src/Zir.zig index 73ba396e755b..1852a2d991b8 100644 --- a/src/Zir.zig +++ b/src/Zir.zig @@ -2731,6 +2731,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, @@ -2743,7 +2744,7 @@ pub const Inst = struct { has_ret_ty_body: bool, has_lib_name: bool, has_any_noalias: bool, - _: u16 = undefined, + _: u15 = undefined, }; }; diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 6966d8b164cf..e760ebbb3ee0 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -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| { diff --git a/src/print_zir.zig b/src/print_zir.zig index 96923c6d8623..bbc6b3cecc8f 100644 --- a/src/print_zir.zig +++ b/src/print_zir.zig @@ -1983,6 +1983,7 @@ const Writer = struct { inferred_error_set, false, false, + false, .none, &.{}, @@ -2090,6 +2091,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, @@ -2249,6 +2251,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, @@ -2272,6 +2275,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}); From 4be0ef84495a712eb0dd9bb64cd8920fa54867aa Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Sat, 23 Jul 2022 14:51:56 +0300 Subject: [PATCH 2/2] add test for new error --- src/Sema.zig | 2 +- test/cases/compile_errors/noinline_fn_cc_inline.zig | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 test/cases/compile_errors/noinline_fn_cc_inline.zig diff --git a/src/Sema.zig b/src/Sema.zig index a79d57216ed4..cc1a0836628c 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -7557,7 +7557,7 @@ fn funcCommon( } if (cc_workaround == .Inline and is_noinline) { - return sema.fail(block, cc_src, "callconv(.Inline) and noinline are incompatible together", .{}); + return sema.fail(block, cc_src, "'noinline' function cannot have callconv 'Inline'", .{}); } break :fn_ty try Type.Tag.function.create(sema.arena, .{ diff --git a/test/cases/compile_errors/noinline_fn_cc_inline.zig b/test/cases/compile_errors/noinline_fn_cc_inline.zig new file mode 100644 index 000000000000..3a2d6440c3a6 --- /dev/null +++ b/test/cases/compile_errors/noinline_fn_cc_inline.zig @@ -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'