ast: add a type_size() method (#14213)
parent
5a42350a78
commit
14309594fe
|
@ -44,6 +44,7 @@ pub mut:
|
||||||
mdeprecated_msg map[string]string // module deprecation message
|
mdeprecated_msg map[string]string // module deprecation message
|
||||||
mdeprecated_after map[string]time.Time // module deprecation date
|
mdeprecated_after map[string]time.Time // module deprecation date
|
||||||
builtin_pub_fns map[string]bool
|
builtin_pub_fns map[string]bool
|
||||||
|
pointer_size int
|
||||||
}
|
}
|
||||||
|
|
||||||
// used by vls to avoid leaks
|
// used by vls to avoid leaks
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
import v.builder
|
||||||
|
import v.parser
|
||||||
|
import v.pref
|
||||||
|
|
||||||
|
struct T01 {
|
||||||
|
a int
|
||||||
|
b byte
|
||||||
|
c int
|
||||||
|
}
|
||||||
|
|
||||||
|
type T02 = string
|
||||||
|
type T03 = int | string
|
||||||
|
type T04 = []T03
|
||||||
|
type T05 = [47]T03
|
||||||
|
|
||||||
|
interface T06 {
|
||||||
|
a int
|
||||||
|
}
|
||||||
|
|
||||||
|
interface T07 {
|
||||||
|
T06
|
||||||
|
b int
|
||||||
|
}
|
||||||
|
|
||||||
|
struct T08 {
|
||||||
|
T01
|
||||||
|
x string
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_type_size() ? {
|
||||||
|
mut pref := pref.new_preferences()
|
||||||
|
$if x64 {
|
||||||
|
pref.m64 = true
|
||||||
|
}
|
||||||
|
mut b := builder.new_builder(pref)
|
||||||
|
mut files := b.get_builtin_files()
|
||||||
|
b.set_module_lookup_paths()
|
||||||
|
parser.parse_files(files, b.table, b.pref)
|
||||||
|
b.parse_imports()
|
||||||
|
parser.parse_file(@FILE, b.table, .parse_comments, b.pref)
|
||||||
|
|
||||||
|
mut t := b.table
|
||||||
|
|
||||||
|
assert sizeof(T01) == t.type_size(t.type_idxs['main.T01'] ?)
|
||||||
|
assert sizeof(T02) == t.type_size(t.type_idxs['main.T02'] ?)
|
||||||
|
assert sizeof(T03) == t.type_size(t.type_idxs['main.T03'] ?)
|
||||||
|
assert sizeof(T04) == t.type_size(t.type_idxs['main.T04'] ?)
|
||||||
|
assert sizeof(T05) == t.type_size(t.type_idxs['main.T05'] ?)
|
||||||
|
assert sizeof(T06) == t.type_size(t.type_idxs['main.T06'] ?)
|
||||||
|
assert sizeof(T07) == t.type_size(t.type_idxs['main.T07'] ?)
|
||||||
|
assert sizeof(T08) == t.type_size(t.type_idxs['main.T08'] ?)
|
||||||
|
|
||||||
|
println('done')
|
||||||
|
}
|
|
@ -823,6 +823,97 @@ pub fn (t &TypeSymbol) is_builtin() bool {
|
||||||
return t.mod == 'builtin'
|
return t.mod == 'builtin'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// type_size returns the size in bytes of `typ`, similarly to C's `sizeof()`.
|
||||||
|
pub fn (t &Table) type_size(typ Type) int {
|
||||||
|
if typ.has_flag(.optional) {
|
||||||
|
return t.type_size(ast.error_type_idx)
|
||||||
|
}
|
||||||
|
if typ.nr_muls() > 0 {
|
||||||
|
return t.pointer_size
|
||||||
|
}
|
||||||
|
sym := t.sym(typ)
|
||||||
|
match sym.kind {
|
||||||
|
.placeholder, .void, .none_ {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
.voidptr, .byteptr, .charptr, .function, .usize, .isize, .any, .thread, .chan {
|
||||||
|
return t.pointer_size
|
||||||
|
}
|
||||||
|
.i8, .u8, .char, .bool {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
.i16, .u16 {
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
.int, .u32, .rune, .f32, .enum_ {
|
||||||
|
return 4
|
||||||
|
}
|
||||||
|
.i64, .u64, .int_literal, .f64, .float_literal {
|
||||||
|
return 8
|
||||||
|
}
|
||||||
|
.alias {
|
||||||
|
return t.type_size((sym.info as Alias).parent_type)
|
||||||
|
}
|
||||||
|
.struct_, .string, .multi_return {
|
||||||
|
mut max_alignment := 0
|
||||||
|
mut total_size := 0
|
||||||
|
types := if sym.info is Struct {
|
||||||
|
sym.info.fields.map(it.typ)
|
||||||
|
} else {
|
||||||
|
(sym.info as MultiReturn).types
|
||||||
|
}
|
||||||
|
for ftyp in types {
|
||||||
|
field_size := t.type_size(ftyp)
|
||||||
|
alignment := if field_size > t.pointer_size { t.pointer_size } else { field_size }
|
||||||
|
if alignment > max_alignment {
|
||||||
|
max_alignment = alignment
|
||||||
|
}
|
||||||
|
total_size = round_up(total_size, alignment) + field_size
|
||||||
|
}
|
||||||
|
return round_up(total_size, max_alignment)
|
||||||
|
}
|
||||||
|
.sum_type, .interface_, .aggregate {
|
||||||
|
match sym.info {
|
||||||
|
SumType, Aggregate {
|
||||||
|
return (sym.info.fields.len + 2) * t.pointer_size
|
||||||
|
}
|
||||||
|
Interface {
|
||||||
|
mut res := (sym.info.fields.len + 2) * t.pointer_size
|
||||||
|
for etyp in sym.info.embeds {
|
||||||
|
res += t.type_size(etyp) - 2 * t.pointer_size
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// unreachable
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.array_fixed {
|
||||||
|
info := sym.info as ArrayFixed
|
||||||
|
return info.size * t.type_size(info.elem_type)
|
||||||
|
}
|
||||||
|
// TODO hardcoded:
|
||||||
|
.map {
|
||||||
|
return if t.pointer_size == 8 { 120 } else { 80 }
|
||||||
|
}
|
||||||
|
.array {
|
||||||
|
return if t.pointer_size == 8 { 32 } else { 24 }
|
||||||
|
}
|
||||||
|
.generic_inst {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// round_up rounds the number `n` up to the next multiple `multiple`.
|
||||||
|
// Note: `multiple` must be a power of 2.
|
||||||
|
[inline]
|
||||||
|
fn round_up(n int, multiple int) int {
|
||||||
|
return (n + multiple - 1) & -multiple
|
||||||
|
}
|
||||||
|
|
||||||
// for debugging/errors only, perf is not an issue
|
// for debugging/errors only, perf is not an issue
|
||||||
pub fn (k Kind) str() string {
|
pub fn (k Kind) str() string {
|
||||||
return match k {
|
return match k {
|
||||||
|
|
|
@ -53,6 +53,7 @@ pub fn new_builder(pref &pref.Preferences) Builder {
|
||||||
if pref.use_color == .never {
|
if pref.use_color == .never {
|
||||||
util.emanager.set_support_color(false)
|
util.emanager.set_support_color(false)
|
||||||
}
|
}
|
||||||
|
table.pointer_size = if pref.m64 { 8 } else { 4 }
|
||||||
msvc := find_msvc(pref.m64) or {
|
msvc := find_msvc(pref.m64) or {
|
||||||
if pref.ccompiler == 'msvc' {
|
if pref.ccompiler == 'msvc' {
|
||||||
// verror('Cannot find MSVC on this OS')
|
// verror('Cannot find MSVC on this OS')
|
||||||
|
|
|
@ -709,38 +709,3 @@ pub fn (mut c Checker) infer_fn_generic_types(func ast.Fn, mut node ast.CallExpr
|
||||||
c.need_recheck_generic_fns = true
|
c.need_recheck_generic_fns = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (c &Checker) sizeof_integer(a ast.Type) int {
|
|
||||||
t := if a in ast.unsigned_integer_type_idxs { a.flip_signedness() } else { a }
|
|
||||||
r := match t {
|
|
||||||
ast.char_type_idx, ast.i8_type_idx {
|
|
||||||
1
|
|
||||||
}
|
|
||||||
ast.i16_type_idx {
|
|
||||||
2
|
|
||||||
}
|
|
||||||
ast.int_type_idx {
|
|
||||||
4
|
|
||||||
}
|
|
||||||
ast.rune_type_idx {
|
|
||||||
4
|
|
||||||
}
|
|
||||||
ast.i64_type_idx {
|
|
||||||
8
|
|
||||||
}
|
|
||||||
ast.isize_type_idx {
|
|
||||||
if c.pref.m64 { 8 } else { 4 }
|
|
||||||
}
|
|
||||||
ast.int_literal_type {
|
|
||||||
s := c.table.type_to_str(a)
|
|
||||||
panic('`$s` has unknown size')
|
|
||||||
0
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
s := c.table.type_to_str(a)
|
|
||||||
panic('`$s` is not an integer')
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return r
|
|
||||||
}
|
|
||||||
|
|
|
@ -643,8 +643,8 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
|
||||||
} else if is_left_type_signed != is_right_type_signed
|
} else if is_left_type_signed != is_right_type_signed
|
||||||
&& left_type != ast.int_literal_type_idx
|
&& left_type != ast.int_literal_type_idx
|
||||||
&& right_type != ast.int_literal_type_idx {
|
&& right_type != ast.int_literal_type_idx {
|
||||||
ls := c.sizeof_integer(left_type)
|
ls := c.table.type_size(left_type)
|
||||||
rs := c.sizeof_integer(right_type)
|
rs := c.table.type_size(right_type)
|
||||||
// prevent e.g. `u32 == i16` but not `u16 == i32` as max_u16 fits in i32
|
// prevent e.g. `u32 == i16` but not `u16 == i32` as max_u16 fits in i32
|
||||||
// TODO u32 == i32, change < to <=
|
// TODO u32 == i32, change < to <=
|
||||||
if (is_left_type_signed && ls < rs) || (is_right_type_signed && rs < ls) {
|
if (is_left_type_signed && ls < rs) || (is_right_type_signed && rs < ls) {
|
||||||
|
|
|
@ -127,30 +127,7 @@ fn (mut c Checker) eval_comptime_const_expr(expr ast.Expr, nlevel int) ?ast.Comp
|
||||||
// return expr.val.i64()
|
// return expr.val.i64()
|
||||||
// }
|
// }
|
||||||
ast.SizeOf {
|
ast.SizeOf {
|
||||||
xtype := expr.typ
|
return c.table.type_size(expr.typ)
|
||||||
if xtype.is_real_pointer() {
|
|
||||||
if c.pref.m64 {
|
|
||||||
return 8 // 64bit platform
|
|
||||||
}
|
|
||||||
return 4 // 32bit platform
|
|
||||||
}
|
|
||||||
if int(xtype) == xtype.idx() {
|
|
||||||
match xtype {
|
|
||||||
ast.char_type { return 1 }
|
|
||||||
ast.i8_type { return 1 }
|
|
||||||
ast.i16_type { return 2 }
|
|
||||||
ast.int_type { return 4 }
|
|
||||||
ast.i64_type { return 8 }
|
|
||||||
//
|
|
||||||
ast.byte_type { return 1 }
|
|
||||||
// ast.u8_type { return 1 }
|
|
||||||
ast.u16_type { return 2 }
|
|
||||||
ast.u32_type { return 4 }
|
|
||||||
ast.u64_type { return 8 }
|
|
||||||
else {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return none
|
|
||||||
}
|
}
|
||||||
ast.FloatLiteral {
|
ast.FloatLiteral {
|
||||||
x := expr.val.f64()
|
x := expr.val.f64()
|
||||||
|
|
Loading…
Reference in New Issue