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