ast: add a type_size() method (#14213)
parent
7fc9e3a4c1
commit
893e2ff6cb
|
@ -44,6 +44,7 @@ pub mut:
|
|||
mdeprecated_msg map[string]string // module deprecation message
|
||||
mdeprecated_after map[string]time.Time // module deprecation date
|
||||
builtin_pub_fns map[string]bool
|
||||
pointer_size int
|
||||
}
|
||||
|
||||
// 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'
|
||||
}
|
||||
|
||||
// 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
|
||||
pub fn (k Kind) str() string {
|
||||
return match k {
|
||||
|
|
|
@ -53,6 +53,7 @@ pub fn new_builder(pref &pref.Preferences) Builder {
|
|||
if pref.use_color == .never {
|
||||
util.emanager.set_support_color(false)
|
||||
}
|
||||
table.pointer_size = if pref.m64 { 8 } else { 4 }
|
||||
msvc := find_msvc(pref.m64) or {
|
||||
if pref.ccompiler == 'msvc' {
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
&& left_type != ast.int_literal_type_idx
|
||||
&& right_type != ast.int_literal_type_idx {
|
||||
ls := c.sizeof_integer(left_type)
|
||||
rs := c.sizeof_integer(right_type)
|
||||
ls := c.table.type_size(left_type)
|
||||
rs := c.table.type_size(right_type)
|
||||
// prevent e.g. `u32 == i16` but not `u16 == i32` as max_u16 fits in i32
|
||||
// TODO u32 == i32, change < to <=
|
||||
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()
|
||||
// }
|
||||
ast.SizeOf {
|
||||
xtype := 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
|
||||
return c.table.type_size(expr.typ)
|
||||
}
|
||||
ast.FloatLiteral {
|
||||
x := expr.val.f64()
|
||||
|
|
Loading…
Reference in New Issue