import "cffc.hff"; import "util.hff"; import "common.hff"; import "set.hff"; struct TypeTraits { fn hash(ty *const Type) u32 { let h = FNV1A_INI; h = fnv1a_i(h, as(int)ty.u.#tag); h = fnv1a_i(h, ty.konst ? 1 : 0); switch ty.u { case Void; case Bool; case Flo; h = fnv1a_i(h, ty.size); case Int i; h = fnv1a_i(h, i.sgn ? 1 : 0); h = fnv1a_i(h, ty.size); case Ptr child; h = fnv1a_i(h, child.id); case Arr arr; h = fnv1a_i(h, arr.child.id); h = fnv1a_i(h, arr.length); case Slice child; h = fnv1a_i(h, child.id); } return h; } fn eq(a *const Type, b *const Type) bool { if a.u.#tag != b.u.#tag or a.size != b.size or a.align != b.align or a.konst != b.konst { return #f; } switch a.u { case Void; case Bool; case Flo; case Int i; return i.sgn == b.u.Int.sgn; case Ptr child; return child == b.u.Ptr; case Arr arr; let brr = b.u.Arr; return arr.length == brr.length and arr.child == brr.child; case Slice child; return child == b.u.Slice; case Fn f0; let f1 = b.u.Fn; if f0.variadic != f1.variadic { return #f; } if f0.ret != f1.ret { return #f; } if f0.params.#len != f1.params.#len { return #f; } foreach(p, i, f0.params, if p != f1.params[i] { return #f; } ) return #t; } return #f; } fn dup(ty *const Type) *const Type { let p *Type = xmalloc(sizeof Type); static id int = 0; *p = *ty; p.id = id++; return p; } } extern fn interntype(ty0 Type) *const Type { static set Set<*const Type, TypeTraits> = {}; if ty0.align == 0 { ty0.align = ty0.size; } return *set->intern(&ty0); } extern static ty_void *const Type = {}, ty_bool *const Type = {}, ty_i8 *const Type = {}, ty_u8 *const Type = {}, ty_i16 *const Type = {}, ty_u16 *const Type = {}, ty_i32 *const Type = {}, ty_u32 *const Type = {}, ty_int *const Type = {}, ty_uint *const Type = {}, ty_i64 *const Type = {}, ty_u64 *const Type = {}, ty_isize *const Type = {}, ty_usize *const Type = {}, ty_iptrint *const Type = {}, ty_uptrint *const Type = {}, ty_f32 *const Type = {}, ty_f64 *const Type = {}, ty_voidptr *const Type = {}; extern fn putprimtypes(env *Env) void { let types []struct { name *const u8, gty **const Type, ty Type } = { { "void", &ty_void, { .size: 0, .align: 1, .u: :Void }}, { "bool", &ty_bool, { .size: 1, .align: 1, .u: :Bool }}, { "f32", &ty_f32, { .size: 4, .u: :Flo }}, { "f64", &ty_f64, { .size: 8, g_targ.f64align, .u: :Flo }}, { "i8", &ty_i8, { .size: 1, .u: :Int { .sgn: #t }}}, { "u8", &ty_u8, { .size: 1, .u: :Int { .sgn: #f }}}, { "i16", &ty_i16, { .size: 2, .u: :Int { .sgn: #t }}}, { "u16", &ty_u16, { .size: 2, .u: :Int { .sgn: #f }}}, { "i32", &ty_i32, { .size: 4, .u: :Int { .sgn: #t }}}, { "u32", &ty_u32, { .size: 4, .u: :Int { .sgn: #f }}}, { "int", &ty_int, { g_targ.intsize, .u: :Int { .sgn: #t }}}, { "uint", &ty_uint, { g_targ.intsize, .u: :Int { .sgn: #f }}}, { "isize", &ty_isize,{ g_targ.sizesize, .u: :Int { .sgn: #t }}}, { "usize", &ty_usize,{ g_targ.sizesize, .u: :Int { .sgn: #f }}}, { "i64", &ty_i64, { .size: 8, g_targ.i64align, .u: :Int { .sgn: #t }}}, { "u64", &ty_u64, { .size: 8, g_targ.i64align, .u: :Int { .sgn: #f }}}, { "iptrint",&ty_iptrint, { g_targ.ptrsize, .u: :Int { .sgn: #t }}}, { "uptrint",&ty_uptrint, { g_targ.ptrsize, .u: :Int { .sgn: #f }}}, }; foreach(type, _, types[0::], envput(env, { type.name, .u: :Ty(*type.gty = interntype(type.ty)) }, #null); ) ty_voidptr = interntype({ .size: g_targ.ptrsize, .u: :Ptr(ty_void) }); } extern fn isnumtype(ty *const Type) bool { return ty->is(:Int) or ty->is(:Flo); } fn numtype2rank(ty *const Type) int { ty = unconstify(ty); switch { case ty->is(:Int) and (ty == ty_int or ty.size < ty_int.size); return 0; case ty == ty_uint; return 1; case ty == ty_i32; return 2; case ty == ty_u32; return 3; case ty == ty_i64; return 4; case ty == ty_u64; return 5; case ty == ty_f32; return 6; case ty == ty_f64; return 7; } return -1; } fn rank2numtype(r int) *const Type { static const types []**const Type = { &ty_int, &ty_uint, &ty_i32, &ty_u32, &ty_i64, &ty_u64, &ty_f32, &ty_f64, }; assert(r >= 0 and r < types.#len, "rank"); return *types[r]; } extern fn typeof2(a *const Type, b *const Type) *const Type { if a == b and !a->is(:Int) { return a; } if isnumtype(a) and isnumtype(b) { let ra = numtype2rank(a), rb = numtype2rank(b); return rank2numtype(MAX(ra, rb)); } if unconstify(a) == b { return a; } if a == unconstify(b) { return b; } return #null; }