From c418f14a78acb114278bd942adc35be313a4b89e Mon Sep 17 00:00:00 2001 From: Evan Haas <evan@lagerdata.com> Date: Fri, 23 Aug 2024 08:50:51 -0700 Subject: [PATCH 01/15] Tree: remove unnecessary use of Type.canonicalize --- src/aro/Tree.zig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/aro/Tree.zig b/src/aro/Tree.zig index b82cea2f..68e16913 100644 --- a/src/aro/Tree.zig +++ b/src/aro/Tree.zig @@ -1363,12 +1363,11 @@ fn dumpNode( var lhs_ty = tree.nodes.items(.ty)[@intFromEnum(data.member.lhs)]; if (lhs_ty.isPtr()) lhs_ty = lhs_ty.elemType(); - lhs_ty = lhs_ty.canonicalize(.standard); try w.writeByteNTimes(' ', level + 1); try w.writeAll("name: "); try config.setColor(w, NAME); - try w.print("{s}\n", .{mapper.lookup(lhs_ty.data.record.fields[data.member.index].name)}); + try w.print("{s}\n", .{mapper.lookup(lhs_ty.getRecord().?.fields[data.member.index].name)}); try config.setColor(w, .reset); }, .array_access_expr => { From 241d3186706887146967d80a1d5112a53a610e21 Mon Sep 17 00:00:00 2001 From: Evan Haas <evan@lagerdata.com> Date: Fri, 23 Aug 2024 08:55:49 -0700 Subject: [PATCH 02/15] Type: add function for getting actual type specifier --- src/aro/Parser.zig | 4 ++-- src/aro/Type.zig | 56 +++++++++++++++++++++++++--------------------- 2 files changed, 32 insertions(+), 28 deletions(-) diff --git a/src/aro/Parser.zig b/src/aro/Parser.zig index c4baeb8c..02bfaf43 100644 --- a/src/aro/Parser.zig +++ b/src/aro/Parser.zig @@ -5795,8 +5795,8 @@ pub const Result = struct { .{ .invalid, .fp16 }, .{ .complex_float16, .float16 }, }; - const a_spec = a.ty.canonicalize(.standard).specifier; - const b_spec = b.ty.canonicalize(.standard).specifier; + const a_spec = a.ty.base(); + const b_spec = b.ty.base(); if (p.comp.target.cTypeBitSize(.longdouble) == 128) { if (try a.floatConversion(b, a_spec, b_spec, p, float_types[0])) return; } diff --git a/src/aro/Type.zig b/src/aro/Type.zig index ab083942..6f8d47e9 100644 --- a/src/aro/Type.zig +++ b/src/aro/Type.zig @@ -146,7 +146,7 @@ pub const Attributed = struct { attributes: []Attribute, base: Type, - pub fn create(allocator: std.mem.Allocator, base: Type, existing_attributes: []const Attribute, attributes: []const Attribute) !*Attributed { + pub fn create(allocator: std.mem.Allocator, base_ty: Type, existing_attributes: []const Attribute, attributes: []const Attribute) !*Attributed { const attributed_type = try allocator.create(Attributed); errdefer allocator.destroy(attributed_type); @@ -156,7 +156,7 @@ pub const Attributed = struct { attributed_type.* = .{ .attributes = all_attrs, - .base = base, + .base = base_ty, }; return attributed_type; } @@ -825,8 +825,8 @@ fn realIntegerConversion(a: Type, b: Type, comp: *const Compilation) Type { pub fn makeIntegerUnsigned(ty: Type) Type { // TODO discards attributed/typeof - var base = ty.canonicalize(.standard); - switch (base.specifier) { + var base_ty = ty.canonicalize(.standard); + switch (base_ty.specifier) { // zig fmt: off .uchar, .ushort, .uint, .ulong, .ulong_long, .uint128, .complex_uchar, .complex_ushort, .complex_uint, .complex_ulong, .complex_ulong_long, .complex_uint128, @@ -834,21 +834,21 @@ pub fn makeIntegerUnsigned(ty: Type) Type { // zig fmt: on .char, .complex_char => { - base.specifier = @enumFromInt(@intFromEnum(base.specifier) + 2); - return base; + base_ty.specifier = @enumFromInt(@intFromEnum(base_ty.specifier) + 2); + return base_ty; }, // zig fmt: off .schar, .short, .int, .long, .long_long, .int128, .complex_schar, .complex_short, .complex_int, .complex_long, .complex_long_long, .complex_int128 => { - base.specifier = @enumFromInt(@intFromEnum(base.specifier) + 1); - return base; + base_ty.specifier = @enumFromInt(@intFromEnum(base_ty.specifier) + 1); + return base_ty; }, // zig fmt: on .bit_int, .complex_bit_int => { - base.data.int.signedness = .unsigned; - return base; + base_ty.data.int.signedness = .unsigned; + return base_ty; }, else => unreachable, } @@ -1137,6 +1137,10 @@ pub const QualHandling = enum { preserve_quals, }; +pub fn base(ty: Type) Type.Specifier { + return ty.canonicalize(.standard).specifier; +} + /// Canonicalize a possibly-typeof() type. If the type is not a typeof() type, simply /// return it. Otherwise, determine the actual qualified type. /// The `qual_handling` parameter can be used to return the full set of qualifiers @@ -1332,19 +1336,19 @@ pub fn sameRankDifferentSign(a: Type, b: Type, comp: *const Compilation) bool { pub fn makeReal(ty: Type) Type { // TODO discards attributed/typeof - var base = ty.canonicalize(.standard); - switch (base.specifier) { + var base_ty = ty.canonicalize(.standard); + switch (base_ty.specifier) { .complex_float16, .complex_float, .complex_double, .complex_long_double, .complex_float128 => { - base.specifier = @enumFromInt(@intFromEnum(base.specifier) - 5); - return base; + base_ty.specifier = @enumFromInt(@intFromEnum(base_ty.specifier) - 5); + return base_ty; }, .complex_char, .complex_schar, .complex_uchar, .complex_short, .complex_ushort, .complex_int, .complex_uint, .complex_long, .complex_ulong, .complex_long_long, .complex_ulong_long, .complex_int128, .complex_uint128 => { - base.specifier = @enumFromInt(@intFromEnum(base.specifier) - 13); - return base; + base_ty.specifier = @enumFromInt(@intFromEnum(base_ty.specifier) - 13); + return base_ty; }, .complex_bit_int => { - base.specifier = .bit_int; - return base; + base_ty.specifier = .bit_int; + return base_ty; }, else => return ty, } @@ -1352,19 +1356,19 @@ pub fn makeReal(ty: Type) Type { pub fn makeComplex(ty: Type) Type { // TODO discards attributed/typeof - var base = ty.canonicalize(.standard); - switch (base.specifier) { + var base_ty = ty.canonicalize(.standard); + switch (base_ty.specifier) { .float, .double, .long_double, .float128 => { - base.specifier = @enumFromInt(@intFromEnum(base.specifier) + 5); - return base; + base_ty.specifier = @enumFromInt(@intFromEnum(base_ty.specifier) + 5); + return base_ty; }, .char, .schar, .uchar, .short, .ushort, .int, .uint, .long, .ulong, .long_long, .ulong_long, .int128, .uint128 => { - base.specifier = @enumFromInt(@intFromEnum(base.specifier) + 13); - return base; + base_ty.specifier = @enumFromInt(@intFromEnum(base_ty.specifier) + 13); + return base_ty; }, .bit_int => { - base.specifier = .complex_bit_int; - return base; + base_ty.specifier = .complex_bit_int; + return base_ty; }, else => return ty, } From ea37d72f2def6a2582ff3e7ac13b98e6b4d68d63 Mon Sep 17 00:00:00 2001 From: Evan Haas <evan@lagerdata.com> Date: Fri, 23 Aug 2024 08:56:45 -0700 Subject: [PATCH 03/15] Parser: remove unnecessary use of canonicalize in addFieldsFromAnonymous --- src/aro/Parser.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aro/Parser.zig b/src/aro/Parser.zig index 02bfaf43..31275e44 100644 --- a/src/aro/Parser.zig +++ b/src/aro/Parser.zig @@ -167,7 +167,7 @@ record: struct { fn addFieldsFromAnonymous(r: @This(), p: *Parser, ty: Type) Error!void { for (ty.getRecord().?.fields) |f| { if (f.isAnonymousRecord()) { - try r.addFieldsFromAnonymous(p, f.ty.canonicalize(.standard)); + try r.addFieldsFromAnonymous(p, f.ty); } else if (f.name_tok != 0) { try r.addField(p, f.name, f.name_tok); } From 89578d00759a6d765c1fb41e505d016a13cfce72 Mon Sep 17 00:00:00 2001 From: Evan Haas <evan@lagerdata.com> Date: Fri, 23 Aug 2024 08:58:17 -0700 Subject: [PATCH 04/15] Parser: use Type.base instead of Type.canonicalize --- src/aro/Parser.zig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/aro/Parser.zig b/src/aro/Parser.zig index 31275e44..d3a9f466 100644 --- a/src/aro/Parser.zig +++ b/src/aro/Parser.zig @@ -981,7 +981,7 @@ fn decl(p: *Parser) Error!bool { (decl_spec.ty.isRecord() and !decl_spec.ty.isAnonymousRecord(p.comp) and !decl_spec.ty.isTypeof())) // we follow GCC and clang's behavior here { - const specifier = decl_spec.ty.canonicalize(.standard).specifier; + const specifier = decl_spec.ty.base(); const attrs = p.attr_buf.items(.attr)[attr_buf_top..]; const toks = p.attr_buf.items(.tok)[attr_buf_top..]; for (attrs, toks) |attr, tok| { @@ -1870,7 +1870,7 @@ fn initDeclarator(p: *Parser, decl_spec: *DeclSpec, attr_buf_top: usize) Error!? init_d.d.ty = try Attribute.applyVariableAttributes(p, init_d.d.ty, attr_buf_top, null); } if (decl_spec.storage_class != .typedef and init_d.d.ty.hasIncompleteSize()) incomplete: { - const specifier = init_d.d.ty.canonicalize(.standard).specifier; + const specifier = init_d.d.ty.base(); if (decl_spec.storage_class == .@"extern") switch (specifier) { .@"struct", .@"union", .@"enum" => break :incomplete, .incomplete_array => { @@ -3776,8 +3776,8 @@ fn coerceArrayInitExtra(p: *Parser, item: *Result, tok: TokenIndex, target: Type return true; // do not do further coercion } - const target_spec = target.elemType().canonicalize(.standard).specifier; - const item_spec = item.ty.elemType().canonicalize(.standard).specifier; + const target_spec = target.elemType().base(); + const item_spec = item.ty.elemType().base(); const compatible = target.elemType().eql(item.ty.elemType(), p.comp, false) or (is_str_lit and item_spec == .char and (target_spec == .uchar or target_spec == .schar)) or From 6d7ab2da23edd8dca0eff4ebf59587ee0ad4b494 Mon Sep 17 00:00:00 2001 From: Evan Haas <evan@lagerdata.com> Date: Fri, 23 Aug 2024 09:01:26 -0700 Subject: [PATCH 05/15] CodeGen: remove unnecessary canonicalize --- src/aro/CodeGen.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/aro/CodeGen.zig b/src/aro/CodeGen.zig index 9dcc6980..90e51d2f 100644 --- a/src/aro/CodeGen.zig +++ b/src/aro/CodeGen.zig @@ -185,12 +185,12 @@ fn genType(c: *CodeGen, base_ty: Type) !Interner.Ref { fn genFn(c: *CodeGen, decl: NodeIndex) Error!void { const name = c.tree.tokSlice(c.node_data[@intFromEnum(decl)].decl.name); - const func_ty = c.node_ty[@intFromEnum(decl)].canonicalize(.standard); + const func_ty = c.node_ty[@intFromEnum(decl)]; c.ret_nodes.items.len = 0; try c.builder.startFn(); - for (func_ty.data.func.params) |param| { + for (func_ty.params()) |param| { // TODO handle calling convention here const arg = try c.builder.addArg(try c.genType(param.ty)); From 848f0c0e073e0fd746eb0b509ae0779e0732051a Mon Sep 17 00:00:00 2001 From: Evan Haas <evan@lagerdata.com> Date: Fri, 23 Aug 2024 09:11:01 -0700 Subject: [PATCH 06/15] Type: implement base with a loop instead of just calling canonicalize --- src/aro/Type.zig | 71 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) diff --git a/src/aro/Type.zig b/src/aro/Type.zig index 6f8d47e9..4b326696 100644 --- a/src/aro/Type.zig +++ b/src/aro/Type.zig @@ -1138,7 +1138,76 @@ pub const QualHandling = enum { }; pub fn base(ty: Type) Type.Specifier { - return ty.canonicalize(.standard).specifier; + var cur = ty; + while (true) { + switch (cur.specifier) { + .invalid, + .auto_type, + .c23_auto, + => unreachable, + + .typeof_type => cur = cur.data.sub_type.*, + .typeof_expr => cur = cur.data.expr.ty, + .attributed => cur = cur.data.attributed.base, + + .void, + .bool, + .char, + .schar, + .uchar, + .short, + .ushort, + .int, + .uint, + .long, + .ulong, + .long_long, + .ulong_long, + .int128, + .uint128, + .complex_char, + .complex_schar, + .complex_uchar, + .complex_short, + .complex_ushort, + .complex_int, + .complex_uint, + .complex_long, + .complex_ulong, + .complex_long_long, + .complex_ulong_long, + .complex_int128, + .complex_uint128, + .bit_int, + .complex_bit_int, + .fp16, + .float16, + .float, + .double, + .long_double, + .float128, + .complex_float16, + .complex_float, + .complex_double, + .complex_long_double, + .complex_float128, + .pointer, + .unspecified_variable_len_array, + .func, + .var_args_func, + .old_style_func, + .array, + .static_array, + .incomplete_array, + .vector, + .variable_len_array, + .@"struct", + .@"union", + .@"enum", + .nullptr_t, + => |s| return s, + } + } } /// Canonicalize a possibly-typeof() type. If the type is not a typeof() type, simply From aabbf4c2a5c2eda82c826b3a49a8c2985955f6f1 Mon Sep 17 00:00:00 2001 From: Evan Haas <evan@lagerdata.com> Date: Fri, 23 Aug 2024 09:12:26 -0700 Subject: [PATCH 07/15] Attribute: remove unnecessary canonicalize --- src/aro/Attribute.zig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/aro/Attribute.zig b/src/aro/Attribute.zig index fe9770e2..4b35abf8 100644 --- a/src/aro/Attribute.zig +++ b/src/aro/Attribute.zig @@ -1014,14 +1014,13 @@ pub fn applyEnumeratorAttributes(p: *Parser, ty: Type, attr_buf_start: usize) !T } fn applyAligned(attr: Attribute, p: *Parser, ty: Type, tag: ?Diagnostics.Tag) !void { - const base = ty.canonicalize(.standard); if (attr.args.aligned.alignment) |alignment| alignas: { if (attr.syntax != .keyword) break :alignas; const align_tok = attr.args.aligned.__name_tok; if (tag) |t| try p.errTok(t, align_tok); - const default_align = base.alignof(p.comp); + const default_align = ty.alignof(p.comp); if (ty.isFunc()) { try p.errTok(.alignas_on_func, align_tok); } else if (alignment.requested < default_align) { From 86fc12543387f5e8592fb2ea529efeb5d1ea7f4b Mon Sep 17 00:00:00 2001 From: Evan Haas <evan@lagerdata.com> Date: Fri, 23 Aug 2024 11:21:04 -0700 Subject: [PATCH 08/15] Type: use canonicalize instead of recursing for some Type functions --- src/aro/Type.zig | 209 ++++++++++++++++++++++++----------------------- 1 file changed, 106 insertions(+), 103 deletions(-) diff --git a/src/aro/Type.zig b/src/aro/Type.zig index 4b326696..a7c59513 100644 --- a/src/aro/Type.zig +++ b/src/aro/Type.zig @@ -520,7 +520,8 @@ pub fn isDecayed(ty: Type) bool { } pub fn isPtr(ty: Type) bool { - return switch (ty.specifier) { + const canon = ty.canonicalize(.standard); + return switch (canon.specifier) { .pointer => true, .array, @@ -528,16 +529,16 @@ pub fn isPtr(ty: Type) bool { .incomplete_array, .variable_len_array, .unspecified_variable_len_array, - => ty.isDecayed(), - .typeof_type => ty.isDecayed() or ty.data.sub_type.isPtr(), - .typeof_expr => ty.isDecayed() or ty.data.expr.ty.isPtr(), - .attributed => ty.isDecayed() or ty.data.attributed.base.isPtr(), + => canon.isDecayed(), + .typeof_type => unreachable, + .typeof_expr => unreachable, + .attributed => unreachable, else => false, }; } pub fn isInt(ty: Type) bool { - return switch (ty.specifier) { + return switch (ty.base()) { // zig fmt: off .@"enum", .bool, .char, .schar, .uchar, .short, .ushort, .int, .uint, .long, .ulong, .long_long, .ulong_long, .int128, .uint128, .complex_char, .complex_schar, .complex_uchar, @@ -545,28 +546,28 @@ pub fn isInt(ty: Type) bool { .complex_long_long, .complex_ulong_long, .complex_int128, .complex_uint128, .bit_int, .complex_bit_int => true, // zig fmt: on - .typeof_type => ty.data.sub_type.isInt(), - .typeof_expr => ty.data.expr.ty.isInt(), - .attributed => ty.data.attributed.base.isInt(), + .typeof_type => unreachable, + .typeof_expr => unreachable, + .attributed => unreachable, else => false, }; } pub fn isFloat(ty: Type) bool { - return switch (ty.specifier) { + return switch (ty.base()) { // zig fmt: off .float, .double, .long_double, .complex_float, .complex_double, .complex_long_double, .fp16, .float16, .float128, .complex_float128, .complex_float16 => true, // zig fmt: on - .typeof_type => ty.data.sub_type.isFloat(), - .typeof_expr => ty.data.expr.ty.isFloat(), - .attributed => ty.data.attributed.base.isFloat(), + .typeof_type => unreachable, + .typeof_expr => unreachable, + .attributed => unreachable, else => false, }; } pub fn isReal(ty: Type) bool { - return switch (ty.specifier) { + return switch (ty.base()) { // zig fmt: off .complex_float, .complex_double, .complex_long_double, .complex_float128, .complex_char, .complex_schar, .complex_uchar, .complex_short, @@ -574,15 +575,15 @@ pub fn isReal(ty: Type) bool { .complex_long_long, .complex_ulong_long, .complex_int128, .complex_uint128, .complex_bit_int, .complex_float16 => false, // zig fmt: on - .typeof_type => ty.data.sub_type.isReal(), - .typeof_expr => ty.data.expr.ty.isReal(), - .attributed => ty.data.attributed.base.isReal(), + .typeof_type => unreachable, + .typeof_expr => unreachable, + .attributed => unreachable, else => true, }; } pub fn isComplex(ty: Type) bool { - return switch (ty.specifier) { + return switch (ty.base()) { // zig fmt: off .complex_float, .complex_double, .complex_long_double, .complex_float128, .complex_char, .complex_schar, .complex_uchar, .complex_short, @@ -590,19 +591,19 @@ pub fn isComplex(ty: Type) bool { .complex_long_long, .complex_ulong_long, .complex_int128, .complex_uint128, .complex_bit_int, .complex_float16 => true, // zig fmt: on - .typeof_type => ty.data.sub_type.isComplex(), - .typeof_expr => ty.data.expr.ty.isComplex(), - .attributed => ty.data.attributed.base.isComplex(), + .typeof_type => unreachable, + .typeof_expr => unreachable, + .attributed => unreachable, else => false, }; } pub fn isVoidStar(ty: Type) bool { - return switch (ty.specifier) { - .pointer => ty.data.sub_type.specifier == .void, - .typeof_type => ty.data.sub_type.isVoidStar(), - .typeof_expr => ty.data.expr.ty.isVoidStar(), - .attributed => ty.data.attributed.base.isVoidStar(), + return switch (ty.base()) { + .pointer => ty.elemType().base() == .void, + .typeof_type => unreachable, + .typeof_expr => unreachable, + .attributed => unreachable, else => false, }; } @@ -615,12 +616,7 @@ pub fn isTypeof(ty: Type) bool { } pub fn isConst(ty: Type) bool { - return switch (ty.specifier) { - .typeof_type => ty.qual.@"const" or ty.data.sub_type.isConst(), - .typeof_expr => ty.qual.@"const" or ty.data.expr.ty.isConst(), - .attributed => ty.data.attributed.base.isConst(), - else => ty.qual.@"const", - }; + return ty.canonicalize(.standard).qual.@"const"; } pub fn isUnsignedInt(ty: Type, comp: *const Compilation) bool { @@ -628,51 +624,52 @@ pub fn isUnsignedInt(ty: Type, comp: *const Compilation) bool { } pub fn signedness(ty: Type, comp: *const Compilation) std.builtin.Signedness { - return switch (ty.specifier) { + const canon = ty.canonicalize(.standard); + return switch (canon.specifier) { // zig fmt: off .char, .complex_char => return comp.getCharSignedness(), .uchar, .ushort, .uint, .ulong, .ulong_long, .uint128, .bool, .complex_uchar, .complex_ushort, .complex_uint, .complex_ulong, .complex_ulong_long, .complex_uint128 => .unsigned, // zig fmt: on - .bit_int, .complex_bit_int => ty.data.int.signedness, - .typeof_type => ty.data.sub_type.signedness(comp), - .typeof_expr => ty.data.expr.ty.signedness(comp), - .attributed => ty.data.attributed.base.signedness(comp), + .bit_int, .complex_bit_int => canon.data.int.signedness, + .typeof_type => unreachable, + .typeof_expr => unreachable, + .attributed => unreachable, else => .signed, }; } pub fn isEnumOrRecord(ty: Type) bool { - return switch (ty.specifier) { + return switch (ty.base()) { .@"enum", .@"struct", .@"union" => true, - .typeof_type => ty.data.sub_type.isEnumOrRecord(), - .typeof_expr => ty.data.expr.ty.isEnumOrRecord(), - .attributed => ty.data.attributed.base.isEnumOrRecord(), + .typeof_type => unreachable, + .typeof_expr => unreachable, + .attributed => unreachable, else => false, }; } pub fn isRecord(ty: Type) bool { - return switch (ty.specifier) { + return switch (ty.base()) { .@"struct", .@"union" => true, - .typeof_type => ty.data.sub_type.isRecord(), - .typeof_expr => ty.data.expr.ty.isRecord(), - .attributed => ty.data.attributed.base.isRecord(), + .typeof_type => unreachable, + .typeof_expr => unreachable, + .attributed => unreachable, else => false, }; } pub fn isAnonymousRecord(ty: Type, comp: *const Compilation) bool { - return switch (ty.specifier) { + return switch (ty.base()) { // anonymous records can be recognized by their names which are in // the format "(anonymous TAG at path:line:col)". .@"struct", .@"union" => { const mapper = comp.string_interner.getSlowTypeMapper(); - return mapper.lookup(ty.data.record.name)[0] == '('; + return mapper.lookup(ty.getRecord().?.name)[0] == '('; }, - .typeof_type => ty.data.sub_type.isAnonymousRecord(comp), - .typeof_expr => ty.data.expr.ty.isAnonymousRecord(comp), - .attributed => ty.data.attributed.base.isAnonymousRecord(comp), + .typeof_type => unreachable, + .typeof_expr => unreachable, + .attributed => unreachable, else => false, }; } @@ -702,22 +699,24 @@ pub fn elemType(ty: Type) Type { } pub fn returnType(ty: Type) Type { - return switch (ty.specifier) { - .func, .var_args_func, .old_style_func => ty.data.func.return_type, - .typeof_type => ty.data.sub_type.returnType(), - .typeof_expr => ty.data.expr.ty.returnType(), - .attributed => ty.data.attributed.base.returnType(), + const canon = ty.canonicalize(.standard); + return switch (canon.specifier) { + .func, .var_args_func, .old_style_func => canon.data.func.return_type, + .typeof_type => unreachable, + .typeof_expr => unreachable, + .attributed => unreachable, .invalid => Type.invalid, else => unreachable, }; } pub fn params(ty: Type) []Func.Param { - return switch (ty.specifier) { - .func, .var_args_func, .old_style_func => ty.data.func.params, - .typeof_type => ty.data.sub_type.params(), - .typeof_expr => ty.data.expr.ty.params(), - .attributed => ty.data.attributed.base.params(), + const canon = ty.canonicalize(.standard); + return switch (canon.specifier) { + .func, .var_args_func, .old_style_func => canon.data.func.params, + .typeof_type => unreachable, + .typeof_expr => unreachable, + .attributed => unreachable, .invalid => &.{}, else => unreachable, }; @@ -734,11 +733,12 @@ pub fn isInvalidFunc(ty: Type) bool { } pub fn arrayLen(ty: Type) ?u64 { - return switch (ty.specifier) { - .array, .static_array => ty.data.array.len, - .typeof_type => ty.data.sub_type.arrayLen(), - .typeof_expr => ty.data.expr.ty.arrayLen(), - .attributed => ty.data.attributed.base.arrayLen(), + const canon = ty.canonicalize(.standard); + return switch (canon.specifier) { + .array, .static_array => canon.data.array.len, + .typeof_type => unreachable, + .typeof_expr => unreachable, + .attributed => unreachable, else => null, }; } @@ -766,11 +766,12 @@ pub fn getAttributes(ty: Type) []const Attribute { } pub fn getRecord(ty: Type) ?*const Type.Record { - return switch (ty.specifier) { - .attributed => ty.data.attributed.base.getRecord(), - .typeof_type => ty.data.sub_type.getRecord(), - .typeof_expr => ty.data.expr.ty.getRecord(), - .@"struct", .@"union" => ty.data.record, + const canon = ty.canonicalize(.standard); + return switch (canon.specifier) { + .@"struct", .@"union" => canon.data.record, + .attributed => unreachable, + .typeof_type => unreachable, + .typeof_expr => unreachable, else => null, }; } @@ -863,15 +864,16 @@ pub fn integerConversion(a: Type, b: Type, comp: *const Compilation) Type { } pub fn integerPromotion(ty: Type, comp: *Compilation) Type { - var specifier = ty.specifier; + var canon = ty.canonicalize(.standard); + var specifier = canon.specifier; switch (specifier) { .@"enum" => { - if (ty.hasIncompleteSize()) return .{ .specifier = .int }; - if (ty.data.@"enum".fixed) return ty.data.@"enum".tag_ty.integerPromotion(comp); + if (canon.hasIncompleteSize()) return .{ .specifier = .int }; + if (canon.data.@"enum".fixed) return canon.data.@"enum".tag_ty.integerPromotion(comp); - specifier = ty.data.@"enum".tag_ty.specifier; + specifier = canon.data.@"enum".tag_ty.specifier; }, - .bit_int, .complex_bit_int => return .{ .specifier = specifier, .data = ty.data }, + .bit_int, .complex_bit_int => return .{ .specifier = specifier, .data = canon.data }, else => {}, } return switch (specifier) { @@ -879,15 +881,15 @@ pub fn integerPromotion(ty: Type, comp: *Compilation) Type { .specifier = switch (specifier) { // zig fmt: off .bool, .char, .schar, .uchar, .short => .int, - .ushort => if (ty.sizeof(comp).? == sizeof(.{ .specifier = .int }, comp)) Specifier.uint else .int, + .ushort => if (canon.sizeof(comp).? == sizeof(Type.int, comp)) Specifier.uint else .int, .int, .uint, .long, .ulong, .long_long, .ulong_long, .int128, .uint128, .complex_char, .complex_schar, .complex_uchar, .complex_short, .complex_ushort, .complex_int, .complex_uint, .complex_long, .complex_ulong, .complex_long_long, .complex_ulong_long, .complex_int128, .complex_uint128 => specifier, // zig fmt: on - .typeof_type => return ty.data.sub_type.integerPromotion(comp), - .typeof_expr => return ty.data.expr.ty.integerPromotion(comp), - .attributed => return ty.data.attributed.base.integerPromotion(comp), + .typeof_type => unreachable, + .typeof_expr => unreachable, + .attributed => unreachable, .invalid => .invalid, else => unreachable, // _BitInt, or not an integer type }, @@ -914,22 +916,24 @@ pub fn bitfieldPromotion(ty: Type, comp: *Compilation, width: u32) ?Type { } pub fn hasIncompleteSize(ty: Type) bool { - if (ty.isDecayed()) return false; - return switch (ty.specifier) { + const canon = ty.canonicalize(.standard); + if (canon.isDecayed()) return false; + return switch (canon.specifier) { .void, .incomplete_array => true, - .@"enum" => ty.data.@"enum".isIncomplete() and !ty.data.@"enum".fixed, - .@"struct", .@"union" => ty.data.record.isIncomplete(), - .array, .static_array => ty.data.array.elem.hasIncompleteSize(), - .typeof_type => ty.data.sub_type.hasIncompleteSize(), - .typeof_expr, .variable_len_array => ty.data.expr.ty.hasIncompleteSize(), - .unspecified_variable_len_array => ty.data.sub_type.hasIncompleteSize(), - .attributed => ty.data.attributed.base.hasIncompleteSize(), + .@"enum" => canon.data.@"enum".isIncomplete() and !canon.data.@"enum".fixed, + .@"struct", .@"union" => canon.data.record.isIncomplete(), + .array, .static_array => canon.data.array.elem.hasIncompleteSize(), + .variable_len_array => canon.data.expr.ty.hasIncompleteSize(), + .unspecified_variable_len_array => canon.data.sub_type.hasIncompleteSize(), + .typeof_type => unreachable, + .typeof_expr => unreachable, + .attributed => unreachable, else => false, }; } pub fn hasUnboundVLA(ty: Type) bool { - var cur = ty; + var cur = ty.canonicalize(.standard); while (true) { switch (cur.specifier) { .unspecified_variable_len_array => return true, @@ -938,9 +942,9 @@ pub fn hasUnboundVLA(ty: Type) bool { .incomplete_array, .variable_len_array, => cur = cur.elemType(), - .typeof_type => cur = cur.data.sub_type.*, - .typeof_expr => cur = cur.data.expr.ty, - .attributed => cur = cur.data.attributed.base, + .typeof_type => unreachable, + .typeof_expr => unreachable, + .attributed => unreachable, else => return false, } } @@ -1028,14 +1032,15 @@ pub fn sizeof(ty: Type, comp: *const Compilation) ?u64 { } pub fn bitSizeof(ty: Type, comp: *const Compilation) ?u64 { - return switch (ty.specifier) { + const canon = ty.canonicalize(.standard); + return switch (canon.specifier) { .bool => if (comp.langopts.emulate == .msvc) @as(u64, 8) else 1, - .typeof_type => ty.data.sub_type.bitSizeof(comp), - .typeof_expr => ty.data.expr.ty.bitSizeof(comp), - .attributed => ty.data.attributed.base.bitSizeof(comp), - .bit_int => return ty.data.int.bits, + .bit_int => canon.data.int.bits, .long_double => comp.target.cTypeBitSize(.longdouble), - else => 8 * (ty.sizeof(comp) orelse return null), + .typeof_type => unreachable, + .typeof_expr => unreachable, + .attributed => unreachable, + else => 8 * (canon.sizeof(comp) orelse return null), }; } @@ -1141,15 +1146,13 @@ pub fn base(ty: Type) Type.Specifier { var cur = ty; while (true) { switch (cur.specifier) { - .invalid, - .auto_type, - .c23_auto, - => unreachable, - .typeof_type => cur = cur.data.sub_type.*, .typeof_expr => cur = cur.data.expr.ty, .attributed => cur = cur.data.attributed.base, + .auto_type, + .c23_auto, + .invalid, .void, .bool, .char, From 76288eb3f3182a0eee21d800fcacf6f8e300b216 Mon Sep 17 00:00:00 2001 From: Evan Haas <evan@lagerdata.com> Date: Fri, 23 Aug 2024 11:21:14 -0700 Subject: [PATCH 09/15] Type: implement get using canonicalize --- src/aro/Type.zig | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/aro/Type.zig b/src/aro/Type.zig index a7c59513..ca79917b 100644 --- a/src/aro/Type.zig +++ b/src/aro/Type.zig @@ -1244,13 +1244,14 @@ pub fn canonicalize(ty: Type, qual_handling: QualHandling) Type { return cur; } -pub fn get(ty: *const Type, specifier: Specifier) ?*const Type { +pub fn get(ty: Type, specifier: Specifier) ?Type { std.debug.assert(specifier != .typeof_type and specifier != .typeof_expr); - return switch (ty.specifier) { - .typeof_type => ty.data.sub_type.get(specifier), - .typeof_expr => ty.data.expr.ty.get(specifier), - .attributed => ty.data.attributed.base.get(specifier), - else => if (ty.specifier == specifier) ty else null, + const canon = ty.canonicalize(.standard); + return switch (canon.specifier) { + .typeof_type => unreachable, + .typeof_expr => unreachable, + .attributed => unreachable, + else => if (canon.specifier == specifier) canon else null, }; } From 4bd239ccae2a4494458b16b9af27a0f3ea0235c7 Mon Sep 17 00:00:00 2001 From: Evan Haas <evan@lagerdata.com> Date: Fri, 23 Aug 2024 11:25:29 -0700 Subject: [PATCH 10/15] Type: make typeof types unreachable in integerRank --- src/aro/Type.zig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/aro/Type.zig b/src/aro/Type.zig index ca79917b..e74490a0 100644 --- a/src/aro/Type.zig +++ b/src/aro/Type.zig @@ -1389,9 +1389,9 @@ pub fn integerRank(ty: Type, comp: *const Compilation) usize { .long_long, .ulong_long => 6 + (ty.bitSizeof(comp).? << 3), .int128, .uint128 => 7 + (ty.bitSizeof(comp).? << 3), - .typeof_type => ty.data.sub_type.integerRank(comp), - .typeof_expr => ty.data.expr.ty.integerRank(comp), - .attributed => ty.data.attributed.base.integerRank(comp), + .typeof_type => unreachable, + .typeof_expr => unreachable, + .attributed => unreachable, .@"enum" => real.data.@"enum".tag_ty.integerRank(comp), @@ -1423,7 +1423,7 @@ pub fn makeReal(ty: Type) Type { base_ty.specifier = .bit_int; return base_ty; }, - else => return ty, + else => return base_ty, } } From d946fd37d3a1a97e03ca555b71cf11cadaa5d609 Mon Sep 17 00:00:00 2001 From: Evan Haas <evan@lagerdata.com> Date: Fri, 23 Aug 2024 11:27:15 -0700 Subject: [PATCH 11/15] Type: simplify getAttribute implementation --- src/aro/Type.zig | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/aro/Type.zig b/src/aro/Type.zig index e74490a0..2251d423 100644 --- a/src/aro/Type.zig +++ b/src/aro/Type.zig @@ -2421,17 +2421,10 @@ pub const Builder = struct { }; pub fn getAttribute(ty: Type, comptime tag: Attribute.Tag) ?Attribute.ArgumentsForTag(tag) { - switch (ty.specifier) { - .typeof_type => return ty.data.sub_type.getAttribute(tag), - .typeof_expr => return ty.data.expr.ty.getAttribute(tag), - .attributed => { - for (ty.data.attributed.attributes) |attribute| { - if (attribute.tag == tag) return @field(attribute.args, @tagName(tag)); - } - return null; - }, - else => return null, + for (ty.getAttributes()) |attribute| { + if (attribute.tag == tag) return @field(attribute.args, @tagName(tag)); } + return null; } pub fn hasAttribute(ty: Type, tag: Attribute.Tag) bool { From d7249d7fed421dca1889c209e5486087e2c58dfb Mon Sep 17 00:00:00 2001 From: Evan Haas <evan@lagerdata.com> Date: Fri, 23 Aug 2024 11:32:39 -0700 Subject: [PATCH 12/15] Type: simplify isFunc and isCallable --- src/aro/Type.zig | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/aro/Type.zig b/src/aro/Type.zig index 2251d423..263011eb 100644 --- a/src/aro/Type.zig +++ b/src/aro/Type.zig @@ -443,22 +443,29 @@ pub fn withAttributes(self: Type, allocator: std.mem.Allocator, attributes: []co } pub fn isCallable(ty: Type) ?Type { - return switch (ty.specifier) { - .func, .var_args_func, .old_style_func => ty, - .pointer => if (ty.data.sub_type.isFunc()) ty.data.sub_type.* else null, - .typeof_type => ty.data.sub_type.isCallable(), - .typeof_expr => ty.data.expr.ty.isCallable(), - .attributed => ty.data.attributed.base.isCallable(), + const canon = ty.canonicalize(.standard); + return switch (ty.base()) { + .func, .var_args_func, .old_style_func => canon, + .pointer => { + const child_ty = ty.elemType(); + if (child_ty.isFunc()) { + return child_ty; + } + return null; + }, + .typeof_type => unreachable, + .typeof_expr => unreachable, + .attributed => unreachable, else => null, }; } pub fn isFunc(ty: Type) bool { - return switch (ty.specifier) { + return switch (ty.base()) { .func, .var_args_func, .old_style_func => true, - .typeof_type => ty.data.sub_type.isFunc(), - .typeof_expr => ty.data.expr.ty.isFunc(), - .attributed => ty.data.attributed.base.isFunc(), + .typeof_type => unreachable, + .typeof_expr => unreachable, + .attributed => unreachable, else => false, }; } From 61087a3554f605117dfdd69c25a92a1fc66bfd9a Mon Sep 17 00:00:00 2001 From: Evan Haas <evan@lagerdata.com> Date: Fri, 23 Aug 2024 11:34:17 -0700 Subject: [PATCH 13/15] Type: use Type.base to implememnt Type.is --- src/aro/Type.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aro/Type.zig b/src/aro/Type.zig index 263011eb..8b8be255 100644 --- a/src/aro/Type.zig +++ b/src/aro/Type.zig @@ -433,7 +433,7 @@ pub const invalid = Type{ .specifier = .invalid }; /// types if necessary. pub fn is(ty: Type, specifier: Specifier) bool { std.debug.assert(specifier != .typeof_type and specifier != .typeof_expr); - return ty.get(specifier) != null; + return ty.base() == specifier; } pub fn withAttributes(self: Type, allocator: std.mem.Allocator, attributes: []const Attribute) !Type { From 64804c08ec9ae9dd47c28e46fce71bc6932f9dbe Mon Sep 17 00:00:00 2001 From: Evan Haas <evan@lagerdata.com> Date: Fri, 23 Aug 2024 11:36:34 -0700 Subject: [PATCH 14/15] Type: use Type.base to implement Type.undergoesDefaultArgPromotion --- src/aro/Type.zig | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/aro/Type.zig b/src/aro/Type.zig index 8b8be255..616121e8 100644 --- a/src/aro/Type.zig +++ b/src/aro/Type.zig @@ -499,16 +499,16 @@ pub fn setIncompleteArrayLen(ty: *Type, len: u64) void { /// Whether the type is promoted if used as a variadic argument or as an argument to a function with no prototype fn undergoesDefaultArgPromotion(ty: Type, comp: *const Compilation) bool { - return switch (ty.specifier) { + return switch (ty.base()) { .bool => true, .char, .uchar, .schar => true, .short, .ushort => true, - .@"enum" => if (comp.langopts.emulate == .clang) ty.data.@"enum".isIncomplete() else false, + .@"enum" => if (comp.langopts.emulate == .clang) ty.hasIncompleteSize() else false, .float => true, - .typeof_type => ty.data.sub_type.undergoesDefaultArgPromotion(comp), - .typeof_expr => ty.data.expr.ty.undergoesDefaultArgPromotion(comp), - .attributed => ty.data.attributed.base.undergoesDefaultArgPromotion(comp), + .typeof_type => unreachable, + .typeof_expr => unreachable, + .attributed => unreachable, else => false, }; } From b42d19d6c408ec98028ed005ba9d3aa225b5206e Mon Sep 17 00:00:00 2001 From: Evan Haas <evan@lagerdata.com> Date: Fri, 23 Aug 2024 11:41:57 -0700 Subject: [PATCH 15/15] Type: use canonicalize for isArray --- src/aro/Type.zig | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/aro/Type.zig b/src/aro/Type.zig index 616121e8..a65641ef 100644 --- a/src/aro/Type.zig +++ b/src/aro/Type.zig @@ -471,11 +471,12 @@ pub fn isFunc(ty: Type) bool { } pub fn isArray(ty: Type) bool { - return switch (ty.specifier) { - .array, .static_array, .incomplete_array, .variable_len_array, .unspecified_variable_len_array => !ty.isDecayed(), - .typeof_type => !ty.isDecayed() and ty.data.sub_type.isArray(), - .typeof_expr => !ty.isDecayed() and ty.data.expr.ty.isArray(), - .attributed => !ty.isDecayed() and ty.data.attributed.base.isArray(), + const canon = ty.canonicalize(.standard); + return switch (canon.specifier) { + .array, .static_array, .incomplete_array, .variable_len_array, .unspecified_variable_len_array => !canon.isDecayed(), + .typeof_type => unreachable, + .typeof_expr => unreachable, + .attributed => unreachable, else => false, }; }