Browse Source

Fix alignment issues with vectors, unions, and raw_unions

Ginger Bill 8 years ago
parent
commit
e2d98324ba
6 changed files with 133 additions and 50 deletions
  1. 16 0
      core/_preload.odin
  2. 3 3
      src/checker/checker.cpp
  3. 7 3
      src/checker/expr.cpp
  4. 17 16
      src/checker/types.cpp
  5. 51 23
      src/ssa.cpp
  6. 39 5
      src/ssa_print.cpp

+ 16 - 0
core/_preload.odin

@@ -233,6 +233,7 @@ default_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator.Mode,
                                size, alignment: int,
                                old_memory: rawptr, old_size: int, flags: u64) -> rawptr {
 	using Allocator.Mode
+/*
 	match mode {
 	case ALLOC:
 		total_size := size + alignment + size_of(mem.AllocationHeader)
@@ -257,6 +258,21 @@ default_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator.Mode,
 		mem.allocation_header_fill(header, ptr, size)
 		return mem.zero(ptr, size)
 	}
+*/
+	match mode {
+	case ALLOC:
+		return os.heap_alloc(size)
+
+	case FREE:
+		os.heap_free(old_memory)
+		return nil
+
+	case FREE_ALL:
+		// NOTE(bill): Does nothing
+
+	case RESIZE:
+		return os.heap_resize(old_memory, size)
+	}
 
 	return nil
 }

+ 3 - 3
src/checker/checker.cpp

@@ -520,6 +520,9 @@ void init_universal_scope(void) {
 		entity->Builtin.id = id;
 		add_global_entity(entity);
 	}
+
+	t_u8_ptr = make_type_pointer(a, t_u8);
+	t_int_ptr = make_type_pointer(a, t_int);
 }
 
 
@@ -920,9 +923,6 @@ Map<Entity *> generate_minimum_dependency_map(CheckerInfo *info, Entity *start)
 void init_preload_types(Checker *c) {
 	PROF_PROC();
 
-	if (t_u8_ptr == NULL) {
-		t_u8_ptr = make_type_pointer(c->allocator, t_u8);
-	}
 
 	if (t_type_info == NULL) {
 		Entity *e = current_scope_lookup_entity(c->global_scope, make_string("Type_Info"));

+ 7 - 3
src/checker/expr.cpp

@@ -820,10 +820,13 @@ Type *check_get_params(Checker *c, Scope *scope, AstNodeArray params, b32 *is_va
 		}
 	}
 
-	if (is_variadic && params.count > 0) {
+	variable_count = variable_index;
+
+	if (is_variadic) {
+		GB_ASSERT(params.count > 0);
 		// NOTE(bill): Change last variadic parameter to be a slice
 		// Custom Calling convention for variadic parameters
-		Entity *end = variables[params.count-1];
+		Entity *end = variables[variable_count-1];
 		end->type = make_type_slice(c->allocator, end->type);
 	}
 
@@ -3458,6 +3461,7 @@ void check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode
 		defer (gb_string_free(proc_str));
 		error(ast_node_token(call), err_fmt, proc_str, param_count);
 		operand->mode = Addressing_Invalid;
+		return;
 	}
 
 	GB_ASSERT(proc_type->Proc.params != NULL);
@@ -3467,7 +3471,6 @@ void check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode
 		Type *arg_type = sig_params[operand_index]->type;
 		Operand o = operands[operand_index];
 		if (variadic) {
-
 			o = operands[operand_index];
 		}
 		check_assignment(c, &o, arg_type, make_string("argument"), true);
@@ -3476,6 +3479,7 @@ void check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode
 	if (variadic) {
 		b32 variadic_expand = false;
 		Type *slice = sig_params[param_count]->type;
+		GB_ASSERT(is_type_slice(slice));
 		Type *elem = base_type(slice)->Slice.elem;
 		Type *t = elem;
 		for (; operand_index < operands.count; operand_index++) {

+ 17 - 16
src/checker/types.cpp

@@ -364,7 +364,8 @@ gb_global Type *t_byte            = &basic_type_aliases[0];
 gb_global Type *t_rune            = &basic_type_aliases[1];
 
 
-gb_global Type *t_u8_ptr = NULL;
+gb_global Type *t_u8_ptr  = NULL;
+gb_global Type *t_int_ptr = NULL;
 
 gb_global Type *t_type_info            = NULL;
 gb_global Type *t_type_info_ptr        = NULL;
@@ -908,25 +909,26 @@ Selection lookup_field(gbAllocator a, Type *type_, String field_name, b32 is_typ
 			sel.entity = make_entity_constant(a, NULL, make_token_ident(count_str), t_int, make_exact_value_integer(type->Vector.count));
 			return sel;
 		}
+
 		if (type->Vector.count <= 4 && !is_type_boolean(type->Vector.elem)) {
 			// HACK(bill): Memory leak
 			switch (type->Vector.count) {
-			#define _VECTOR_FIELD(_name, length) \
-			case (length): \
+			#define _VECTOR_FIELD_CASE(_length, _name) \
+			case (_length): \
 				if (field_name == _name) { \
-					selection_add_index(&sel, (length)-1); \
-					sel.entity = make_entity_field(a, NULL, make_token_ident(make_string(_name)), type->Vector.elem, false, (length)-1); \
+					selection_add_index(&sel, (_length)-1); \
+					sel.entity = make_entity_vector_elem(a, NULL, make_token_ident(make_string(_name)), type->Vector.elem, (_length)-1); \
 					return sel; \
 				} \
 				/*fallthrough*/
 
-			_VECTOR_FIELD("w", 4);
-			_VECTOR_FIELD("z", 3);
-			_VECTOR_FIELD("y", 2);
-			_VECTOR_FIELD("x", 1);
-			case 0: break;
+			_VECTOR_FIELD_CASE(4, "w");
+			_VECTOR_FIELD_CASE(3, "z");
+			_VECTOR_FIELD_CASE(2, "y");
+			_VECTOR_FIELD_CASE(1, "x");
+			default: break;
 
-			#undef _VECTOR_FIELD
+			#undef _VECTOR_FIELD_CASE
 			}
 		}
 
@@ -1057,10 +1059,9 @@ i64 type_align_of(BaseTypeSizes s, gbAllocator allocator, Type *t) {
 		return type_align_of(s, allocator, t->Array.elem);
 	case Type_Vector: {
 		i64 size = type_size_of(s, allocator, t->Vector.elem);
-		size *= t->Vector.count;
-		size = prev_pow2(size);
-		// TODO(bill): Type_Vector type_align_of
-		return gb_clamp(size, 1, s.max_align);
+		i64 count = gb_max(prev_pow2(size), 1);
+		i64 total = size * count;
+		return gb_clamp(total, 1, s.max_align);
 	} break;
 
 	case Type_Tuple: {
@@ -1097,7 +1098,7 @@ i64 type_align_of(BaseTypeSizes s, gbAllocator allocator, Type *t) {
 			}
 			break;
 		case TypeRecord_Union: {
-			i64 max = s.word_size;
+			i64 max = 1;
 			for (isize i = 1; i < t->Record.field_count; i++) {
 				// NOTE(bill): field zero is null
 				i64 align = type_align_of(s, allocator, t->Record.fields[i]->type);

+ 51 - 23
src/ssa.cpp

@@ -128,6 +128,8 @@ struct ssaProcedure {
 	SSA_INSTR_KIND(StructElementPtr), \
 	SSA_INSTR_KIND(ArrayExtractValue), \
 	SSA_INSTR_KIND(StructExtractValue), \
+	SSA_INSTR_KIND(UnionTagPtr), \
+	SSA_INSTR_KIND(UnionTagValue), \
 	SSA_INSTR_KIND(Conv), \
 	SSA_INSTR_KIND(Jump), \
 	SSA_INSTR_KIND(If), \
@@ -233,6 +235,14 @@ struct ssaInstr {
 			Type *    result_type;
 			i32       index;
 		} StructExtractValue;
+		struct {
+			ssaValue *address;
+			Type     *type; // ^int
+		} UnionTagPtr;
+		struct {
+			ssaValue *address;
+			Type     *type; // int
+		} UnionTagValue;
 		struct {
 			ssaValue *value;
 			ssaValue *elem;
@@ -559,6 +569,10 @@ Type *ssa_instr_type(ssaInstr *instr) {
 		return instr->ArrayExtractValue.result_type;
 	case ssaInstr_StructExtractValue:
 		return instr->StructExtractValue.result_type;
+	case ssaInstr_UnionTagPtr:
+		return instr->UnionTagPtr.type;
+	case ssaInstr_UnionTagValue:
+		return instr->UnionTagValue.type;
 	case ssaInstr_BinaryOp:
 		return instr->BinaryOp.type;
 	case ssaInstr_Conv:
@@ -870,6 +884,23 @@ ssaValue *ssa_make_instr_struct_extract_value(ssaProcedure *p, ssaValue *address
 	return v;
 }
 
+ssaValue *ssa_make_instr_union_tag_ptr(ssaProcedure *p, ssaValue *address) {
+	ssaValue *v = ssa_alloc_instr(p, ssaInstr_UnionTagPtr);
+	ssaInstr *i = &v->Instr;
+	i->UnionTagPtr.address = address;
+	i->UnionTagPtr.type = t_int_ptr;
+	return v;
+}
+
+ssaValue *ssa_make_instr_union_tag_value(ssaProcedure *p, ssaValue *address) {
+	ssaValue *v = ssa_alloc_instr(p, ssaInstr_UnionTagValue);
+	ssaInstr *i = &v->Instr;
+	i->UnionTagValue.address = address;
+	i->UnionTagValue.type = t_int_ptr;
+	return v;
+}
+
+
 ssaValue *ssa_make_instr_binary_op(ssaProcedure *p, TokenKind op, ssaValue *left, ssaValue *right, Type *type) {
 	ssaValue *v = ssa_alloc_instr(p, ssaInstr_BinaryOp);
 	ssaInstr *i = &v->Instr;
@@ -1535,6 +1566,20 @@ ssaValue *ssa_emit_array_ep(ssaProcedure *proc, ssaValue *s, i32 index) {
 	return ssa_emit_array_ep(proc, s, ssa_make_const_i32(proc->module->allocator, index));
 }
 
+ssaValue *ssa_emit_union_tag_ptr(ssaProcedure *proc, ssaValue *u) {
+	Type *t = ssa_type(u);
+	GB_ASSERT(is_type_pointer(t) &&
+	          is_type_union(type_deref(t)));
+	return ssa_emit(proc, ssa_make_instr_union_tag_ptr(proc, u));
+}
+
+ssaValue *ssa_emit_union_tag_value(ssaProcedure *proc, ssaValue *u) {
+	Type *t = ssa_type(u);
+	GB_ASSERT(is_type_union(t));
+	return ssa_emit(proc, ssa_make_instr_union_tag_value(proc, u));
+}
+
+
 
 ssaValue *ssa_emit_struct_ep(ssaProcedure *proc, ssaValue *s, i32 index) {
 	gbAllocator a = proc->module->allocator;
@@ -1571,15 +1616,6 @@ ssaValue *ssa_emit_struct_ep(ssaProcedure *proc, ssaValue *s, i32 index) {
 		case 0: result_type = make_type_pointer(a, t->Maybe.elem); break;
 		case 1: result_type = make_type_pointer(a, t_bool);        break;
 		}
-	} else if (is_type_union(t)) {
-		switch (index) {
-		case 1: result_type = make_type_pointer(a, t_int); break;
-
-		case 0:
-		default:
-			GB_PANIC("TODO(bill): struct_gep 0 for unions");
-			break;
-		}
 	} else {
 		GB_PANIC("TODO(bill): struct_gep type: %s, %d", type_to_string(ssa_type(s)), index);
 	}
@@ -1634,15 +1670,6 @@ ssaValue *ssa_emit_struct_ev(ssaProcedure *proc, ssaValue *s, i32 index) {
 		case 0: result_type = t->Maybe.elem; break;
 		case 1: result_type = t_bool;        break;
 		}
-	} else if (is_type_union(t)) {
-		switch (index) {
-		case 1: result_type = t_int; break;
-
-		case 0:
-		default:
-			GB_PANIC("TODO(bill): struct_gep 0 for unions");
-			break;
-		}
 	} else {
 		GB_PANIC("TODO(bill): struct_ev type: %s, %d", type_to_string(ssa_type(s)), index);
 	}
@@ -1718,8 +1745,9 @@ ssaValue *ssa_emit_deep_field_ev(ssaProcedure *proc, Type *type, ssaValue *e, Se
 
 
 		if (is_type_raw_union(type)) {
+			GB_PANIC("TODO(bill): IS THIS EVEN CORRECT?");
 			type = type->Record.fields[index]->type;
-			e = ssa_emit_conv(proc, e, make_type_pointer(proc->module->allocator, type));
+			e = ssa_emit_conv(proc, e, type);
 		} else {
 			e = ssa_emit_struct_ev(proc, e, index);
 		}
@@ -1990,7 +2018,7 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t) {
 				gbAllocator allocator = proc->module->allocator;
 				ssaValue *parent = ssa_add_local_generated(proc, t);
 				ssaValue *tag = ssa_make_const_int(allocator, i);
-				ssa_emit_store(proc, ssa_emit_struct_ep(proc, parent, 1), tag);
+				ssa_emit_store(proc, ssa_emit_union_tag_ptr(proc, parent), tag);
 
 				ssaValue *data = ssa_emit_conv(proc, parent, t_rawptr);
 
@@ -2189,7 +2217,7 @@ ssaValue *ssa_emit_union_cast(ssaProcedure *proc, ssaValue *value, Type *tuple)
 		Type *dst_ptr = tuple->Tuple.variables[0]->type;
 		Type *dst = type_deref(dst_ptr);
 
-		ssaValue *tag = ssa_emit_load(proc, ssa_emit_struct_ep(proc, value, 1));
+		ssaValue *tag = ssa_emit_load(proc, ssa_emit_union_tag_ptr(proc, value));
 		ssaValue *dst_tag = NULL;
 		for (isize i = 1; i < src->Record.field_count; i++) {
 			Entity *f = src->Record.fields[i];
@@ -2222,7 +2250,7 @@ ssaValue *ssa_emit_union_cast(ssaProcedure *proc, ssaValue *value, Type *tuple)
 		Type *dst = tuple->Tuple.variables[0]->type;
 		Type *dst_ptr = make_type_pointer(a, dst);
 
-		ssaValue *tag = ssa_emit_struct_ev(proc, value, 1);
+		ssaValue *tag = ssa_emit_union_tag_value(proc, value);
 		ssaValue *dst_tag = NULL;
 		for (isize i = 1; i < src->Record.field_count; i++) {
 			Entity *f = src->Record.fields[i];
@@ -4228,7 +4256,7 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
 		GB_ASSERT(is_type_union(union_type));
 
 		ssa_emit_comment(proc, make_string("get union's tag"));
-		ssaValue *tag_index = ssa_emit_struct_ep(proc, parent, 1);
+		ssaValue *tag_index = ssa_emit_union_tag_ptr(proc, parent);
 		tag_index = ssa_emit_load(proc, tag_index);
 
 		ssaValue *data = ssa_emit_conv(proc, parent, t_rawptr);

+ 39 - 5
src/ssa_print.cpp

@@ -212,12 +212,19 @@ void ssa_print_type(ssaFileBuffer *f, ssaModule *m, Type *t) {
 			}
 			break;
 		case TypeRecord_Union: {
-			i64 size_of_union = type_size_of(s, heap_allocator(), t) - s.word_size;
-			ssa_fprintf(f, "{[%lld x i8], i%lld}", size_of_union, word_bits);
+			// NOTE(bill): The zero size array is used to fix the alignment used in a structure as
+			// LLVM takes the first element's alignment as the entire alignment (like C)
+			i64 size_of_union  = type_size_of(s, heap_allocator(), t) - s.word_size;
+			i64 align_of_union = type_align_of(s, heap_allocator(), t);
+			ssa_fprintf(f, "{[0 x <%lld x i8>], [%lld x i8], i%lld}", align_of_union, size_of_union, word_bits);
+		} break;
+		case TypeRecord_RawUnion: {
+			// NOTE(bill): The zero size array is used to fix the alignment used in a structure as
+			// LLVM takes the first element's alignment as the entire alignment (like C)
+			i64 size_of_union  = type_size_of(s, heap_allocator(), t);
+			i64 align_of_union = type_align_of(s, heap_allocator(), t);
+			ssa_fprintf(f, "{[0 x <%lld x i8>], [%lld x i8]}", align_of_union, size_of_union);
 		} break;
-		case TypeRecord_RawUnion:
-			ssa_fprintf(f, "[%lld x i8]", type_size_of(s, heap_allocator(), t));
-			break;
 		case TypeRecord_Enum:
 			ssa_print_type(f, m, t->Record.enum_base);
 			break;
@@ -748,6 +755,33 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
 		ssa_fprintf(f, ", %d\n", instr->StructExtractValue.index);
 	} break;
 
+	case ssaInstr_UnionTagPtr: {
+		Type *et = ssa_type(instr->UnionTagPtr.address);
+		ssa_fprintf(f, "%%%d = getelementptr inbounds ", value->index);
+
+		ssa_print_type(f, m, type_deref(et));
+		ssa_fprintf(f, ", ");
+		ssa_print_type(f, m, et);
+		ssa_fprintf(f, " ");
+		ssa_print_value(f, m, instr->UnionTagPtr.address, et);
+		ssa_fprintf(f, ", ");
+		ssa_print_type(f, m, t_int);
+		ssa_fprintf(f, " 0, ");
+		ssa_print_type(f, m, t_i32);
+		ssa_fprintf(f, " %d", 2);
+		ssa_fprintf(f, "\n");
+	} break;
+
+	case ssaInstr_UnionTagValue: {
+		Type *et = ssa_type(instr->UnionTagValue.address);
+		ssa_fprintf(f, "%%%d = extractvalue ", value->index);
+
+		ssa_print_type(f, m, et);
+		ssa_fprintf(f, " ");
+		ssa_print_value(f, m, instr->UnionTagValue.address, et);
+		ssa_fprintf(f, ", %d\n", 2);
+	} break;
+
 	case ssaInstr_Jump: {;
 		ssa_fprintf(f, "br label %%");
 		ssa_print_block_name(f, instr->Jump.block);