zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

blob dcd192da (5360B) - Raw


      1 const assert = @import("std").debug.assert;
      2 const std = @import("std");
      3 const InternPool = @import("../../InternPool.zig");
      4 const Type = @import("../../Type.zig");
      5 const Zcu = @import("../../Zcu.zig");
      6 
      7 pub const Class = union(enum) {
      8     memory,
      9     byval,
     10     integer,
     11     double_integer,
     12     float_array: u8,
     13 };
     14 
     15 /// For `float_array` the second element will be the amount of floats.
     16 pub fn classifyType(ty: Type, zcu: *Zcu) Class {
     17     assert(ty.hasRuntimeBits(zcu));
     18 
     19     switch (ty.zigTypeTag(zcu)) {
     20         .@"struct" => {
     21             if (ty.containerLayout(zcu) == .@"packed") return .byval;
     22             if (countFloats(ty, zcu)) |float| return .{ .float_array = float.count };
     23 
     24             const bit_size = ty.abiSize(zcu) * 8;
     25             if (bit_size > 128) return .memory;
     26             if (bit_size > 64) return .double_integer;
     27             return .integer;
     28         },
     29         .@"union" => {
     30             if (ty.containerLayout(zcu) == .@"packed") return .byval;
     31             if (countFloats(ty, zcu)) |float| return .{ .float_array = float.count };
     32 
     33             const bit_size = ty.abiSize(zcu) * 8;
     34             if (bit_size > 128) return .memory;
     35             if (bit_size > 64) return .double_integer;
     36             return .integer;
     37         },
     38         .int, .@"enum", .error_set, .float, .bool => return .byval,
     39         .vector => {
     40             const bit_size = ty.bitSize(zcu);
     41             // TODO is this controlled by a cpu feature?
     42             if (bit_size > 128) return .memory;
     43             return .byval;
     44         },
     45         .optional => {
     46             assert(ty.isPtrLikeOptional(zcu));
     47             return .byval;
     48         },
     49         .pointer => {
     50             assert(!ty.isSlice(zcu));
     51             return .byval;
     52         },
     53         .error_union,
     54         .frame,
     55         .@"anyframe",
     56         .noreturn,
     57         .void,
     58         .type,
     59         .comptime_float,
     60         .comptime_int,
     61         .undefined,
     62         .null,
     63         .@"fn",
     64         .@"opaque",
     65         .spirv,
     66         .enum_literal,
     67         .array,
     68         => unreachable,
     69     }
     70 }
     71 
     72 const CountFloatsResult = struct {
     73     ty: Type,
     74     count: std.math.IntFittingRange(0, max_count),
     75 
     76     const none: CountFloatsResult = .{ .ty = .void, .count = 0 };
     77 
     78     const max_count = 4;
     79 };
     80 fn countFloats(ty: Type, zcu: *Zcu) ?CountFloatsResult {
     81     const ip = &zcu.intern_pool;
     82     if (!ty.hasRuntimeBits(zcu)) return .none;
     83     switch (ty.zigTypeTag(zcu)) {
     84         .@"union" => {
     85             const loaded_union = zcu.typeToUnion(ty).?;
     86             var result: CountFloatsResult = .none;
     87             for (loaded_union.field_types.get(ip)) |field_ty| {
     88                 const float = countFloats(Type.fromInterned(field_ty), zcu) orelse return null;
     89                 if (result.ty.toIntern() == .void_type) {
     90                     result.ty = float.ty;
     91                 } else if (result.ty.bitSize(zcu) != float.ty.bitSize(zcu)) return null;
     92                 result.count = @max(result.count, float.count);
     93             }
     94             if (ty.abiSize(zcu) != result.ty.abiSize(zcu) * result.count) return null;
     95             return result;
     96         },
     97         .@"struct" => {
     98             var result: CountFloatsResult = .none;
     99             var field_it: InternPool.LoadedStructType.RuntimeOrderIterator = if (zcu.typeToStruct(ty)) |loaded_struct|
    100                 loaded_struct.iterateRuntimeOrder(ip)
    101             else
    102                 .{ .runtime_order = null, .fields_len = ty.structFieldCount(zcu), .next_index = 0 };
    103             while (field_it.next()) |field_index| {
    104                 if (ty.structFieldOffset(field_index, zcu) != result.ty.abiSize(zcu) * result.count) return null;
    105                 const field_ty = ty.fieldType(field_index, zcu);
    106                 const float = countFloats(field_ty, zcu) orelse return null;
    107                 if (result.ty.toIntern() == .void_type) {
    108                     result.ty = float.ty;
    109                 } else if (result.ty.bitSize(zcu) != float.ty.bitSize(zcu)) return null;
    110                 if (float.count > CountFloatsResult.max_count - result.count) return null;
    111                 result.count += float.count;
    112             }
    113             if (ty.abiSize(zcu) != result.ty.abiSize(zcu) * result.count) return null;
    114             return result;
    115         },
    116         .float => return .{ .ty = ty, .count = 1 },
    117         else => return null,
    118     }
    119 }
    120 
    121 pub fn getFloatArrayType(ty: Type, zcu: *Zcu) ?Type {
    122     const ip = &zcu.intern_pool;
    123     switch (ty.zigTypeTag(zcu)) {
    124         .@"union" => {
    125             const loaded_union = zcu.typeToUnion(ty).?;
    126             for (loaded_union.field_types.get(ip)) |field_ty| {
    127                 if (getFloatArrayType(Type.fromInterned(field_ty), zcu)) |some| return some;
    128             }
    129             return null;
    130         },
    131         .@"struct" => {
    132             var field_it: InternPool.LoadedStructType.RuntimeOrderIterator = if (zcu.typeToStruct(ty)) |loaded_struct|
    133                 loaded_struct.iterateRuntimeOrder(ip)
    134             else
    135                 .{ .runtime_order = null, .fields_len = ty.structFieldCount(zcu), .next_index = 0 };
    136             while (field_it.next()) |field_index| {
    137                 const field_ty = ty.fieldType(field_index, zcu);
    138                 if (getFloatArrayType(field_ty, zcu)) |some| return some;
    139             }
    140             return null;
    141         },
    142         .float => return ty,
    143         else => return null,
    144     }
    145 }