| ... | @@ -537,6 +537,32 @@ pub const Key = union(enum) { | ... | @@ -537,6 +537,32 @@ pub const Key = union(enum) { |
| 537 | assert(i < self.param_types.len); | 537 | assert(i < self.param_types.len); |
| 538 | return @as(u1, @truncate(self.noalias_bits >> i)) != 0; | 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 | pub const Variable = struct { | 568 | pub const Variable = struct { |
| ... | @@ -572,6 +598,7 @@ pub const Key = union(enum) { | ... | @@ -572,6 +598,7 @@ pub const Key = union(enum) { |
| 572 | zir_body_inst_extra_index: u32, | 598 | zir_body_inst_extra_index: u32, |
| 573 | /// Index into extra array of the resolved inferred error set for this function. | 599 | /// Index into extra array of the resolved inferred error set for this function. |
| 574 | /// Used for mutating that data. | 600 | /// Used for mutating that data. |
| | 601 | /// 0 when the function does not have an inferred error set. |
| 575 | resolved_error_set_extra_index: u32, | 602 | resolved_error_set_extra_index: u32, |
| 576 | /// When a generic function is instantiated, branch_quota is inherited from the | 603 | /// When a generic function is instantiated, branch_quota is inherited from the |
| 577 | /// active Sema context. Importantly, this value is also updated when an existing | 604 | /// active Sema context. Importantly, this value is also updated when an existing |
| ... | @@ -942,17 +969,7 @@ pub const Key = union(enum) { | ... | @@ -942,17 +969,7 @@ pub const Key = union(enum) { |
| 942 | | 969 | |
| 943 | .func_type => |func_type| { | 970 | .func_type => |func_type| { |
| 944 | var hasher = Hash.init(seed); | 971 | var hasher = Hash.init(seed); |
| 945 | for (func_type.param_types.get(ip)) |param_type| { | 972 | func_type.hash(&hasher, ip); |
| 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); | | |
| 956 | return hasher.final(); | 973 | return hasher.final(); |
| 957 | }, | 974 | }, |
| 958 | | 975 | |
| ... | @@ -964,13 +981,24 @@ pub const Key = union(enum) { | ... | @@ -964,13 +981,24 @@ pub const Key = union(enum) { |
| 964 | }, | 981 | }, |
| 965 | | 982 | |
| 966 | .func => |func| { | 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 | return Hash.hash(seed, asBytes(&func.owner_decl) ++ asBytes(&func.ty)); | 990 | return Hash.hash(seed, asBytes(&func.owner_decl) ++ asBytes(&func.ty)); |
| 969 | | 991 | |
| 970 | var hasher = Hash.init(seed); | 992 | var hasher = Hash.init(seed); |
| 971 | std.hash.autoHash(&hasher, func.generic_owner); | 993 | std.hash.autoHash(&hasher, func.generic_owner); |
| 972 | for (func.comptime_args.get(ip)) |arg| std.hash.autoHash(&hasher, arg); | 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 | return hasher.final(); | 1002 | return hasher.final(); |
| 975 | }, | 1003 | }, |
| 976 | | 1004 | |
| ... | @@ -1079,13 +1107,37 @@ pub const Key = union(enum) { | ... | @@ -1079,13 +1107,37 @@ pub const Key = union(enum) { |
| 1079 | if (a_info.generic_owner != b_info.generic_owner) | 1107 | if (a_info.generic_owner != b_info.generic_owner) |
| 1080 | return false; | 1108 | return false; |
| 1081 | | 1109 | |
| 1082 | if (a_info.ty != b_info.ty) | 1110 | if (a_info.generic_owner == .none) { |
| 1083 | return false; | 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) | 1121 | if (a_info.ty == b_info.ty) |
| 1086 | return a_info.owner_decl == b_info.owner_decl; | 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 | .ptr => |a_info| { | 1143 | .ptr => |a_info| { |
| ... | @@ -1246,16 +1298,7 @@ pub const Key = union(enum) { | ... | @@ -1246,16 +1298,7 @@ pub const Key = union(enum) { |
| 1246 | | 1298 | |
| 1247 | .func_type => |a_info| { | 1299 | .func_type => |a_info| { |
| 1248 | const b_info = b.func_type; | 1300 | const b_info = b.func_type; |
| 1249 | | 1301 | return Key.FuncType.eql(a_info, b_info, ip); |
| 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; | | |
| 1259 | }, | 1302 | }, |
| 1260 | | 1303 | |
| 1261 | .memoized_call => |a_info| { | 1304 | .memoized_call => |a_info| { |
| ... | @@ -2156,7 +2199,6 @@ pub const Tag = enum(u8) { | ... | @@ -2156,7 +2199,6 @@ pub const Tag = enum(u8) { |
| 2156 | const Error = Key.Error; | 2199 | const Error = Key.Error; |
| 2157 | const EnumTag = Key.EnumTag; | 2200 | const EnumTag = Key.EnumTag; |
| 2158 | const ExternFunc = Key.ExternFunc; | 2201 | const ExternFunc = Key.ExternFunc; |
| 2159 | const Func = Key.Func; | | |
| 2160 | const Union = Key.Union; | 2202 | const Union = Key.Union; |
| 2161 | const TypePointer = Key.PtrType; | 2203 | const TypePointer = Key.PtrType; |
| 2162 | | 2204 | |
| ... | @@ -3137,7 +3179,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { | ... | @@ -3137,7 +3179,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { |
| 3137 | }, | 3179 | }, |
| 3138 | .extern_func => .{ .extern_func = ip.extraData(Tag.ExternFunc, data) }, | 3180 | .extern_func => .{ .extern_func = ip.extraData(Tag.ExternFunc, data) }, |
| 3139 | .func_instance => .{ .func = ip.indexToKeyFuncInstance(data) }, | 3181 | .func_instance => .{ .func = ip.indexToKeyFuncInstance(data) }, |
| 3140 | .func_decl => .{ .func = ip.indexToKeyFuncDecl(data) }, | 3182 | .func_decl => .{ .func = ip.extraIndexToFuncDecl(data) }, |
| 3141 | .only_possible_value => { | 3183 | .only_possible_value => { |
| 3142 | const ty = @as(Index, @enumFromInt(data)); | 3184 | const ty = @as(Index, @enumFromInt(data)); |
| 3143 | const ty_item = ip.items.get(@intFromEnum(ty)); | 3185 | const ty_item = ip.items.get(@intFromEnum(ty)); |
| ... | @@ -3286,9 +3328,9 @@ fn extraFuncType(ip: *const InternPool, extra_index: u32) Key.FuncType { | ... | @@ -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 | _ = ip; | 3332 | _ = ip; |
| 3291 | _ = data; | 3333 | _ = extra_index; |
| 3292 | @panic("TODO"); | 3334 | @panic("TODO"); |
| 3293 | } | 3335 | } |
| 3294 | | 3336 | |
| ... | @@ -4357,38 +4399,41 @@ pub fn getFuncDecl(ip: *InternPool, gpa: Allocator, key: GetFuncDeclKey) Allocat | ... | @@ -4357,38 +4399,41 @@ pub fn getFuncDecl(ip: *InternPool, gpa: Allocator, key: GetFuncDeclKey) Allocat |
| 4357 | | 4399 | |
| 4358 | try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Tag.FuncDecl).Struct.fields.len); | 4400 | try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Tag.FuncDecl).Struct.fields.len); |
| 4359 | try ip.items.ensureUnusedCapacity(gpa, 1); | 4401 | try ip.items.ensureUnusedCapacity(gpa, 1); |
| | 4402 | try ip.map.ensureUnusedCapacity(gpa, 1); |
| 4360 | | 4403 | |
| 4361 | ip.items.appendAssumeCapacity(.{ | 4404 | const func_decl_extra_index = ip.addExtraAssumeCapacity(Tag.FuncDecl{ |
| 4362 | .tag = .func_decl, | 4405 | .analysis = .{ |
| 4363 | .data = ip.addExtraAssumeCapacity(Tag.FuncDecl{ | 4406 | .state = if (key.cc == .Inline) .inline_only else .none, |
| 4364 | .analysis = .{ | 4407 | .is_cold = false, |
| 4365 | .state = if (key.cc == .Inline) .inline_only else .none, | 4408 | .is_noinline = key.is_noinline, |
| 4366 | .is_cold = false, | 4409 | .calls_or_awaits_errorable_fn = false, |
| 4367 | .is_noinline = key.is_noinline, | 4410 | .stack_alignment = .none, |
| 4368 | .calls_or_awaits_errorable_fn = false, | 4411 | .inferred_error_set = false, |
| 4369 | .stack_alignment = .none, | 4412 | }, |
| 4370 | .inferred_error_set = false, | 4413 | .owner_decl = key.owner_decl, |
| 4371 | }, | 4414 | .ty = key.ty, |
| 4372 | .owner_decl = key.owner_decl, | 4415 | .zir_body_inst = key.zir_body_inst, |
| 4373 | .ty = key.ty, | 4416 | .lbrace_line = key.lbrace_line, |
| 4374 | .zir_body_inst = key.zir_body_inst, | 4417 | .rbrace_line = key.rbrace_line, |
| 4375 | .lbrace_line = key.lbrace_line, | 4418 | .lbrace_column = key.lbrace_column, |
| 4376 | .rbrace_line = key.rbrace_line, | 4419 | .rbrace_column = key.rbrace_column, |
| 4377 | .lbrace_column = key.lbrace_column, | | |
| 4378 | .rbrace_column = key.rbrace_column, | | |
| 4379 | }), | | |
| 4380 | }); | 4420 | }); |
| 4381 | | 4421 | |
| 4382 | const adapter: KeyAdapter = .{ .intern_pool = ip }; | 4422 | const adapter: KeyAdapter = .{ .intern_pool = ip }; |
| 4383 | const gop = try ip.map.getOrPutAdapted(gpa, Key{ | 4423 | const gop = ip.map.getOrPutAssumeCapacityAdapted(Key{ |
| 4384 | .func = indexToKeyFuncDecl(ip, @intCast(ip.items.len - 1)), | 4424 | .func = extraIndexToFuncDecl(ip, func_decl_extra_index), |
| 4385 | }, adapter); | 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. | 4427 | if (gop.found_existing) { |
| 4389 | ip.items.len -= 1; | 4428 | ip.extra.items.len = prev_extra_len; |
| 4390 | ip.extra.items.len = prev_extra_len; | 4429 | return @enumFromInt(gop.index); |
| 4391 | 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 | pub const GetFuncDeclIesKey = struct { | 4439 | pub const GetFuncDeclIesKey = struct { |
| ... | @@ -4434,25 +4479,27 @@ pub fn getFuncDeclIes(ip: *InternPool, gpa: Allocator, key: GetFuncDeclIesKey) A | ... | @@ -4434,25 +4479,27 @@ pub fn getFuncDeclIes(ip: *InternPool, gpa: Allocator, key: GetFuncDeclIesKey) A |
| 4434 | params_len); | 4479 | params_len); |
| 4435 | try ip.items.ensureUnusedCapacity(gpa, 4); | 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 | ip.items.appendAssumeCapacity(.{ | 4500 | ip.items.appendAssumeCapacity(.{ |
| 4438 | .tag = .func_decl, | 4501 | .tag = .func_decl, |
| 4439 | .data = ip.addExtraAssumeCapacity(Tag.FuncDecl{ | 4502 | .data = func_decl_extra_index, |
| 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 | }), | | |
| 4456 | }); | 4503 | }); |
| 4457 | ip.extra.appendAssumeCapacity(@intFromEnum(Index.none)); | 4504 | ip.extra.appendAssumeCapacity(@intFromEnum(Index.none)); |
| 4458 | | 4505 | |
| ... | @@ -4497,7 +4544,7 @@ pub fn getFuncDeclIes(ip: *InternPool, gpa: Allocator, key: GetFuncDeclIesKey) A | ... | @@ -4497,7 +4544,7 @@ pub fn getFuncDeclIes(ip: *InternPool, gpa: Allocator, key: GetFuncDeclIesKey) A |
| 4497 | | 4544 | |
| 4498 | const adapter: KeyAdapter = .{ .intern_pool = ip }; | 4545 | const adapter: KeyAdapter = .{ .intern_pool = ip }; |
| 4499 | const gop = ip.map.getOrPutAssumeCapacityAdapted(Key{ | 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 | }, adapter); | 4548 | }, adapter); |
| 4502 | if (!gop.found_existing) { | 4549 | if (!gop.found_existing) { |
| 4503 | assert(!ip.map.getOrPutAssumeCapacityAdapted(Key{ .error_union_type = .{ | 4550 | assert(!ip.map.getOrPutAssumeCapacityAdapted(Key{ .error_union_type = .{ |
| ... | @@ -5570,6 +5617,10 @@ pub fn errorUnionSet(ip: *const InternPool, ty: Index) Index { | ... | @@ -5570,6 +5617,10 @@ pub fn errorUnionSet(ip: *const InternPool, ty: Index) Index { |
| 5570 | return ip.indexToKey(ty).error_union_type.error_set_type; | 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 | /// The is only legal because the initializer is not part of the hash. | 5624 | /// The is only legal because the initializer is not part of the hash. |
| 5574 | pub fn mutateVarInit(ip: *InternPool, index: Index, init_index: Index) void { | 5625 | pub fn mutateVarInit(ip: *InternPool, index: Index, init_index: Index) void { |
| 5575 | const item = ip.items.get(@intFromEnum(index)); | 5626 | const item = ip.items.get(@intFromEnum(index)); |
| ... | @@ -5738,7 +5789,7 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void { | ... | @@ -5738,7 +5789,7 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void { |
| 5738 | .float_comptime_float => @sizeOf(Float128), | 5789 | .float_comptime_float => @sizeOf(Float128), |
| 5739 | .variable => @sizeOf(Tag.Variable) + @sizeOf(Module.Decl), | 5790 | .variable => @sizeOf(Tag.Variable) + @sizeOf(Module.Decl), |
| 5740 | .extern_func => @sizeOf(Tag.ExternFunc) + @sizeOf(Module.Decl), | 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 | .func_instance => b: { | 5793 | .func_instance => b: { |
| 5743 | const info = ip.extraData(Tag.FuncInstance, data); | 5794 | const info = ip.extraData(Tag.FuncInstance, data); |
| 5744 | const ty = ip.typeOf(info.generic_owner); | 5795 | const ty = ip.typeOf(info.generic_owner); |