authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-05-31 17:38:42-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-05-31 17:38:42-07:00
log356a865b871db458149f70bc103a3971780d6962
treec4e06c84ce3735b48add6e89c69cf6cc3e84da1c
parent602af1b88f150f8b09d980520620ab289c425075

stage2: introduce support for noalias

Not implemented yet is enhancements to coerceInMemory to account for noalias parameters. Related to #11498.

6 files changed, 108 insertions(+), 23 deletions(-)

src/AstGen.zig+33-10
......@@ -1155,14 +1155,20 @@ fn fnProtoExpr(
11551155
11561156 const block_inst = try gz.makeBlockInst(.block_inline, node);
11571157
1158 var noalias_bits: u32 = 0;
11581159 const is_var_args = is_var_args: {
11591160 var param_type_i: usize = 0;
11601161 var it = fn_proto.iterate(tree);
11611162 while (it.next()) |param| : (param_type_i += 1) {
1162 const is_comptime = if (param.comptime_noalias) |token|
1163 token_tags[token] == .keyword_comptime
1164 else
1165 false;
1163 const is_comptime = if (param.comptime_noalias) |token| switch (token_tags[token]) {
1164 .keyword_noalias => is_comptime: {
1165 noalias_bits |= @as(u32, 1) << (std.math.cast(u5, param_type_i) orelse
1166 return astgen.failTok(token, "this compiler implementation only supports 'noalias' on the first 32 parameters", .{}));
1167 break :is_comptime false;
1168 },
1169 .keyword_comptime => true,
1170 else => false,
1171 } else false;
11661172
11671173 const is_anytype = if (param.anytype_ellipsis3) |token| blk: {
11681174 switch (token_tags[token]) {
......@@ -1255,6 +1261,7 @@ fn fnProtoExpr(
12551261 .is_inferred_error = false,
12561262 .is_test = false,
12571263 .is_extern = false,
1264 .noalias_bits = noalias_bits,
12581265 });
12591266
12601267 _ = try block_scope.addBreak(.break_inline, block_inst, result);
......@@ -3381,15 +3388,21 @@ fn fnDecl(
33813388 // align, linksection, and addrspace is passed in the func instruction in this case.
33823389 wip_members.nextDecl(is_pub, is_export, false, false);
33833390
3391 var noalias_bits: u32 = 0;
33843392 var params_scope = &fn_gz.base;
33853393 const is_var_args = is_var_args: {
33863394 var param_type_i: usize = 0;
33873395 var it = fn_proto.iterate(tree);
33883396 while (it.next()) |param| : (param_type_i += 1) {
3389 const is_comptime = if (param.comptime_noalias) |token|
3390 token_tags[token] == .keyword_comptime
3391 else
3392 false;
3397 const is_comptime = if (param.comptime_noalias) |token| switch (token_tags[token]) {
3398 .keyword_noalias => is_comptime: {
3399 noalias_bits |= @as(u32, 1) << (std.math.cast(u5, param_type_i) orelse
3400 return astgen.failTok(token, "this compiler implementation only supports 'noalias' on the first 32 parameters", .{}));
3401 break :is_comptime false;
3402 },
3403 .keyword_comptime => true,
3404 else => false,
3405 } else false;
33933406
33943407 const is_anytype = if (param.anytype_ellipsis3) |token| blk: {
33953408 switch (token_tags[token]) {
......@@ -3576,6 +3589,7 @@ fn fnDecl(
35763589 .is_inferred_error = false,
35773590 .is_test = false,
35783591 .is_extern = true,
3592 .noalias_bits = noalias_bits,
35793593 });
35803594 } else func: {
35813595 if (is_var_args) {
......@@ -3623,6 +3637,7 @@ fn fnDecl(
36233637 .is_inferred_error = is_inferred_error,
36243638 .is_test = false,
36253639 .is_extern = false,
3640 .noalias_bits = noalias_bits,
36263641 });
36273642 };
36283643
......@@ -4057,6 +4072,7 @@ fn testDecl(
40574072 .is_inferred_error = true,
40584073 .is_test = true,
40594074 .is_extern = false,
4075 .noalias_bits = 0,
40604076 });
40614077
40624078 _ = try decl_block.addBreak(.break_inline, block_inst, func_inst);
......@@ -10024,6 +10040,7 @@ const GenZir = struct {
1002410040 ret_ref: Zir.Inst.Ref,
1002510041
1002610042 lib_name: u32,
10043 noalias_bits: u32,
1002710044 is_var_args: bool,
1002810045 is_inferred_error: bool,
1002910046 is_test: bool,
......@@ -10071,7 +10088,7 @@ const GenZir = struct {
1007110088 if (args.cc_ref != .none or args.lib_name != 0 or
1007210089 args.is_var_args or args.is_test or args.is_extern or
1007310090 args.align_ref != .none or args.section_ref != .none or
10074 args.addrspace_ref != .none)
10091 args.addrspace_ref != .none or args.noalias_bits != 0)
1007510092 {
1007610093 var align_body: []Zir.Inst.Index = &.{};
1007710094 var addrspace_body: []Zir.Inst.Index = &.{};
......@@ -10093,7 +10110,8 @@ const GenZir = struct {
1009310110 fancyFnExprExtraLen(cc_body, args.cc_ref) +
1009410111 fancyFnExprExtraLen(ret_body, ret_ref) +
1009510112 body.len + src_locs.len +
10096 @boolToInt(args.lib_name != 0),
10113 @boolToInt(args.lib_name != 0) +
10114 @boolToInt(args.noalias_bits != 0),
1009710115 );
1009810116 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.FuncFancy{
1009910117 .param_block = args.param_block,
......@@ -10104,6 +10122,7 @@ const GenZir = struct {
1010410122 .is_test = args.is_test,
1010510123 .is_extern = args.is_extern,
1010610124 .has_lib_name = args.lib_name != 0,
10125 .has_any_noalias = args.noalias_bits != 0,
1010710126
1010810127 .has_align_ref = args.align_ref != .none,
1010910128 .has_addrspace_ref = args.addrspace_ref != .none,
......@@ -10159,6 +10178,10 @@ const GenZir = struct {
1015910178 astgen.extra.appendAssumeCapacity(@enumToInt(ret_ref));
1016010179 }
1016110180
10181 if (args.noalias_bits != 0) {
10182 astgen.extra.appendAssumeCapacity(args.noalias_bits);
10183 }
10184
1016210185 astgen.extra.appendSliceAssumeCapacity(body);
1016310186 astgen.extra.appendSliceAssumeCapacity(src_locs);
1016410187
src/Sema.zig+12-5
......@@ -6565,12 +6565,10 @@ fn zirFunc(
65656565 has_body,
65666566 src_locs,
65676567 null,
6568 0,
65686569 );
65696570}
65706571
6571// TODO this function and its callsites along with funcCommon need to be reworked
6572// to handle when callconv, align, linksection, addrspace depend on comptime values
6573// (thus triggering error.GenericPoison)
65746572fn resolveGenericBody(
65756573 sema: *Sema,
65766574 block: *Block,
......@@ -6696,6 +6694,7 @@ fn funcCommon(
66966694 has_body: bool,
66976695 src_locs: Zir.Inst.Func.SrcLocs,
66986696 opt_lib_name: ?[]const u8,
6697 noalias_bits: u32,
66996698) CompileError!Air.Inst.Ref {
67006699 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset };
67016700
......@@ -6807,6 +6806,7 @@ fn funcCommon(
68076806 .addrspace_is_generic = address_space == null,
68086807 .is_var_args = var_args,
68096808 .is_generic = is_generic,
6809 .noalias_bits = noalias_bits,
68106810 });
68116811 };
68126812
......@@ -9626,7 +9626,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
96269626 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
96279627 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
96289628
9629 // In `**` rhs has to be comptime-known, but lhs can be runtime-known
9629 // In `**` rhs must be comptime-known, but lhs can be runtime-known
96309630 const factor = try sema.resolveInt(block, rhs_src, extra.rhs, Type.usize);
96319631
96329632 if (lhs_ty.isTuple()) {
......@@ -11916,7 +11916,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1191611916
1191711917 try sema.queueFullTypeResolution(try error_field_ty.copy(sema.arena));
1191811918
11919 // If the error set is inferred it has to be resolved at this point
11919 // If the error set is inferred it must be resolved at this point
1192011920 try sema.resolveInferredErrorSetTy(block, src, ty);
1192111921
1192211922 // Build our list of Error values
......@@ -16970,6 +16970,12 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
1697016970 break :blk ty;
1697116971 } else Type.void;
1697216972
16973 const noalias_bits: u32 = if (extra.data.bits.has_any_noalias) blk: {
16974 const x = sema.code.extra[extra_index];
16975 extra_index += 1;
16976 break :blk x;
16977 } else 0;
16978
1697316979 var src_locs: Zir.Inst.Func.SrcLocs = undefined;
1697416980 const has_body = extra.data.body_len != 0;
1697516981 if (has_body) {
......@@ -16996,6 +17002,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
1699617002 has_body,
1699717003 src_locs,
1699817004 lib_name,
17005 noalias_bits,
1699917006 );
1700017007}
1700117008
src/Zir.zig+11-3
......@@ -2670,8 +2670,10 @@ pub const Inst = struct {
26702670 /// 14. ret_ty_body_len: u32
26712671 /// 15. ret_ty_body: u32 // for each ret_ty_body_len
26722672 /// }
2673 /// 16. body: Index // for each body_len
2674 /// 17. src_locs: Func.SrcLocs // if body_len != 0
2673 /// 16. noalias_bits: u32 // if has_any_noalias
2674 /// - each bit starting with LSB corresponds to parameter indexes
2675 /// 17. body: Index // for each body_len
2676 /// 18. src_locs: Func.SrcLocs // if body_len != 0
26752677 pub const FuncFancy = struct {
26762678 /// Points to the block that contains the param instructions for this function.
26772679 param_block: Index,
......@@ -2699,7 +2701,8 @@ pub const Inst = struct {
26992701 has_ret_ty_ref: bool,
27002702 has_ret_ty_body: bool,
27012703 has_lib_name: bool,
2702 _: u17 = undefined,
2704 has_any_noalias: bool,
2705 _: u16 = undefined,
27032706 };
27042707 };
27052708
......@@ -3699,6 +3702,8 @@ fn findDeclsInner(
36993702 extra_index += 1;
37003703 }
37013704
3705 extra_index += @boolToInt(extra.data.bits.has_any_noalias);
3706
37023707 const body = zir.extra[extra_index..][0..extra.data.body_len];
37033708 return zir.findDeclsBody(list, body);
37043709 },
......@@ -3906,6 +3911,9 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {
39063911 ret_ty_ref = @intToEnum(Inst.Ref, zir.extra[extra_index]);
39073912 extra_index += 1;
39083913 }
3914
3915 extra_index += @boolToInt(extra.data.bits.has_any_noalias);
3916
39093917 const body = zir.extra[extra_index..][0..extra.data.body_len];
39103918 extra_index += body.len;
39113919 break :blk .{
src/codegen/llvm.zig+5-1
......@@ -725,8 +725,12 @@ pub const Object = struct {
725725 try args.append(param);
726726
727727 if (param_ty.isPtrAtRuntime()) {
728 // TODO noalias attribute
729728 const ptr_info = param_ty.ptrInfo().data;
729 if (math.cast(u5, it.zig_index - 1)) |i| {
730 if (@truncate(u1, fn_info.noalias_bits >> i) != 0) {
731 dg.addArgAttr(llvm_func, llvm_arg_i, "noalias");
732 }
733 }
730734 if (!param_ty.isPtrLikeOptional() and !ptr_info.@"allowzero") {
731735 dg.addArgAttr(llvm_func, llvm_arg_i, "nonnull");
732736 }
src/print_zir.zig+13
......@@ -1961,6 +1961,7 @@ const Writer = struct {
19611961 body,
19621962 src,
19631963 src_locs,
1964 0,
19641965 );
19651966 }
19661967
......@@ -2034,6 +2035,12 @@ const Writer = struct {
20342035 extra_index += 1;
20352036 }
20362037
2038 const noalias_bits: u32 = if (extra.data.bits.has_any_noalias) blk: {
2039 const x = self.code.extra[extra_index];
2040 extra_index += 1;
2041 break :blk x;
2042 } else 0;
2043
20372044 const body = self.code.extra[extra_index..][0..extra.data.body_len];
20382045 extra_index += body.len;
20392046
......@@ -2059,6 +2066,7 @@ const Writer = struct {
20592066 body,
20602067 src,
20612068 src_locs,
2069 noalias_bits,
20622070 );
20632071 }
20642072
......@@ -2216,6 +2224,7 @@ const Writer = struct {
22162224 body: []const Zir.Inst.Index,
22172225 src: LazySrcLoc,
22182226 src_locs: Zir.Inst.Func.SrcLocs,
2227 noalias_bits: u32,
22192228 ) !void {
22202229 try self.writeOptionalInstRefOrBody(stream, "align=", align_ref, align_body);
22212230 try self.writeOptionalInstRefOrBody(stream, "addrspace=", addrspace_ref, addrspace_body);
......@@ -2226,6 +2235,10 @@ const Writer = struct {
22262235 try self.writeFlag(stream, "extern, ", is_extern);
22272236 try self.writeFlag(stream, "inferror, ", inferred_error_set);
22282237
2238 if (noalias_bits != 0) {
2239 try stream.print("noalias=0b{b}, ", .{noalias_bits});
2240 }
2241
22292242 try stream.writeAll("body=");
22302243 try self.writeBracedBody(stream, body);
22312244 try stream.writeAll(") ");
src/type.zig+34-4
......@@ -646,6 +646,9 @@ pub const Type = extern union {
646646 if (a_info.is_generic != b_info.is_generic)
647647 return false;
648648
649 if (a_info.noalias_bits != b_info.noalias_bits)
650 return false;
651
649652 if (!a_info.cc_is_generic and a_info.cc != b_info.cc)
650653 return false;
651654
......@@ -1047,6 +1050,7 @@ pub const Type = extern union {
10471050 }
10481051 std.hash.autoHash(hasher, fn_info.is_var_args);
10491052 std.hash.autoHash(hasher, fn_info.is_generic);
1053 std.hash.autoHash(hasher, fn_info.noalias_bits);
10501054
10511055 std.hash.autoHash(hasher, fn_info.param_types.len);
10521056 for (fn_info.param_types) |param_ty, i| {
......@@ -1424,6 +1428,11 @@ pub const Type = extern union {
14241428 .is_var_args = payload.is_var_args,
14251429 .is_generic = payload.is_generic,
14261430 .comptime_params = comptime_params.ptr,
1431 .align_is_generic = payload.align_is_generic,
1432 .cc_is_generic = payload.cc_is_generic,
1433 .section_is_generic = payload.section_is_generic,
1434 .addrspace_is_generic = payload.addrspace_is_generic,
1435 .noalias_bits = payload.noalias_bits,
14271436 });
14281437 },
14291438 .pointer => {
......@@ -4738,6 +4747,11 @@ pub const Type = extern union {
47384747 .alignment = 0,
47394748 .is_var_args = false,
47404749 .is_generic = false,
4750 .align_is_generic = false,
4751 .cc_is_generic = false,
4752 .section_is_generic = false,
4753 .addrspace_is_generic = false,
4754 .noalias_bits = 0,
47414755 },
47424756 .fn_void_no_args => .{
47434757 .param_types = &.{},
......@@ -4747,6 +4761,11 @@ pub const Type = extern union {
47474761 .alignment = 0,
47484762 .is_var_args = false,
47494763 .is_generic = false,
4764 .align_is_generic = false,
4765 .cc_is_generic = false,
4766 .section_is_generic = false,
4767 .addrspace_is_generic = false,
4768 .noalias_bits = 0,
47504769 },
47514770 .fn_naked_noreturn_no_args => .{
47524771 .param_types = &.{},
......@@ -4756,6 +4775,11 @@ pub const Type = extern union {
47564775 .alignment = 0,
47574776 .is_var_args = false,
47584777 .is_generic = false,
4778 .align_is_generic = false,
4779 .cc_is_generic = false,
4780 .section_is_generic = false,
4781 .addrspace_is_generic = false,
4782 .noalias_bits = 0,
47594783 },
47604784 .fn_ccc_void_no_args => .{
47614785 .param_types = &.{},
......@@ -4765,6 +4789,11 @@ pub const Type = extern union {
47654789 .alignment = 0,
47664790 .is_var_args = false,
47674791 .is_generic = false,
4792 .align_is_generic = false,
4793 .cc_is_generic = false,
4794 .section_is_generic = false,
4795 .addrspace_is_generic = false,
4796 .noalias_bits = 0,
47684797 },
47694798 .function => ty.castTag(.function).?.data,
47704799
......@@ -6123,13 +6152,14 @@ pub const Type = extern union {
61236152 return_type: Type,
61246153 /// If zero use default target function code alignment.
61256154 alignment: u32,
6155 noalias_bits: u32,
61266156 cc: std.builtin.CallingConvention,
61276157 is_var_args: bool,
61286158 is_generic: bool,
6129 align_is_generic: bool = false,
6130 cc_is_generic: bool = false,
6131 section_is_generic: bool = false,
6132 addrspace_is_generic: bool = false,
6159 align_is_generic: bool,
6160 cc_is_generic: bool,
6161 section_is_generic: bool,
6162 addrspace_is_generic: bool,
61336163
61346164 pub fn paramIsComptime(self: @This(), i: usize) bool {
61356165 assert(i < self.param_types.len);