╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ Type.zig ─────────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭ find file ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╮ ╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │ │ │http│ ssh │ │ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╯ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
2963 return pt.ptrType(field_ptr_info); 2964 }, 2965 .@"packed" => { 2966 const field_ty = aggregate_ty.fieldType(field_index, zcu); 2967 var field_ptr_info = ptr_info; 2968 if (field_ptr_info.flags.alignment == .none) { 2969 const resolved_align = aggregate_ty.abiAlignment(zcu); 2970 if (field_ty.abiAlignment(zcu) != resolved_align) { 2971 field_ptr_info.flags.alignment = resolved_align; 2972 } 2973 } 2974 field_ptr_info.child = aggregate_ty.fieldType(field_index, zcu).toIntern(); 2975 return pt.ptrType(field_ptr_info); 2976 }, 2977 }, 2978 .pointer => field: { 2979 assert(aggregate_ty.isSlice(zcu)); 2980 break :field switch (field_index) { 2981 Value.slice_ptr_index => .{ aggregate_ty.slicePtrFieldType(zcu), .none }, 2982 Value.slice_len_index => .{ .usize, .none }, 2983 else => unreachable, 2984 }; 2985 }, 2986 else => unreachable, 2987 }; 2988 const field_ptr_align: Alignment = a: { 2989 if (aggregate_ty.zigTypeTag(zcu) == .@"struct" and aggregate_ty.structFieldIsComptime(field_index, zcu)) { 2990 // For `comptime` fields, just use exactly what was specified, or ABI alignment if nothing was specified. 2991 break :a field_align; 2992 } 2993 const actual_field_align = switch (field_align) { 2994 .none => switch (ip.indexToKey(aggregate_ty.toIntern())) { 2995 .struct_type, .tuple_type, .union_type => field_ty.abiAlignment(zcu), 2996 .ptr_type => Type.usize.abiAlignment(zcu), 2997 else => unreachable, 2998 }, 2999 else => |a| a, 3000 }; 3001 const actual_aggregate_align = switch (ptr_info.flags.alignment) { 3002 .none => aggregate_ty.abiAlignment(zcu), 3003 else => |a| a, 3004 }; 3005 if (actual_aggregate_align.compareStrict(.lt, actual_field_align)) { 3006 // Underaligned aggregate; use that alignment. 3007 assert(ptr_info.flags.alignment != .none); 3008 break :a actual_aggregate_align; 3009 } 3010 if (field_align == .none and actual_field_align == field_ty.abiAlignment(zcu)) { 3011 // No explicit annotation on the field (nor an unusual default), and the aggregate 3012 // alignment is irrelevant to us, so return an un-annotated pointer. 3013 break :a .none; 3014 } 3015 break :a actual_field_align; 3016 }; 3017 var field_ptr_info = ptr_info; 3018 field_ptr_info.flags.alignment = field_ptr_align; 3019 field_ptr_info.child = field_ty.toIntern(); 3020 return pt.ptrType(field_ptr_info); 3021 } 3022 3023 pub fn containerTypeName(ty: Type, ip: *const InternPool) struct { 3024 name: InternPool.NullTerminatedString, 3025 fqn: InternPool.NullTerminatedString, 3026 } { 3027 switch (ip.indexToKey(ty.toIntern())) { 3028 .struct_type => { 3029 const loaded_struct = ip.loadStructType(ty.toIntern()); 3030 return .{ .name = loaded_struct.name, .fqn = loaded_struct.fqn }; 3031 }, 3032 .union_type => { 3033 const loaded_union = ip.loadUnionType(ty.toIntern()); 3034 return .{ .name = loaded_union.name, .fqn = loaded_union.fqn }; 3035 }, 3036 .enum_type => { 3037 const loaded_enum = ip.loadEnumType(ty.toIntern()); 3038 return .{ .name = loaded_enum.name, .fqn = loaded_enum.fqn }; 3039 }, 3040 .opaque_type => { 3041 const loaded_opaque = ip.loadOpaqueType(ty.toIntern()); 3042 return .{ .name = loaded_opaque.name, .fqn = loaded_opaque.fqn }; 3043 }, 3044 else => unreachable, 3045 } 3046 } 3047 3048 pub fn destructurable(ty: Type, zcu: *const Zcu) bool { 3049 return switch (ty.zigTypeTag(zcu)) { 3050 .array, .vector => true, 3051 .@"struct" => ty.isTuple(zcu), 3052 else => false, 3053 }; 3054 } 3055 3056 pub const UnpackableReason = union(enum) { 3057 comptime_only, 3058 pointer, 3059 enum_inferred_int_tag: Type, 3060 non_packed_struct: Type, 3061 non_packed_union: Type, 3062 slice, 3063 other, 3064 }; 3065 3066 /// Returns `null` iff `ty` is allowed in packed types. 3067 pub fn unpackable(ty: Type, zcu: *const Zcu) ?UnpackableReason { 3068 return switch (ty.zigTypeTag(zcu)) { 3069 .void, 3070 .bool, 3071 .float, 3072 .int, 3073 => null, 3074 3075 .type, 3076 .comptime_float, 3077 .comptime_int, 3078 .enum_literal, 3079 .undefined, 3080 .null, 3081 => .comptime_only, 3082 3083 .noreturn, 3084 .@"opaque", 3085 .spirv, 3086 .error_union, 3087 .error_set, 3088 .frame, 3089 .@"anyframe", 3090 .@"fn", 3091 .array, 3092 .vector, 3093 => .other, 3094 3095 .optional => if (ty.isPtrLikeOptional(zcu)) 3096 .pointer 3097 else 3098 .other, 3099 3100 .pointer => switch (ty.ptrSize(zcu)) { 3101 .slice => .slice, 3102 .one, .many, .c => .pointer, 3103 }, 3104 3105 .@"enum" => switch (ty.backingIntMode(zcu)) { 3106 .explicit => switch (ty.backingIntType(zcu).toIntern()) { 3107 else => null, 3108 .noreturn_type => .other, 3109 }, 3110 .auto => .{ .enum_inferred_int_tag = ty }, 3111 }, 3112 3113 .@"struct" => switch (ty.containerLayout(zcu)) { 3114 .@"packed" => null, 3115 .auto, .@"extern" => .{ .non_packed_struct = ty }, 3116 }, 3117 .@"union" => switch (ty.containerLayout(zcu)) { 3118 .@"packed" => null, 3119 .auto, .@"extern" => .{ .non_packed_union = ty }, 3120 }, 3121 }; 3122 } 3123 3124 pub const ExternPosition = enum { 3125 ret_ty, 3126 param_ty, 3127 union_field, 3128 struct_field, 3129 element, 3130 other, 3131 }; 3132 3133 /// Returns true if `ty` is allowed in extern types. 3134 /// Asserts that `ty` is fully resolved. 3135 /// Keep in sync with `Sema.explainWhyTypeIsNotExtern`. 3136 pub fn validateExtern(ty: Type, position: ExternPosition, zcu: *const Zcu) bool { 3137 ty.assertHasLayout(zcu); 3138 return switch (ty.zigTypeTag(zcu)) { 3139 .type, 3140 .comptime_float, 3141 .comptime_int, 3142 .enum_literal, 3143 .undefined, 3144 .null, 3145 .error_union, 3146 .error_set, 3147 .frame, 3148 => false, 3149 3150 .vector => { 3151 if (zcu.getTarget().cpu.arch.isSpirV()) return true; 3152 return position == .param_ty or position == .ret_ty; 3153 }, 3154 3155 .void => switch (position) { 3156 .ret_ty, 3157 .union_field, 3158 .struct_field, 3159 .element, 3160 => true, 3161 .param_ty, 3162 .other, 3163 => false, 3164 }, 3165 3166 .noreturn => position == .ret_ty, 3167 3168 .@"opaque", 3169 .bool, 3170 .@"anyframe", 3171 => true, 3172 3173 .spirv => switch (position) { 3174 .struct_field, .union_field => true, 3175 .ret_ty, .param_ty, .element => !ty.isSpirvRuntimeArray(zcu), 3176 .other => !ty.isSpirvRuntimeArray(zcu) or zcu.getTarget().cpu.has(.spirv, .runtime_descriptor_array), 3177 }, 3178 3179 .pointer => { 3180 if (ty.isSlice(zcu)) return false; 3181 const child_ty = ty.childType(zcu); 3182 if (child_ty.zigTypeTag(zcu) == .@"fn") { 3183 return ty.isConstPtr(zcu) and validateExternCallconv(child_ty.fnCallingConvention(zcu)); 3184 } 3185 return true; 3186 }, 3187 .int => switch (ty.intInfo(zcu).bits) { 3188 0, 8, 16, 32, 64, 128 => true, 3189 24, 48 => zcu.getTarget().cpu.arch == .ez80, 3190 else => false, 3191 }, 3192 .float => switch (ty.floatBits(zcu.getTarget())) { 3193 else => true, 3194 80 => |bits| std.zig.target.compilerRtFloatAbi(zcu.getTarget(), bits) == .hard, 3195 }, 3196 .@"fn" => { 3197 if (position != .other) return false; 3198 return validateExternCallconv(ty.fnCallingConvention(zcu)); 3199 }, 3200 .@"enum" => { 3201 const enum_obj = zcu.intern_pool.loadEnumType(ty.toIntern()); 3202 return switch (enum_obj.int_tag_mode) { 3203 .auto => false, 3204 .explicit => Type.fromInterned(enum_obj.int_tag_type).validateExtern(position, zcu), 3205 }; 3206 }, 3207 .@"struct" => { 3208 if (ty.isTuple(zcu)) return false; 3209 const struct_obj = zcu.intern_pool.loadStructType(ty.toIntern()); 3210 return switch (struct_obj.layout) { 3211 .auto => false, 3212 .@"extern" => true, 3213 .@"packed" => switch (struct_obj.packed_backing_mode) { 3214 .auto => false, 3215 .explicit => Type.fromInterned(struct_obj.packed_backing_int_type).validateExtern(position, zcu), 3216 }, 3217 }; 3218 }, 3219 .@"union" => { 3220 const union_obj = zcu.intern_pool.loadUnionType(ty.toIntern()); 3221 return switch (union_obj.layout) { 3222 .auto => false, 3223 .@"extern" => true, 3224 .@"packed" => switch (union_obj.packed_backing_mode) { 3225 .auto => false, 3226 .explicit => Type.fromInterned(union_obj.packed_backing_int_type).validateExtern(position, zcu), 3227 }, 3228 }; 3229 }, 3230 .array => switch (position) { 3231 .ret_ty, 3232 .param_ty, 3233 => false, 3234 3235 .union_field, 3236 .struct_field, 3237 .element, 3238 .other, 3239 => ty.childType(zcu).validateExtern(.element, zcu), 3240 }, 3241 .optional => ty.isPtrLikeOptional(zcu), 3242 }; 3243 } 3244 fn validateExternCallconv(cc: std.lang.CallingConvention) bool { 3245 return switch (cc) { 3246 // For now we want to authorize PTX kernel to use zig objects, even if we end up exposing the ABI. 3247 // The goal is to experiment with more integrated CPU/GPU code. 3248 .nvptx_kernel => true, 3249 else => !target_util.fnCallConvAllowsZigTypes(cc), 3250 }; 3251 } 3252 3253 /// Returns whether `ty` is considered by Zig to have a bit-level representation, meaning it is 3254 /// allowed as the operand to `@bitSizeOf`. This is a superset of packable types. 3255 pub fn hasBitRepresentation(ty: Type, zcu: *const Zcu) bool { 3256 return switch (ty.zigTypeTag(zcu)) { 3257 .@"fn", 3258 .noreturn, 3259 .undefined, 3260 .null, 3261 .@"opaque", 3262 .spirv, 3263 .type, 3264 .enum_literal, 3265 .comptime_float, 3266 .comptime_int, 3267 .error_set, 3268 .error_union, 3269 .frame, 3270 .@"anyframe", 3271 => false, 3272 3273 .void, 3274 .bool, 3275 .int, 3276 .float, 3277 => true, 3278 3279 .@"enum" => { 3280 const enum_obj = zcu.intern_pool.loadEnumType(ty.toIntern()); 3281 return enum_obj.int_tag_mode == .explicit and 3282 enum_obj.int_tag_type != .noreturn_type; 3283 }, 3284 .pointer, .optional => ty.isPtrAtRuntime(zcu), 3285 .@"struct", .@"union" => ty.containerLayout(zcu) == .@"packed", 3286 3287 .array, .vector => ty.childType(zcu).hasBitRepresentation(zcu), 3288 }; 3289 } 3290 3291 /// Asserts that `ty` has resolved layout. 3292 pub fn assertHasLayout(ty: Type, zcu: *const Zcu) void { 3293 if (!std.debug.runtime_safety) { 3294 // This early exit isn't necessary (`Zcu.assertUpToDate` checks `std.debug.runtime_safety` 3295 // itself), but LLVM has been observed to fail at optimizing away this safety check, which 3296 // has a major performance impact on ReleaseFast compiler builds. 3297 return; 3298 } 3299 switch (zcu.intern_pool.indexToKey(ty.toIntern())) { 3300 .int_type, 3301 .ptr_type, 3302 .anyframe_type, 3303 .simple_type, 3304 .opaque_type, 3305 .error_set_type, 3306 .spirv_type, 3307 .inferred_error_set_type, 3308 => {}, 3309 .func_type => |func_type| { 3310 for (func_type.param_types.get(&zcu.intern_pool)) |param_ty| { 3311 assertHasLayout(.fromInterned(param_ty), zcu); 3312 } 3313 assertHasLayout(.fromInterned(func_type.return_type), zcu); 3314 }, 3315 .array_type => |arr| assertHasLayout(.fromInterned(arr.child), zcu), 3316 .vector_type => |vec| assertHasLayout(.fromInterned(vec.child), zcu), 3317 .opt_type => |child| assertHasLayout(.fromInterned(child), zcu), 3318 .error_union_type => |eu| assertHasLayout(.fromInterned(eu.payload_type), zcu), 3319 .tuple_type => |tuple| for (tuple.types.get(&zcu.intern_pool)) |field_ty| { 3320 assertHasLayout(.fromInterned(field_ty), zcu); 3321 }, 3322 .struct_type => { 3323 assert(zcu.intern_pool.loadStructType(ty.toIntern()).want_layout); 3324 zcu.assertUpToDate(.wrap(.{ .type_layout = ty.toIntern() })); 3325 }, 3326 .union_type => { 3327 assert(zcu.intern_pool.loadUnionType(ty.toIntern()).want_layout); 3328 zcu.assertUpToDate(.wrap(.{ .type_layout = ty.toIntern() })); 3329 }, 3330 .enum_type => { 3331 assert(zcu.intern_pool.loadEnumType(ty.toIntern()).want_layout); 3332 zcu.assertUpToDate(.wrap(.{ .type_layout = ty.toIntern() })); 3333 }, 3334 3335 // values, not types 3336 .simple_value, 3337 .@"extern", 3338 .func, 3339 .int, 3340 .err, 3341 .error_union, 3342 .enum_literal, 3343 .enum_tag, 3344 .float, 3345 .ptr, 3346 .slice, 3347 .opt, 3348 .aggregate, 3349 .un, 3350 .bitpack, 3351 .undef, 3352 // memoization, not types 3353 .memoized_call, 3354 => unreachable, 3355 } 3356 } 3357 3358 /// Recursively walks the type and marks for each subtype how many times it has been seen 3359 fn collectSubtypes(ty: Type, pt: Zcu.PerThread, visited: *std.array_hash_map.Auto(Type, u16)) error{OutOfMemory}!void { 3360 const zcu = pt.zcu; 3361 const ip = &zcu.intern_pool; 3362 3363 const gop = try visited.getOrPut(zcu.gpa, ty); 3364 if (gop.found_existing) { 3365 gop.value_ptr.* += 1; 3366 } else { 3367 gop.value_ptr.* = 1; 3368 } 3369 3370 switch (ip.indexToKey(ty.toIntern())) { 3371 .ptr_type => try collectSubtypes(Type.fromInterned(ty.ptrInfo(zcu).child), pt, visited), 3372 .array_type => |array_type| try collectSubtypes(Type.fromInterned(array_type.child), pt, visited), 3373 .vector_type => |vector_type| try collectSubtypes(Type.fromInterned(vector_type.child), pt, visited), 3374 .opt_type => |child| try collectSubtypes(Type.fromInterned(child), pt, visited), 3375 .error_union_type => |error_union_type| { 3376 try collectSubtypes(Type.fromInterned(error_union_type.error_set_type), pt, visited); 3377 if (error_union_type.payload_type != .generic_poison_type) { 3378 try collectSubtypes(Type.fromInterned(error_union_type.payload_type), pt, visited); 3379 } 3380 }, 3381 .tuple_type => |tuple| { 3382 for (tuple.types.get(ip)) |field_ty| { 3383 try collectSubtypes(Type.fromInterned(field_ty), pt, visited); 3384 } 3385 }, 3386 .func_type => |fn_info| { 3387 const param_types = fn_info.param_types.get(&zcu.intern_pool); 3388 for (param_types) |param_ty| { 3389 if (param_ty != .generic_poison_type) { 3390 try collectSubtypes(Type.fromInterned(param_ty), pt, visited); 3391 } 3392 } 3393 3394 if (fn_info.return_type != .generic_poison_type) { 3395 try collectSubtypes(Type.fromInterned(fn_info.return_type), pt, visited); 3396 } 3397 }, 3398 .anyframe_type => |child| try collectSubtypes(Type.fromInterned(child), pt, visited), 3399 3400 // leaf types 3401 .undef, 3402 .inferred_error_set_type, 3403 .error_set_type, 3404 .struct_type, 3405 .union_type, 3406 .opaque_type, 3407 .enum_type, 3408 .spirv_type, 3409 .simple_type, 3410 .int_type, 3411 => {}, 3412 3413 // values, not types 3414 .simple_value, 3415 .@"extern", 3416 .func, 3417 .int, 3418 .err, 3419 .error_union, 3420 .enum_literal, 3421 .enum_tag, 3422 .float, 3423 .ptr, 3424 .slice, 3425 .opt, 3426 .aggregate, 3427 .un, 3428 .bitpack, 3429 // memoization, not types 3430 .memoized_call, 3431 => unreachable, 3432 } 3433 } 3434 3435 fn shouldDedupeType(ty: Type, ctx: *Comparison, pt: Zcu.PerThread) error{OutOfMemory}!Comparison.DedupeEntry { 3436 if (ctx.type_occurrences.get(ty)) |occ| { 3437 if (ctx.type_dedupe_cache.get(ty)) |cached| { 3438 return cached; 3439 } 3440 3441 var discarding: std.Io.Writer.Discarding = .init(&.{}); 3442 3443 print(ty, &discarding.writer, pt, null) catch 3444 unreachable; // we are writing into a discarding writer, it should never fail 3445 3446 const type_len: i32 = @intCast(discarding.count); 3447 3448 const placeholder_len: i32 = 1; 3449 const min_saved_bytes: i32 = 20; 3450 3451 const saved_bytes = (type_len - placeholder_len) * (occ - 1); 3452 const max_placeholders = 7; // T to Z 3453 const should_dedupe = saved_bytes >= min_saved_bytes and ctx.placeholder_index < max_placeholders; 3454 3455 const entry: Comparison.DedupeEntry = if (should_dedupe) b: { 3456 ctx.placeholder_index += 1; 3457 break :b .{ .dedupe = .{ .index = ctx.placeholder_index - 1 } }; 3458 } else .dont_dedupe; 3459 3460 try ctx.type_dedupe_cache.put(pt.zcu.gpa, ty, entry); 3461 3462 return entry; 3463 } else { 3464 return .{ .dont_dedupe = {} }; 3465 } 3466 } 3467 3468 /// The comparison recursively walks all types given and notes how many times 3469 /// each subtype occurs. It then while recursively printing decides for each 3470 /// subtype whether to print the type inline or create a placeholder based on 3471 /// the subtype length and number of occurences. Placeholders are then found by 3472 /// iterating `type_dedupe_cache` which caches the inline/placeholder decisions. 3473 pub const Comparison = struct { 3474 type_occurrences: std.array_hash_map.Auto(Type, u16), 3475 type_dedupe_cache: std.array_hash_map.Auto(Type, DedupeEntry), 3476 placeholder_index: u8, 3477 3478 pub const Placeholder = struct { 3479 index: u8, 3480 3481 pub fn format(p: Placeholder, writer: *std.Io.Writer) error{WriteFailed}!void { 3482 return writer.print("{c}", .{p.index + 'T'}); 3483 } 3484 }; 3485 3486 pub const DedupeEntry = union(enum) { 3487 dont_dedupe: void, 3488 dedupe: Placeholder, 3489 }; 3490 3491 pub fn init(types: []const Type, pt: Zcu.PerThread) error{OutOfMemory}!Comparison { 3492 var cmp: Comparison = .{ 3493 .type_occurrences = .empty, 3494 .type_dedupe_cache = .empty, 3495 .placeholder_index = 0, 3496 }; 3497 3498 errdefer cmp.deinit(pt); 3499 3500 for (types) |ty| { 3501 try collectSubtypes(ty, pt, &cmp.type_occurrences); 3502 } 3503 3504 return cmp; 3505 } 3506 3507 pub fn deinit(cmp: *Comparison, pt: Zcu.PerThread) void { 3508 const gpa = pt.zcu.gpa; 3509 cmp.type_occurrences.deinit(gpa); 3510 cmp.type_dedupe_cache.deinit(gpa); 3511 } 3512 3513 pub fn fmtType(ctx: *Comparison, ty: Type, pt: Zcu.PerThread) Comparison.Formatter { 3514 return .{ .ty = ty, .ctx = ctx, .pt = pt }; 3515 } 3516 pub const Formatter = struct { 3517 ty: Type, 3518 ctx: *Comparison, 3519 pt: Zcu.PerThread, 3520 3521 pub fn format(self: Comparison.Formatter, writer: anytype) error{WriteFailed}!void { 3522 print(self.ty, writer, self.pt, self.ctx) catch return error.WriteFailed; 3523 } 3524 }; 3525 }; 3526 3527 pub const @"u0": Type = .{ .ip_index = .u0_type }; 3528 pub const @"u1": Type = .{ .ip_index = .u1_type }; 3529 pub const @"u8": Type = .{ .ip_index = .u8_type }; 3530 pub const @"u16": Type = .{ .ip_index = .u16_type }; 3531 pub const @"u29": Type = .{ .ip_index = .u29_type }; 3532 pub const @"u32": Type = .{ .ip_index = .u32_type }; 3533 pub const @"u64": Type = .{ .ip_index = .u64_type }; 3534 pub const @"u80": Type = .{ .ip_index = .u80_type }; 3535 pub const @"u128": Type = .{ .ip_index = .u128_type }; 3536 pub const @"u256": Type = .{ .ip_index = .u256_type }; 3537 3538 pub const @"i8": Type = .{ .ip_index = .i8_type }; 3539 pub const @"i16": Type = .{ .ip_index = .i16_type }; 3540 pub const @"i32": Type = .{ .ip_index = .i32_type }; 3541 pub const @"i64": Type = .{ .ip_index = .i64_type }; 3542 pub const @"i128": Type = .{ .ip_index = .i128_type }; 3543 3544 pub const @"f16": Type = .{ .ip_index = .f16_type }; 3545 pub const @"f32": Type = .{ .ip_index = .f32_type }; 3546 pub const @"f64": Type = .{ .ip_index = .f64_type }; 3547 pub const @"f80": Type = .{ .ip_index = .f80_type }; 3548 pub const @"f128": Type = .{ .ip_index = .f128_type }; 3549 3550 pub const @"bool": Type = .{ .ip_index = .bool_type }; 3551 pub const @"usize": Type = .{ .ip_index = .usize_type }; 3552 pub const @"isize": Type = .{ .ip_index = .isize_type }; 3553 pub const @"comptime_int": Type = .{ .ip_index = .comptime_int_type }; 3554 pub const @"comptime_float": Type = .{ .ip_index = .comptime_float_type }; 3555 pub const @"void": Type = .{ .ip_index = .void_type }; 3556 pub const @"type": Type = .{ .ip_index = .type_type }; 3557 pub const @"anyerror": Type = .{ .ip_index = .anyerror_type }; 3558 pub const @"anyopaque": Type = .{ .ip_index = .anyopaque_type }; 3559 pub const @"anyframe": Type = .{ .ip_index = .anyframe_type }; 3560 pub const @"null": Type = .{ .ip_index = .null_type }; 3561 pub const @"undefined": Type = .{ .ip_index = .undefined_type }; 3562 pub const @"noreturn": Type = .{ .ip_index = .noreturn_type }; 3563 pub const enum_literal: Type = .{ .ip_index = .enum_literal_type }; 3564 3565 pub const @"c_char": Type = .{ .ip_index = .c_char_type }; 3566 pub const @"c_short": Type = .{ .ip_index = .c_short_type }; 3567 pub const @"c_ushort": Type = .{ .ip_index = .c_ushort_type }; 3568 pub const @"c_int": Type = .{ .ip_index = .c_int_type }; 3569 pub const @"c_uint": Type = .{ .ip_index = .c_uint_type }; 3570 pub const @"c_long": Type = .{ .ip_index = .c_long_type }; 3571 pub const @"c_ulong": Type = .{ .ip_index = .c_ulong_type }; 3572 pub const @"c_longlong": Type = .{ .ip_index = .c_longlong_type }; 3573 pub const @"c_ulonglong": Type = .{ .ip_index = .c_ulonglong_type }; 3574 pub const @"c_longdouble": Type = .{ .ip_index = .c_longdouble_type }; 3575 3576 pub const ptr_usize: Type = .{ .ip_index = .ptr_usize_type }; 3577 pub const ptr_const_comptime_int: Type = .{ .ip_index = .ptr_const_comptime_int_type }; 3578 pub const manyptr_u8: Type = .{ .ip_index = .manyptr_u8_type }; 3579 pub const manyptr_const_u8: Type = .{ .ip_index = .manyptr_const_u8_type }; 3580 pub const manyptr_const_u8_sentinel_0: Type = .{ .ip_index = .manyptr_const_u8_sentinel_0_type }; 3581 pub const slice_const_u8: Type = .{ .ip_index = .slice_const_u8_type }; 3582 pub const slice_const_u8_sentinel_0: Type = .{ .ip_index = .slice_const_u8_sentinel_0_type }; 3583 pub const slice_const_slice_const_u8: Type = .{ .ip_index = .slice_const_slice_const_u8_type }; 3584 pub const slice_const_type: Type = .{ .ip_index = .slice_const_type_type }; 3585 pub const optional_type: Type = .{ .ip_index = .optional_type_type }; 3586 pub const optional_noreturn: Type = .{ .ip_index = .optional_noreturn_type }; 3587 3588 pub const vector_8_i8: Type = .{ .ip_index = .vector_8_i8_type }; 3589 pub const vector_16_i8: Type = .{ .ip_index = .vector_16_i8_type }; 3590 pub const vector_32_i8: Type = .{ .ip_index = .vector_32_i8_type }; 3591 pub const vector_64_i8: Type = .{ .ip_index = .vector_64_i8_type }; 3592 pub const vector_1_u8: Type = .{ .ip_index = .vector_1_u8_type }; 3593 pub const vector_2_u8: Type = .{ .ip_index = .vector_2_u8_type }; 3594 pub const vector_4_u8: Type = .{ .ip_index = .vector_4_u8_type }; 3595 pub const vector_8_u8: Type = .{ .ip_index = .vector_8_u8_type }; 3596 pub const vector_16_u8: Type = .{ .ip_index = .vector_16_u8_type }; 3597 pub const vector_32_u8: Type = .{ .ip_index = .vector_32_u8_type }; 3598 pub const vector_64_u8: Type = .{ .ip_index = .vector_64_u8_type }; 3599 pub const vector_2_i16: Type = .{ .ip_index = .vector_2_i16_type }; 3600 pub const vector_4_i16: Type = .{ .ip_index = .vector_4_i16_type }; 3601 pub const vector_8_i16: Type = .{ .ip_index = .vector_8_i16_type }; 3602 pub const vector_16_i16: Type = .{ .ip_index = .vector_16_i16_type }; 3603 pub const vector_32_i16: Type = .{ .ip_index = .vector_32_i16_type }; 3604 pub const vector_4_u16: Type = .{ .ip_index = .vector_4_u16_type }; 3605 pub const vector_8_u16: Type = .{ .ip_index = .vector_8_u16_type }; 3606 pub const vector_16_u16: Type = .{ .ip_index = .vector_16_u16_type }; 3607 pub const vector_32_u16: Type = .{ .ip_index = .vector_32_u16_type }; 3608 pub const vector_2_i32: Type = .{ .ip_index = .vector_2_i32_type }; 3609 pub const vector_4_i32: Type = .{ .ip_index = .vector_4_i32_type }; 3610 pub const vector_8_i32: Type = .{ .ip_index = .vector_8_i32_type }; 3611 pub const vector_16_i32: Type = .{ .ip_index = .vector_16_i32_type }; 3612 pub const vector_4_u32: Type = .{ .ip_index = .vector_4_u32_type }; 3613 pub const vector_8_u32: Type = .{ .ip_index = .vector_8_u32_type }; 3614 pub const vector_16_u32: Type = .{ .ip_index = .vector_16_u32_type }; 3615 pub const vector_2_i64: Type = .{ .ip_index = .vector_2_i64_type }; 3616 pub const vector_4_i64: Type = .{ .ip_index = .vector_4_i64_type }; 3617 pub const vector_8_i64: Type = .{ .ip_index = .vector_8_i64_type }; 3618 pub const vector_2_u64: Type = .{ .ip_index = .vector_2_u64_type }; 3619 pub const vector_4_u64: Type = .{ .ip_index = .vector_4_u64_type }; 3620 pub const vector_8_u64: Type = .{ .ip_index = .vector_8_u64_type }; 3621 pub const vector_1_u128: Type = .{ .ip_index = .vector_1_u128_type }; 3622 pub const vector_2_u128: Type = .{ .ip_index = .vector_2_u128_type }; 3623 pub const vector_1_u256: Type = .{ .ip_index = .vector_1_u256_type }; 3624 pub const vector_4_f16: Type = .{ .ip_index = .vector_4_f16_type }; 3625 pub const vector_8_f16: Type = .{ .ip_index = .vector_8_f16_type }; 3626 pub const vector_16_f16: Type = .{ .ip_index = .vector_16_f16_type }; 3627 pub const vector_32_f16: Type = .{ .ip_index = .vector_32_f16_type }; 3628 pub const vector_2_f32: Type = .{ .ip_index = .vector_2_f32_type }; 3629 pub const vector_4_f32: Type = .{ .ip_index = .vector_4_f32_type }; 3630 pub const vector_8_f32: Type = .{ .ip_index = .vector_8_f32_type }; 3631 pub const vector_16_f32: Type = .{ .ip_index = .vector_16_f32_type }; 3632 pub const vector_2_f64: Type = .{ .ip_index = .vector_2_f64_type }; 3633 pub const vector_4_f64: Type = .{ .ip_index = .vector_4_f64_type }; 3634 pub const vector_8_f64: Type = .{ .ip_index = .vector_8_f64_type }; 3635 3636 pub const empty_tuple: Type = .{ .ip_index = .empty_tuple_type }; 3637 3638 pub const generic_poison: Type = .{ .ip_index = .generic_poison_type }; 3639 3640 pub fn smallestUnsignedBits(max: u64) u16 { 3641 return switch (max) { 3642 0 => 0, 3643 else => @as(u16, 1) + std.math.log2_int(u64, max), 3644 }; 3645 } 3646 3647 /// This is only used for comptime asserts. Bump this number when you make a change 3648 /// to packed struct layout to find out all the places in the codebase you need to edit! 3649 pub const packed_struct_layout_version = 2; 3650 3651 fn cTypeAlign(target: *const Target, c_type: Target.CType) Alignment { 3652 return .fromByteUnits(target.cTypeAlignment(c_type).?); 3653 } 3654