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_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