| ... | ... | @@ -537,6 +537,32 @@ pub const Key = union(enum) { |
| 537 | 537 | assert(i < self.param_types.len); |
| 538 | 538 | return @as(u1, @truncate(self.noalias_bits >> i)) != 0; |
| 539 | 539 | } |
| 540 | |
| 541 | pub fn eql(a: FuncType, b: FuncType, ip: *const InternPool) bool { |
| 542 | return std.mem.eql(Index, a.param_types.get(ip), b.param_types.get(ip)) and |
| 543 | a.return_type == b.return_type and |
| 544 | a.comptime_bits == b.comptime_bits and |
| 545 | a.noalias_bits == b.noalias_bits and |
| 546 | a.alignment == b.alignment and |
| 547 | a.cc == b.cc and |
| 548 | a.is_var_args == b.is_var_args and |
| 549 | a.is_generic == b.is_generic and |
| 550 | a.is_noinline == b.is_noinline; |
| 551 | } |
| 552 | |
| 553 | pub fn hash(self: FuncType, hasher: *Hash, ip: *const InternPool) void { |
| 554 | for (self.param_types.get(ip)) |param_type| { |
| 555 | std.hash.autoHash(hasher, param_type); |
| 556 | } |
| 557 | std.hash.autoHash(hasher, self.return_type); |
| 558 | std.hash.autoHash(hasher, self.comptime_bits); |
| 559 | std.hash.autoHash(hasher, self.noalias_bits); |
| 560 | std.hash.autoHash(hasher, self.alignment); |
| 561 | std.hash.autoHash(hasher, self.cc); |
| 562 | std.hash.autoHash(hasher, self.is_var_args); |
| 563 | std.hash.autoHash(hasher, self.is_generic); |
| 564 | std.hash.autoHash(hasher, self.is_noinline); |
| 565 | } |
| 540 | 566 | }; |
| 541 | 567 | |
| 542 | 568 | pub const Variable = struct { |
| ... | ... | @@ -572,6 +598,7 @@ pub const Key = union(enum) { |
| 572 | 598 | zir_body_inst_extra_index: u32, |
| 573 | 599 | /// Index into extra array of the resolved inferred error set for this function. |
| 574 | 600 | /// Used for mutating that data. |
| 601 | /// 0 when the function does not have an inferred error set. |
| 575 | 602 | resolved_error_set_extra_index: u32, |
| 576 | 603 | /// When a generic function is instantiated, branch_quota is inherited from the |
| 577 | 604 | /// active Sema context. Importantly, this value is also updated when an existing |
| ... | ... | @@ -942,17 +969,7 @@ pub const Key = union(enum) { |
| 942 | 969 | |
| 943 | 970 | .func_type => |func_type| { |
| 944 | 971 | var hasher = Hash.init(seed); |
| 945 | | for (func_type.param_types.get(ip)) |param_type| { |
| 946 | | std.hash.autoHash(&hasher, param_type); |
| 947 | | } |
| 948 | | std.hash.autoHash(&hasher, func_type.return_type); |
| 949 | | std.hash.autoHash(&hasher, func_type.comptime_bits); |
| 950 | | std.hash.autoHash(&hasher, func_type.noalias_bits); |
| 951 | | std.hash.autoHash(&hasher, func_type.alignment); |
| 952 | | std.hash.autoHash(&hasher, func_type.cc); |
| 953 | | std.hash.autoHash(&hasher, func_type.is_var_args); |
| 954 | | std.hash.autoHash(&hasher, func_type.is_generic); |
| 955 | | std.hash.autoHash(&hasher, func_type.is_noinline); |
| 972 | func_type.hash(&hasher, ip); |
| 956 | 973 | return hasher.final(); |
| 957 | 974 | }, |
| 958 | 975 | |
| ... | ... | @@ -964,13 +981,24 @@ pub const Key = union(enum) { |
| 964 | 981 | }, |
| 965 | 982 | |
| 966 | 983 | .func => |func| { |
| 967 | | if (func.generic_owner == .none) |
| 984 | // In the case of a function with an inferred error set, we |
| 985 | // must not include the inferred error set type in the hash, |
| 986 | // otherwise we would get false negatives for interning generic |
| 987 | // function instances which have inferred error sets. |
| 988 | |
| 989 | if (func.generic_owner == .none and func.resolved_error_set_extra_index == 0) |
| 968 | 990 | return Hash.hash(seed, asBytes(&func.owner_decl) ++ asBytes(&func.ty)); |
| 969 | 991 | |
| 970 | 992 | var hasher = Hash.init(seed); |
| 971 | 993 | std.hash.autoHash(&hasher, func.generic_owner); |
| 972 | 994 | for (func.comptime_args.get(ip)) |arg| std.hash.autoHash(&hasher, arg); |
| 973 | | std.hash.autoHash(&hasher, func.ty); |
| 995 | if (func.resolved_error_set_extra_index == 0) { |
| 996 | std.hash.autoHash(&hasher, func.ty); |
| 997 | } else { |
| 998 | var ty_info = ip.indexToFuncType(func.ty).?; |
| 999 | ty_info.return_type = ip.errorUnionPayload(ty_info.return_type); |
| 1000 | ty_info.hash(&hasher, ip); |
| 1001 | } |
| 974 | 1002 | return hasher.final(); |
| 975 | 1003 | }, |
| 976 | 1004 | |
| ... | ... | @@ -1079,13 +1107,37 @@ pub const Key = union(enum) { |
| 1079 | 1107 | if (a_info.generic_owner != b_info.generic_owner) |
| 1080 | 1108 | return false; |
| 1081 | 1109 | |
| 1082 | | if (a_info.ty != b_info.ty) |
| 1083 | | return false; |
| 1110 | if (a_info.generic_owner == .none) { |
| 1111 | if (a_info.owner_decl != b_info.owner_decl) |
| 1112 | return false; |
| 1113 | } else { |
| 1114 | if (!std.mem.eql( |
| 1115 | Index, |
| 1116 | a_info.comptime_args.get(ip), |
| 1117 | b_info.comptime_args.get(ip), |
| 1118 | )) return false; |
| 1119 | } |
| 1084 | 1120 | |
| 1085 | | if (a_info.generic_owner == .none) |
| 1086 | | return a_info.owner_decl == b_info.owner_decl; |
| 1121 | if (a_info.ty == b_info.ty) |
| 1122 | return true; |
| 1087 | 1123 | |
| 1088 | | return std.mem.eql(Index, a_info.comptime_args.get(ip), b_info.comptime_args.get(ip)); |
| 1124 | // There is one case where the types may be inequal but we |
| 1125 | // still want to find the same function body instance. In the |
| 1126 | // case of the functions having an inferred error set, the key |
| 1127 | // used to find an existing function body will necessarily have |
| 1128 | // a unique inferred error set type, because it refers to the |
| 1129 | // function body InternPool Index. To make this case work we |
| 1130 | // omit the inferred error set from the equality check. |
| 1131 | if (a_info.resolved_error_set_extra_index == 0 or |
| 1132 | b_info.resolved_error_set_extra_index == 0) |
| 1133 | { |
| 1134 | return false; |
| 1135 | } |
| 1136 | var a_ty_info = ip.indexToFuncType(a_info.ty).?; |
| 1137 | a_ty_info.return_type = ip.errorUnionPayload(a_ty_info.return_type); |
| 1138 | var b_ty_info = ip.indexToFuncType(b_info.ty).?; |
| 1139 | b_ty_info.return_type = ip.errorUnionPayload(a_ty_info.return_type); |
| 1140 | return a_ty_info.eql(b_ty_info, ip); |
| 1089 | 1141 | }, |
| 1090 | 1142 | |
| 1091 | 1143 | .ptr => |a_info| { |
| ... | ... | @@ -1246,16 +1298,7 @@ pub const Key = union(enum) { |
| 1246 | 1298 | |
| 1247 | 1299 | .func_type => |a_info| { |
| 1248 | 1300 | const b_info = b.func_type; |
| 1249 | | |
| 1250 | | return std.mem.eql(Index, a_info.param_types.get(ip), b_info.param_types.get(ip)) and |
| 1251 | | a_info.return_type == b_info.return_type and |
| 1252 | | a_info.comptime_bits == b_info.comptime_bits and |
| 1253 | | a_info.noalias_bits == b_info.noalias_bits and |
| 1254 | | a_info.alignment == b_info.alignment and |
| 1255 | | a_info.cc == b_info.cc and |
| 1256 | | a_info.is_var_args == b_info.is_var_args and |
| 1257 | | a_info.is_generic == b_info.is_generic and |
| 1258 | | a_info.is_noinline == b_info.is_noinline; |
| 1301 | return Key.FuncType.eql(a_info, b_info, ip); |
| 1259 | 1302 | }, |
| 1260 | 1303 | |
| 1261 | 1304 | .memoized_call => |a_info| { |
| ... | ... | @@ -2156,7 +2199,6 @@ pub const Tag = enum(u8) { |
| 2156 | 2199 | const Error = Key.Error; |
| 2157 | 2200 | const EnumTag = Key.EnumTag; |
| 2158 | 2201 | const ExternFunc = Key.ExternFunc; |
| 2159 | | const Func = Key.Func; |
| 2160 | 2202 | const Union = Key.Union; |
| 2161 | 2203 | const TypePointer = Key.PtrType; |
| 2162 | 2204 | |
| ... | ... | @@ -3137,7 +3179,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { |
| 3137 | 3179 | }, |
| 3138 | 3180 | .extern_func => .{ .extern_func = ip.extraData(Tag.ExternFunc, data) }, |
| 3139 | 3181 | .func_instance => .{ .func = ip.indexToKeyFuncInstance(data) }, |
| 3140 | | .func_decl => .{ .func = ip.indexToKeyFuncDecl(data) }, |
| 3182 | .func_decl => .{ .func = ip.extraIndexToFuncDecl(data) }, |
| 3141 | 3183 | .only_possible_value => { |
| 3142 | 3184 | const ty = @as(Index, @enumFromInt(data)); |
| 3143 | 3185 | const ty_item = ip.items.get(@intFromEnum(ty)); |
| ... | ... | @@ -3286,9 +3328,9 @@ fn extraFuncType(ip: *const InternPool, extra_index: u32) Key.FuncType { |
| 3286 | 3328 | }; |
| 3287 | 3329 | } |
| 3288 | 3330 | |
| 3289 | | fn indexToKeyFuncDecl(ip: *const InternPool, data: u32) Key.Func { |
| 3331 | fn extraIndexToFuncDecl(ip: *const InternPool, extra_index: u32) Key.Func { |
| 3290 | 3332 | _ = ip; |
| 3291 | | _ = data; |
| 3333 | _ = extra_index; |
| 3292 | 3334 | @panic("TODO"); |
| 3293 | 3335 | } |
| 3294 | 3336 | |
| ... | ... | @@ -4357,38 +4399,41 @@ pub fn getFuncDecl(ip: *InternPool, gpa: Allocator, key: GetFuncDeclKey) Allocat |
| 4357 | 4399 | |
| 4358 | 4400 | try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Tag.FuncDecl).Struct.fields.len); |
| 4359 | 4401 | try ip.items.ensureUnusedCapacity(gpa, 1); |
| 4402 | try ip.map.ensureUnusedCapacity(gpa, 1); |
| 4360 | 4403 | |
| 4361 | | ip.items.appendAssumeCapacity(.{ |
| 4362 | | .tag = .func_decl, |
| 4363 | | .data = ip.addExtraAssumeCapacity(Tag.FuncDecl{ |
| 4364 | | .analysis = .{ |
| 4365 | | .state = if (key.cc == .Inline) .inline_only else .none, |
| 4366 | | .is_cold = false, |
| 4367 | | .is_noinline = key.is_noinline, |
| 4368 | | .calls_or_awaits_errorable_fn = false, |
| 4369 | | .stack_alignment = .none, |
| 4370 | | .inferred_error_set = false, |
| 4371 | | }, |
| 4372 | | .owner_decl = key.owner_decl, |
| 4373 | | .ty = key.ty, |
| 4374 | | .zir_body_inst = key.zir_body_inst, |
| 4375 | | .lbrace_line = key.lbrace_line, |
| 4376 | | .rbrace_line = key.rbrace_line, |
| 4377 | | .lbrace_column = key.lbrace_column, |
| 4378 | | .rbrace_column = key.rbrace_column, |
| 4379 | | }), |
| 4404 | const func_decl_extra_index = ip.addExtraAssumeCapacity(Tag.FuncDecl{ |
| 4405 | .analysis = .{ |
| 4406 | .state = if (key.cc == .Inline) .inline_only else .none, |
| 4407 | .is_cold = false, |
| 4408 | .is_noinline = key.is_noinline, |
| 4409 | .calls_or_awaits_errorable_fn = false, |
| 4410 | .stack_alignment = .none, |
| 4411 | .inferred_error_set = false, |
| 4412 | }, |
| 4413 | .owner_decl = key.owner_decl, |
| 4414 | .ty = key.ty, |
| 4415 | .zir_body_inst = key.zir_body_inst, |
| 4416 | .lbrace_line = key.lbrace_line, |
| 4417 | .rbrace_line = key.rbrace_line, |
| 4418 | .lbrace_column = key.lbrace_column, |
| 4419 | .rbrace_column = key.rbrace_column, |
| 4380 | 4420 | }); |
| 4381 | 4421 | |
| 4382 | 4422 | const adapter: KeyAdapter = .{ .intern_pool = ip }; |
| 4383 | | const gop = try ip.map.getOrPutAdapted(gpa, Key{ |
| 4384 | | .func = indexToKeyFuncDecl(ip, @intCast(ip.items.len - 1)), |
| 4423 | const gop = ip.map.getOrPutAssumeCapacityAdapted(Key{ |
| 4424 | .func = extraIndexToFuncDecl(ip, func_decl_extra_index), |
| 4385 | 4425 | }, adapter); |
| 4386 | | if (!gop.found_existing) return @enumFromInt(ip.items.len - 1); |
| 4387 | 4426 | |
| 4388 | | // An existing function type was found; undo the additions to our two arrays. |
| 4389 | | ip.items.len -= 1; |
| 4390 | | ip.extra.items.len = prev_extra_len; |
| 4391 | | return @enumFromInt(gop.index); |
| 4427 | if (gop.found_existing) { |
| 4428 | ip.extra.items.len = prev_extra_len; |
| 4429 | return @enumFromInt(gop.index); |
| 4430 | } |
| 4431 | |
| 4432 | ip.items.appendAssumeCapacity(.{ |
| 4433 | .tag = .func_decl, |
| 4434 | .data = func_decl_extra_index, |
| 4435 | }); |
| 4436 | return @enumFromInt(ip.items.len - 1); |
| 4392 | 4437 | } |
| 4393 | 4438 | |
| 4394 | 4439 | pub const GetFuncDeclIesKey = struct { |
| ... | ... | @@ -4434,25 +4479,27 @@ pub fn getFuncDeclIes(ip: *InternPool, gpa: Allocator, key: GetFuncDeclIesKey) A |
| 4434 | 4479 | params_len); |
| 4435 | 4480 | try ip.items.ensureUnusedCapacity(gpa, 4); |
| 4436 | 4481 | |
| 4482 | const func_decl_extra_index = ip.addExtraAssumeCapacity(Tag.FuncDecl{ |
| 4483 | .analysis = .{ |
| 4484 | .state = if (key.cc == .Inline) .inline_only else .none, |
| 4485 | .is_cold = false, |
| 4486 | .is_noinline = key.is_noinline, |
| 4487 | .calls_or_awaits_errorable_fn = false, |
| 4488 | .stack_alignment = .none, |
| 4489 | .inferred_error_set = true, |
| 4490 | }, |
| 4491 | .owner_decl = key.owner_decl, |
| 4492 | .ty = @enumFromInt(ip.items.len + 1), |
| 4493 | .zir_body_inst = key.zir_body_inst, |
| 4494 | .lbrace_line = key.lbrace_line, |
| 4495 | .rbrace_line = key.rbrace_line, |
| 4496 | .lbrace_column = key.lbrace_column, |
| 4497 | .rbrace_column = key.rbrace_column, |
| 4498 | }); |
| 4499 | |
| 4437 | 4500 | ip.items.appendAssumeCapacity(.{ |
| 4438 | 4501 | .tag = .func_decl, |
| 4439 | | .data = ip.addExtraAssumeCapacity(Tag.FuncDecl{ |
| 4440 | | .analysis = .{ |
| 4441 | | .state = if (key.cc == .Inline) .inline_only else .none, |
| 4442 | | .is_cold = false, |
| 4443 | | .is_noinline = key.is_noinline, |
| 4444 | | .calls_or_awaits_errorable_fn = false, |
| 4445 | | .stack_alignment = .none, |
| 4446 | | .inferred_error_set = true, |
| 4447 | | }, |
| 4448 | | .owner_decl = key.owner_decl, |
| 4449 | | .ty = @enumFromInt(ip.items.len + 1), |
| 4450 | | .zir_body_inst = key.zir_body_inst, |
| 4451 | | .lbrace_line = key.lbrace_line, |
| 4452 | | .rbrace_line = key.rbrace_line, |
| 4453 | | .lbrace_column = key.lbrace_column, |
| 4454 | | .rbrace_column = key.rbrace_column, |
| 4455 | | }), |
| 4502 | .data = func_decl_extra_index, |
| 4456 | 4503 | }); |
| 4457 | 4504 | ip.extra.appendAssumeCapacity(@intFromEnum(Index.none)); |
| 4458 | 4505 | |
| ... | ... | @@ -4497,7 +4544,7 @@ pub fn getFuncDeclIes(ip: *InternPool, gpa: Allocator, key: GetFuncDeclIesKey) A |
| 4497 | 4544 | |
| 4498 | 4545 | const adapter: KeyAdapter = .{ .intern_pool = ip }; |
| 4499 | 4546 | const gop = ip.map.getOrPutAssumeCapacityAdapted(Key{ |
| 4500 | | .func = indexToKeyFuncDecl(ip, @intCast(ip.items.len - 4)), |
| 4547 | .func = extraIndexToFuncDecl(ip, func_decl_extra_index), |
| 4501 | 4548 | }, adapter); |
| 4502 | 4549 | if (!gop.found_existing) { |
| 4503 | 4550 | assert(!ip.map.getOrPutAssumeCapacityAdapted(Key{ .error_union_type = .{ |
| ... | ... | @@ -5570,6 +5617,10 @@ pub fn errorUnionSet(ip: *const InternPool, ty: Index) Index { |
| 5570 | 5617 | return ip.indexToKey(ty).error_union_type.error_set_type; |
| 5571 | 5618 | } |
| 5572 | 5619 | |
| 5620 | pub fn errorUnionPayload(ip: *const InternPool, ty: Index) Index { |
| 5621 | return ip.indexToKey(ty).error_union_type.payload_type; |
| 5622 | } |
| 5623 | |
| 5573 | 5624 | /// The is only legal because the initializer is not part of the hash. |
| 5574 | 5625 | pub fn mutateVarInit(ip: *InternPool, index: Index, init_index: Index) void { |
| 5575 | 5626 | const item = ip.items.get(@intFromEnum(index)); |
| ... | ... | @@ -5738,7 +5789,7 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void { |
| 5738 | 5789 | .float_comptime_float => @sizeOf(Float128), |
| 5739 | 5790 | .variable => @sizeOf(Tag.Variable) + @sizeOf(Module.Decl), |
| 5740 | 5791 | .extern_func => @sizeOf(Tag.ExternFunc) + @sizeOf(Module.Decl), |
| 5741 | | .func_decl => @sizeOf(Tag.Func) + @sizeOf(Module.Decl), |
| 5792 | .func_decl => @sizeOf(Tag.FuncDecl) + @sizeOf(Module.Decl), |
| 5742 | 5793 | .func_instance => b: { |
| 5743 | 5794 | const info = ip.extraData(Tag.FuncInstance, data); |
| 5744 | 5795 | const ty = ip.typeOf(info.generic_owner); |