Browse Source

LLVM Code Generator: Add explicitly padding between fields in LLVM struct types

gingerBill 3 years ago
parent
commit
8de728e3dc

+ 1 - 3
src/llvm_backend.cpp

@@ -806,8 +806,6 @@ lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *startup_runtime)
 		lbAddr all_tests_array_addr = lb_add_global_generated(p->module, array_type, {});
 		lbAddr all_tests_array_addr = lb_add_global_generated(p->module, array_type, {});
 		lbValue all_tests_array = lb_addr_get_ptr(p, all_tests_array_addr);
 		lbValue all_tests_array = lb_addr_get_ptr(p, all_tests_array_addr);
 
 
-		LLVMTypeRef lbt_Internal_Test = lb_type(m, t_Internal_Test);
-
 		LLVMValueRef indices[2] = {};
 		LLVMValueRef indices[2] = {};
 		indices[0] = LLVMConstInt(lb_type(m, t_i32), 0, false);
 		indices[0] = LLVMConstInt(lb_type(m, t_i32), 0, false);
 
 
@@ -834,7 +832,7 @@ lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *startup_runtime)
 			GB_ASSERT(LLVMIsConstant(vals[2]));
 			GB_ASSERT(LLVMIsConstant(vals[2]));
 
 
 			LLVMValueRef dst = LLVMConstInBoundsGEP(all_tests_array.value, indices, gb_count_of(indices));
 			LLVMValueRef dst = LLVMConstInBoundsGEP(all_tests_array.value, indices, gb_count_of(indices));
-			LLVMValueRef src = llvm_const_named_struct(lbt_Internal_Test, vals, gb_count_of(vals));
+			LLVMValueRef src = llvm_const_named_struct(m, t_Internal_Test, vals, gb_count_of(vals));
 
 
 			LLVMBuildStore(p->builder, src, dst);
 			LLVMBuildStore(p->builder, src, dst);
 		}
 		}

+ 3 - 0
src/llvm_backend.hpp

@@ -432,6 +432,7 @@ void lb_build_nested_proc(lbProcedure *p, AstProcLit *pd, Entity *e);
 lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, Ast *left, Ast *right, Type *type);
 lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, Ast *left, Ast *right, Type *type);
 lbValue lb_build_cond(lbProcedure *p, Ast *cond, lbBlock *true_block, lbBlock *false_block);
 lbValue lb_build_cond(lbProcedure *p, Ast *cond, lbBlock *true_block, lbBlock *false_block);
 
 
+LLVMValueRef llvm_const_named_struct(lbModule *m, Type *t, LLVMValueRef *values, isize value_count_);
 LLVMValueRef llvm_const_named_struct(LLVMTypeRef t, LLVMValueRef *values, isize value_count_);
 LLVMValueRef llvm_const_named_struct(LLVMTypeRef t, LLVMValueRef *values, isize value_count_);
 void lb_set_entity_from_other_modules_linkage_correctly(lbModule *other_module, Entity *e, String const &name);
 void lb_set_entity_from_other_modules_linkage_correctly(lbModule *other_module, Entity *e, String const &name);
 
 
@@ -446,6 +447,8 @@ lbCopyElisionHint lb_set_copy_elision_hint(lbProcedure *p, lbAddr const &addr, A
 void lb_reset_copy_elision_hint(lbProcedure *p, lbCopyElisionHint prev_hint);
 void lb_reset_copy_elision_hint(lbProcedure *p, lbCopyElisionHint prev_hint);
 lbValue lb_consume_copy_elision_hint(lbProcedure *p);
 lbValue lb_consume_copy_elision_hint(lbProcedure *p);
 
 
+bool lb_struct_has_padding_prefix(Type *t);
+
 #define LB_STARTUP_RUNTIME_PROC_NAME   "__$startup_runtime"
 #define LB_STARTUP_RUNTIME_PROC_NAME   "__$startup_runtime"
 #define LB_STARTUP_TYPE_INFO_PROC_NAME "__$startup_type_info"
 #define LB_STARTUP_TYPE_INFO_PROC_NAME "__$startup_type_info"
 #define LB_TYPE_INFO_DATA_NAME       "__$type_info_data"
 #define LB_TYPE_INFO_DATA_NAME       "__$type_info_data"

+ 60 - 24
src/llvm_backend_const.cpp

@@ -99,7 +99,7 @@ LLVMValueRef llvm_const_cast(LLVMValueRef val, LLVMTypeRef dst) {
 		return LLVMConstNull(dst);
 		return LLVMConstNull(dst);
 	}
 	}
 
 
-	GB_ASSERT(LLVMSizeOf(dst) == LLVMSizeOf(src));
+	GB_ASSERT_MSG(LLVMSizeOf(dst) == LLVMSizeOf(src), "%s vs %s", LLVMPrintTypeToString(dst), LLVMPrintTypeToString(src));
 	LLVMTypeKind kind = LLVMGetTypeKind(dst);
 	LLVMTypeKind kind = LLVMGetTypeKind(dst);
 	switch (kind) {
 	switch (kind) {
 	case LLVMPointerTypeKind:
 	case LLVMPointerTypeKind:
@@ -125,11 +125,43 @@ lbValue lb_const_ptr_cast(lbModule *m, lbValue value, Type *t) {
 	return res;
 	return res;
 }
 }
 
 
+LLVMValueRef llvm_const_named_struct(lbModule *m, Type *t, LLVMValueRef *values, isize value_count_) {
+	LLVMTypeRef struct_type = lb_type(m, t);
+	GB_ASSERT(LLVMGetTypeKind(struct_type) == LLVMStructTypeKind);
+	
+	unsigned value_count = cast(unsigned)value_count_;
+	unsigned elem_count = LLVMCountStructElementTypes(struct_type);
+	if (elem_count == value_count) {
+		return llvm_const_named_struct(struct_type, values, value_count_);
+	}
+	Type *bt = base_type(t);
+	GB_ASSERT(bt->kind == Type_Struct);
+	
+	GB_ASSERT(value_count_ == bt->Struct.fields.count);
+	
+	unsigned field_offset = 0;
+	if (lb_struct_has_padding_prefix(bt)) {
+		field_offset = 1;
+	}
+
+	unsigned values_with_padding_count = field_offset + cast(unsigned)(bt->Struct.fields.count*2 + 1);
+	LLVMValueRef *values_with_padding = gb_alloc_array(permanent_allocator(), LLVMValueRef, values_with_padding_count);
+	for (unsigned i = 0; i < value_count; i++) {
+		values_with_padding[field_offset + i*2 + 1] = values[i];
+	}
+	for (unsigned i = 0; i < values_with_padding_count; i++) {
+		if (values_with_padding[i] == nullptr) {
+			values_with_padding[i] = LLVMConstNull(LLVMStructGetTypeAtIndex(struct_type, i));
+		}
+	}
+	
+	return llvm_const_named_struct(struct_type, values_with_padding, values_with_padding_count);
+}
 
 
 LLVMValueRef llvm_const_named_struct(LLVMTypeRef t, LLVMValueRef *values, isize value_count_) {
 LLVMValueRef llvm_const_named_struct(LLVMTypeRef t, LLVMValueRef *values, isize value_count_) {
 	unsigned value_count = cast(unsigned)value_count_;
 	unsigned value_count = cast(unsigned)value_count_;
 	unsigned elem_count = LLVMCountStructElementTypes(t);
 	unsigned elem_count = LLVMCountStructElementTypes(t);
-	GB_ASSERT(value_count == elem_count);
+	GB_ASSERT_MSG(value_count == elem_count, "%s %u %u", LLVMPrintTypeToString(t), value_count, elem_count);
 	for (unsigned i = 0; i < elem_count; i++) {
 	for (unsigned i = 0; i < elem_count; i++) {
 		LLVMTypeRef elem_type = LLVMStructGetTypeAtIndex(t, i);
 		LLVMTypeRef elem_type = LLVMStructGetTypeAtIndex(t, i);
 		values[i] = llvm_const_cast(values[i], elem_type);
 		values[i] = llvm_const_cast(values[i], elem_type);
@@ -235,7 +267,7 @@ lbValue lb_emit_source_code_location(lbProcedure *p, String const &procedure, To
 	fields[3]/*procedure*/ = lb_find_or_add_entity_string(p->module, procedure).value;
 	fields[3]/*procedure*/ = lb_find_or_add_entity_string(p->module, procedure).value;
 
 
 	lbValue res = {};
 	lbValue res = {};
-	res.value = llvm_const_named_struct(lb_type(m, t_source_code_location), fields, gb_count_of(fields));
+	res.value = llvm_const_named_struct(m, t_source_code_location, fields, gb_count_of(fields));
 	res.type = t_source_code_location;
 	res.type = t_source_code_location;
 	return res;
 	return res;
 }
 }
@@ -422,7 +454,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc
 					LLVMValueRef len = LLVMConstInt(lb_type(m, t_int), count, true);
 					LLVMValueRef len = LLVMConstInt(lb_type(m, t_int), count, true);
 					LLVMValueRef values[2] = {ptr, len};
 					LLVMValueRef values[2] = {ptr, len};
 
 
-					res.value = llvm_const_named_struct(lb_type(m, original_type), values, 2);
+					res.value = llvm_const_named_struct(m, original_type, values, 2);
 					return res;
 					return res;
 				}
 				}
 			}
 			}
@@ -512,7 +544,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc
 				LLVMValueRef values[2] = {ptr, str_len};
 				LLVMValueRef values[2] = {ptr, str_len};
 				GB_ASSERT(is_type_string(original_type));
 				GB_ASSERT(is_type_string(original_type));
 
 
-				res.value = llvm_const_named_struct(lb_type(m, original_type), values, 2);
+				res.value = llvm_const_named_struct(m, original_type, values, 2);
 			}
 			}
 
 
 			return res;
 			return res;
@@ -554,7 +586,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc
 				break;
 				break;
 			}
 			}
 
 
-			res.value = llvm_const_named_struct(lb_type(m, original_type), values, 2);
+			res.value = llvm_const_named_struct(m, original_type, values, 2);
 			return res;
 			return res;
 		}
 		}
 		break;
 		break;
@@ -585,7 +617,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc
 				break;
 				break;
 			}
 			}
 
 
-			res.value = llvm_const_named_struct(lb_type(m, original_type), values, 4);
+			res.value = llvm_const_named_struct(m, original_type, values, 4);
 			return res;
 			return res;
 		}
 		}
 		break;
 		break;
@@ -802,11 +834,15 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc
 			}
 			}
 
 
 			isize offset = 0;
 			isize offset = 0;
-			if (type->Struct.custom_align > 0) {
+			if (lb_struct_has_padding_prefix(type)) {
 				offset = 1;
 				offset = 1;
 			}
 			}
+			
+			LLVMTypeRef struct_type = lb_type(m, original_type);
 
 
-			isize value_count = type->Struct.fields.count + offset;
+			unsigned value_count = cast(unsigned)(offset + type->Struct.fields.count*2 + 1);
+			GB_ASSERT(LLVMCountStructElementTypes(struct_type) == value_count);
+			
 			LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, value_count);
 			LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, value_count);
 			bool *visited = gb_alloc_array(temporary_allocator(), bool, value_count);
 			bool *visited = gb_alloc_array(temporary_allocator(), bool, value_count);
 
 
@@ -822,9 +858,11 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc
 
 
 						Selection sel = lookup_field(type, name, false);
 						Selection sel = lookup_field(type, name, false);
 						Entity *f = type->Struct.fields[sel.index[0]];
 						Entity *f = type->Struct.fields[sel.index[0]];
+							
+						isize index = offset + f->Variable.field_index*2 + 1;
 						if (elem_type_can_be_constant(f->type)) {
 						if (elem_type_can_be_constant(f->type)) {
-							values[offset+f->Variable.field_index] = lb_const_value(m, f->type, tav.value, allow_local).value;
-							visited[offset+f->Variable.field_index] = true;
+							values[index] = lb_const_value(m, f->type, tav.value, allow_local).value;
+							visited[index] = true;
 						}
 						}
 					}
 					}
 				} else {
 				} else {
@@ -835,25 +873,24 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc
 						if (tav.mode != Addressing_Invalid) {
 						if (tav.mode != Addressing_Invalid) {
 							val = tav.value;
 							val = tav.value;
 						}
 						}
+						
+						isize index = offset + f->Variable.field_index*2 + 1;
 						if (elem_type_can_be_constant(f->type)) {
 						if (elem_type_can_be_constant(f->type)) {
-							values[offset+f->Variable.field_index]  = lb_const_value(m, f->type, val, allow_local).value;
-							visited[offset+f->Variable.field_index] = true;
+							values[index]  = lb_const_value(m, f->type, val, allow_local).value;
+							visited[index] = true;
 						}
 						}
 					}
 					}
 				}
 				}
 			}
 			}
 
 
-			for (isize i = 0; i < type->Struct.fields.count; i++) {
-				if (!visited[offset+i]) {
-					GB_ASSERT(values[offset+i] == nullptr);
-					values[offset+i] = lb_const_nil(m, get_struct_field_type(type, i)).value;
+			for (isize i = 0; i < value_count; i++) {
+				if (!visited[i]) {
+					GB_ASSERT(values[i] == nullptr);
+					LLVMTypeRef type = LLVMStructGetTypeAtIndex(struct_type, cast(unsigned)i);
+					values[i] = LLVMConstNull(type);
 				}
 				}
 			}
 			}
 
 
-			if (type->Struct.custom_align > 0) {
-				values[0] = LLVMConstNull(lb_alignment_prefix_type_hack(m, type->Struct.custom_align));
-			}
-
 			bool is_constant = true;
 			bool is_constant = true;
 
 
 			for (isize i = 0; i < value_count; i++) {
 			for (isize i = 0; i < value_count; i++) {
@@ -866,7 +903,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc
 			}
 			}
 
 
 			if (is_constant) {
 			if (is_constant) {
-				res.value = llvm_const_named_struct(lb_type(m, original_type), values, cast(unsigned)value_count);
+				res.value = llvm_const_named_struct(struct_type, values, cast(unsigned)value_count);
 				return res;
 				return res;
 			} else {
 			} else {
 				// TODO(bill): THIS IS HACK BUT IT WORKS FOR WHAT I NEED
 				// TODO(bill): THIS IS HACK BUT IT WORKS FOR WHAT I NEED
@@ -880,8 +917,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc
 						new_values[i] = LLVMConstNull(LLVMTypeOf(old_value));
 						new_values[i] = LLVMConstNull(LLVMTypeOf(old_value));
 					}
 					}
 				}
 				}
-				LLVMValueRef constant_value = llvm_const_named_struct(lb_type(m, original_type), new_values, cast(unsigned)value_count);
-
+				LLVMValueRef constant_value = llvm_const_named_struct(struct_type, new_values, cast(unsigned)value_count);
 
 
 				GB_ASSERT(is_local);
 				GB_ASSERT(is_local);
 				lbProcedure *p = m->curr_procedure;
 				lbProcedure *p = m->curr_procedure;

+ 4 - 5
src/llvm_backend_expr.cpp

@@ -1923,9 +1923,9 @@ lbValue lb_emit_comp_against_nil(lbProcedure *p, TokenKind op_kind, lbValue x) {
 			lbValue map_ptr = lb_address_from_load_or_generate_local(p, x);
 			lbValue map_ptr = lb_address_from_load_or_generate_local(p, x);
 
 
 			unsigned indices[2] = {0, 0};
 			unsigned indices[2] = {0, 0};
-			LLVMValueRef hashes_data = LLVMBuildStructGEP(p->builder, map_ptr.value, 0, "");
-			LLVMValueRef hashes_data_ptr_ptr = LLVMBuildStructGEP(p->builder, hashes_data, 0, "");
-			LLVMValueRef hashes_data_ptr = LLVMBuildLoad(p->builder, hashes_data_ptr_ptr, "");
+			lbValue hashes_data = lb_emit_struct_ep(p, map_ptr, 0);
+			lbValue hashes_data_ptr_ptr = lb_emit_struct_ep(p, hashes_data, 0);
+			LLVMValueRef hashes_data_ptr = LLVMBuildLoad(p->builder, hashes_data_ptr_ptr.value, "");
 
 
 			if (op_kind == Token_CmpEq) {
 			if (op_kind == Token_CmpEq) {
 				res.value = LLVMBuildIsNull(p->builder, hashes_data_ptr, "");
 				res.value = LLVMBuildIsNull(p->builder, hashes_data_ptr, "");
@@ -2786,7 +2786,7 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) {
 
 
 		bool deref = is_type_pointer(t);
 		bool deref = is_type_pointer(t);
 		t = base_type(type_deref(t));
 		t = base_type(type_deref(t));
-		if (is_type_soa_struct(t)) {
+		if (is_type_soa_struct(t)) {			
 			// SOA STRUCTURES!!!!
 			// SOA STRUCTURES!!!!
 			lbValue val = lb_build_addr_ptr(p, ie->expr);
 			lbValue val = lb_build_addr_ptr(p, ie->expr);
 			if (deref) {
 			if (deref) {
@@ -2821,7 +2821,6 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) {
 				// lbValue len = ir_soa_struct_len(p, base_struct);
 				// lbValue len = ir_soa_struct_len(p, base_struct);
 				// lb_emit_bounds_check(p, ast_token(ie->index), index, len);
 				// lb_emit_bounds_check(p, ast_token(ie->index), index, len);
 			}
 			}
-
 			lbValue val = lb_emit_ptr_offset(p, field, index);
 			lbValue val = lb_emit_ptr_offset(p, field, index);
 			return lb_addr(val);
 			return lb_addr(val);
 		}
 		}

+ 55 - 15
src/llvm_backend_general.cpp

@@ -1109,7 +1109,7 @@ lbValue lb_emit_union_tag_ptr(lbProcedure *p, lbValue u) {
 
 
 	LLVMTypeRef uvt = LLVMGetElementType(LLVMTypeOf(u.value));
 	LLVMTypeRef uvt = LLVMGetElementType(LLVMTypeOf(u.value));
 	unsigned element_count = LLVMCountStructElementTypes(uvt);
 	unsigned element_count = LLVMCountStructElementTypes(uvt);
-	GB_ASSERT_MSG(element_count == 3, "(%s) != (%s)", type_to_string(ut), LLVMPrintTypeToString(uvt));
+	GB_ASSERT_MSG(element_count == 3, "element_count=%u (%s) != (%s)", element_count, type_to_string(ut), LLVMPrintTypeToString(uvt));
 
 
 	lbValue tag_ptr = {};
 	lbValue tag_ptr = {};
 	tag_ptr.value = LLVMBuildStructGEP(p->builder, u.value, 2, "");
 	tag_ptr.value = LLVMBuildStructGEP(p->builder, u.value, 2, "");
@@ -1160,13 +1160,9 @@ LLVMTypeRef lb_alignment_prefix_type_hack(lbModule *m, i64 alignment) {
 		return LLVMArrayType(lb_type(m, t_u32), 0);
 		return LLVMArrayType(lb_type(m, t_u32), 0);
 	case 8:
 	case 8:
 		return LLVMArrayType(lb_type(m, t_u64), 0);
 		return LLVMArrayType(lb_type(m, t_u64), 0);
-	case 16:
+	default: case 16:
 		return LLVMArrayType(LLVMVectorType(lb_type(m, t_u32), 4), 0);
 		return LLVMArrayType(LLVMVectorType(lb_type(m, t_u32), 4), 0);
-	default:
-		GB_PANIC("Invalid alignment %d", cast(i32)alignment);
-		break;
 	}
 	}
-	return nullptr;
 }
 }
 
 
 String lb_mangle_name(lbModule *m, Entity *e) {
 String lb_mangle_name(lbModule *m, Entity *e) {
@@ -1650,11 +1646,17 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
 			GB_ASSERT(field_count == 2);
 			GB_ASSERT(field_count == 2);
 			LLVMTypeRef *fields = gb_alloc_array(temporary_allocator(), LLVMTypeRef, field_count);
 			LLVMTypeRef *fields = gb_alloc_array(temporary_allocator(), LLVMTypeRef, field_count);
 
 
-			LLVMTypeRef entries_fields[4] = {
-				lb_type(m, t_rawptr),
+			LLVMTypeRef padding_type = LLVMArrayType(lb_type(m, t_uintptr), 0);
+			LLVMTypeRef entries_fields[] = {
+				padding_type,
+				lb_type(m, t_rawptr), // data
+				padding_type,
 				lb_type(m, t_int), // len
 				lb_type(m, t_int), // len
+				padding_type,
 				lb_type(m, t_int), // cap
 				lb_type(m, t_int), // cap
+				padding_type,
 				lb_type(m, t_allocator), // allocator
 				lb_type(m, t_allocator), // allocator
+				padding_type,
 			};
 			};
 
 
 			fields[0] = lb_type(m, internal_type->Struct.fields[0]->type);
 			fields[0] = lb_type(m, internal_type->Struct.fields[0]->type);
@@ -1676,25 +1678,63 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
 			}
 			}
 
 
 			isize offset = 0;
 			isize offset = 0;
-			if (type->Struct.custom_align > 0) {
+			if (lb_struct_has_padding_prefix(type)) {
 				offset = 1;
 				offset = 1;
 			}
 			}
 
 
 			m->internal_type_level += 1;
 			m->internal_type_level += 1;
 			defer (m->internal_type_level -= 1);
 			defer (m->internal_type_level -= 1);
 
 
-			unsigned field_count = cast(unsigned)(type->Struct.fields.count + offset);
+			unsigned field_count = cast(unsigned)(offset + type->Struct.fields.count*2 + 1);
 			LLVMTypeRef *fields = gb_alloc_array(temporary_allocator(), LLVMTypeRef, field_count);
 			LLVMTypeRef *fields = gb_alloc_array(temporary_allocator(), LLVMTypeRef, field_count);
 
 
+			LLVMTypeRef type_u8 = lb_type(m, t_u8);
+			LLVMTypeRef type_u16 = lb_type(m, t_u16);
+			LLVMTypeRef type_u32 = lb_type(m, t_u32);
+			LLVMTypeRef type_u64 = lb_type(m, t_u64);
+			
+			i64 padding_offset = 0;
 			for_array(i, type->Struct.fields) {
 			for_array(i, type->Struct.fields) {
 				Entity *field = type->Struct.fields[i];
 				Entity *field = type->Struct.fields[i];
-				fields[i+offset] = lb_type(m, field->type);
-			}
+				i64 padding = type->Struct.offsets[i]-padding_offset;
 
 
+				LLVMTypeRef padding_type = nullptr;
+				if (padding_offset == 0) {
+					padding_type = lb_alignment_prefix_type_hack(m, type_align_of(type));
+				} else {
+					i64 alignment = type_align_of(field->type);
+					// NOTE(bill): limit to `[N x u64]` to prevent ABI issues
+					alignment = gb_min(alignment, 8); 
+					if (padding % alignment == 0) {
+						isize len = padding/alignment;
+						switch (alignment) {
+						case 1: padding_type = LLVMArrayType(type_u8,  cast(unsigned)len); break;
+						case 2: padding_type = LLVMArrayType(type_u16, cast(unsigned)len); break;
+						case 4: padding_type = LLVMArrayType(type_u32, cast(unsigned)len); break;
+						case 8: padding_type = LLVMArrayType(type_u64, cast(unsigned)len); break;
+						}
+					} else {
+						padding_type = LLVMArrayType(type_u8, cast(unsigned)padding);
+					}
+				}
+				fields[offset + i*2 + 0] = padding_type;
+				fields[offset + i*2 + 1] = lb_type(m, field->type);
+				if (!type->Struct.is_packed) {
+					padding_offset = align_formula(padding_offset, type_align_of(field->type));
+				}
+				padding_offset += type_size_of(field->type);
+			}
+			
+			i64 end_padding = type_size_of(type)-padding_offset;
+			fields[field_count-1] = LLVMArrayType(type_u8, cast(unsigned)end_padding);
 
 
-			if (type->Struct.custom_align > 0) {
+			if (offset != 0) {
+				GB_ASSERT(offset == 1);
 				fields[0] = lb_alignment_prefix_type_hack(m, type->Struct.custom_align);
 				fields[0] = lb_alignment_prefix_type_hack(m, type->Struct.custom_align);
 			}
 			}
+			for (unsigned i = 0; i < field_count; i++) {
+				GB_ASSERT(fields[i] != nullptr);
+			}
 
 
 			return LLVMStructTypeInContext(ctx, fields, field_count, type->Struct.is_packed);
 			return LLVMStructTypeInContext(ctx, fields, field_count, type->Struct.is_packed);
 		}
 		}
@@ -2230,7 +2270,7 @@ lbValue lb_find_or_add_entity_string(lbModule *m, String const &str) {
 	LLVMValueRef values[2] = {ptr, str_len};
 	LLVMValueRef values[2] = {ptr, str_len};
 
 
 	lbValue res = {};
 	lbValue res = {};
-	res.value = llvm_const_named_struct(lb_type(m, t_string), values, 2);
+	res.value = llvm_const_named_struct(m, t_string, values, 2);
 	res.type = t_string;
 	res.type = t_string;
 	return res;
 	return res;
 }
 }
@@ -2265,7 +2305,7 @@ lbValue lb_find_or_add_entity_string_byte_slice(lbModule *m, String const &str)
 	LLVMValueRef values[2] = {ptr, len};
 	LLVMValueRef values[2] = {ptr, len};
 
 
 	lbValue res = {};
 	lbValue res = {};
-	res.value = llvm_const_named_struct(lb_type(m, t_u8_slice), values, 2);
+	res.value = llvm_const_named_struct(m, t_u8_slice, values, 2);
 	res.type = t_u8_slice;
 	res.type = t_u8_slice;
 	return res;
 	return res;
 }
 }

+ 1 - 2
src/llvm_backend_stmt.cpp

@@ -357,8 +357,7 @@ void lb_build_range_indexed(lbProcedure *p, lbValue expr, Type *val_type, lbValu
 		lbValue entries = lb_map_entries_ptr(p, expr);
 		lbValue entries = lb_map_entries_ptr(p, expr);
 		lbValue elem = lb_emit_struct_ep(p, entries, 0);
 		lbValue elem = lb_emit_struct_ep(p, entries, 0);
 		elem = lb_emit_load(p, elem);
 		elem = lb_emit_load(p, elem);
-
-		lbValue entry = lb_emit_ptr_offset(p, elem, idx);
+		lbValue entry = lb_emit_ptr_offset(p, elem, idx);		
 		idx = lb_emit_load(p, lb_emit_struct_ep(p, entry, 2));
 		idx = lb_emit_load(p, lb_emit_struct_ep(p, entry, 2));
 		val = lb_emit_load(p, lb_emit_struct_ep(p, entry, 3));
 		val = lb_emit_load(p, lb_emit_struct_ep(p, entry, 3));
 
 

+ 62 - 33
src/llvm_backend_type.cpp

@@ -157,12 +157,14 @@ lbValue lb_type_info_member_tags_offset(lbProcedure *p, isize count) {
 void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info data
 void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info data
 	lbModule *m = p->module;
 	lbModule *m = p->module;
 	CheckerInfo *info = m->info;
 	CheckerInfo *info = m->info;
-
+	
+	i64 global_type_info_data_entity_count = 0;
 	{
 	{
 		// NOTE(bill): Set the type_table slice with the global backing array
 		// NOTE(bill): Set the type_table slice with the global backing array
 		lbValue global_type_table = lb_find_runtime_value(m, str_lit("type_table"));
 		lbValue global_type_table = lb_find_runtime_value(m, str_lit("type_table"));
 		Type *type = base_type(lb_global_type_info_data_entity->type);
 		Type *type = base_type(lb_global_type_info_data_entity->type);
 		GB_ASSERT(is_type_array(type));
 		GB_ASSERT(is_type_array(type));
+		global_type_info_data_entity_count = type->Array.count;
 
 
 		LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)};
 		LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)};
 		LLVMValueRef values[2] = {
 		LLVMValueRef values[2] = {
@@ -179,6 +181,11 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
 	Entity *type_info_flags_entity = find_core_entity(info->checker, str_lit("Type_Info_Flags"));
 	Entity *type_info_flags_entity = find_core_entity(info->checker, str_lit("Type_Info_Flags"));
 	Type *t_type_info_flags = type_info_flags_entity->type;
 	Type *t_type_info_flags = type_info_flags_entity->type;
 
 
+	
+	auto entries_handled = slice_make<bool>(heap_allocator(), cast(isize)global_type_info_data_entity_count);
+	defer (gb_free(heap_allocator(), entries_handled.data));
+	entries_handled[0] = true;
+	
 	for_array(type_info_type_index, info->type_info_types) {
 	for_array(type_info_type_index, info->type_info_types) {
 		Type *t = info->type_info_types[type_info_type_index];
 		Type *t = info->type_info_types[type_info_type_index];
 		if (t == nullptr || t == t_invalid) {
 		if (t == nullptr || t == t_invalid) {
@@ -189,19 +196,36 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
 		if (entry_index <= 0) {
 		if (entry_index <= 0) {
 			continue;
 			continue;
 		}
 		}
+		
+		if (entries_handled[entry_index]) {
+			continue;
+		}
+		entries_handled[entry_index] = true;
 
 
+		lbValue global_data_ptr = lb_global_type_info_data_ptr(m);
 		lbValue tag = {};
 		lbValue tag = {};
-		lbValue ti_ptr = lb_emit_array_epi(p, lb_global_type_info_data_ptr(m), cast(i32)entry_index);
+		lbValue ti_ptr = lb_emit_array_epi(p, global_data_ptr, cast(i32)entry_index);
+		
+		i64 size = type_size_of(t);
+		i64 align = type_align_of(t);
+		u32 flags = type_info_flags_of_type(t);
+		lbValue id = lb_typeid(m, t);
+		GB_ASSERT_MSG(align != 0, "%lld %s", align, type_to_string(t));
+		
+		lbValue type_info_flags = lb_const_int(p->module, t_type_info_flags, flags);
+		
+		lbValue size_ptr  = lb_emit_struct_ep(p, ti_ptr, 0);
+		lbValue align_ptr = lb_emit_struct_ep(p, ti_ptr, 1);
+		lbValue flags_ptr = lb_emit_struct_ep(p, ti_ptr, 2);
+		lbValue id_ptr    = lb_emit_struct_ep(p, ti_ptr, 3);
+				
+		lb_emit_store(p, size_ptr,  lb_const_int(m, t_int, size));
+		lb_emit_store(p, align_ptr, lb_const_int(m, t_int, align));
+		lb_emit_store(p, flags_ptr, type_info_flags);
+		lb_emit_store(p, id_ptr,    id);
+		
 		lbValue variant_ptr = lb_emit_struct_ep(p, ti_ptr, 4);
 		lbValue variant_ptr = lb_emit_struct_ep(p, ti_ptr, 4);
 
 
-		lbValue type_info_flags = lb_const_int(p->module, t_type_info_flags, type_info_flags_of_type(t));
-
-		lb_emit_store(p, lb_emit_struct_ep(p, ti_ptr, 0), lb_const_int(m, t_int, type_size_of(t)));
-		lb_emit_store(p, lb_emit_struct_ep(p, ti_ptr, 1), lb_const_int(m, t_int, type_align_of(t)));
-		lb_emit_store(p, lb_emit_struct_ep(p, ti_ptr, 2), type_info_flags);
-		lb_emit_store(p, lb_emit_struct_ep(p, ti_ptr, 3), lb_typeid(m, t));
-
-
 		switch (t->kind) {
 		switch (t->kind) {
 		case Type_Named: {
 		case Type_Named: {
 			tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_named_ptr);
 			tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_named_ptr);
@@ -233,7 +257,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
 
 
 			lbValue res = {};
 			lbValue res = {};
 			res.type = type_deref(tag.type);
 			res.type = type_deref(tag.type);
-			res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals));
+			res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals));
 			lb_emit_store(p, tag, res);
 			lb_emit_store(p, tag, res);
 			break;
 			break;
 		}
 		}
@@ -298,7 +322,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
 
 
 				lbValue res = {};
 				lbValue res = {};
 				res.type = type_deref(tag.type);
 				res.type = type_deref(tag.type);
-				res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals));
+				res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals));
 				lb_emit_store(p, tag, res);
 				lb_emit_store(p, tag, res);
 				break;
 				break;
 			}
 			}
@@ -334,7 +358,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
 
 
 					lbValue res = {};
 					lbValue res = {};
 					res.type = type_deref(tag.type);
 					res.type = type_deref(tag.type);
-					res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals));
+					res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals));
 					lb_emit_store(p, tag, res);
 					lb_emit_store(p, tag, res);
 				}
 				}
 				break;
 				break;
@@ -368,7 +392,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
 
 
 					lbValue res = {};
 					lbValue res = {};
 					res.type = type_deref(tag.type);
 					res.type = type_deref(tag.type);
-					res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals));
+					res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals));
 					lb_emit_store(p, tag, res);
 					lb_emit_store(p, tag, res);
 				}
 				}
 				break;
 				break;
@@ -393,7 +417,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
 
 
 			lbValue res = {};
 			lbValue res = {};
 			res.type = type_deref(tag.type);
 			res.type = type_deref(tag.type);
-			res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals));
+			res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals));
 			lb_emit_store(p, tag, res);
 			lb_emit_store(p, tag, res);
 			break;
 			break;
 		}
 		}
@@ -407,7 +431,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
 
 
 			lbValue res = {};
 			lbValue res = {};
 			res.type = type_deref(tag.type);
 			res.type = type_deref(tag.type);
-			res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals));
+			res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals));
 			lb_emit_store(p, tag, res);
 			lb_emit_store(p, tag, res);
 			break;
 			break;
 		}
 		}
@@ -423,7 +447,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
 
 
 			lbValue res = {};
 			lbValue res = {};
 			res.type = type_deref(tag.type);
 			res.type = type_deref(tag.type);
-			res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals));
+			res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals));
 			lb_emit_store(p, tag, res);
 			lb_emit_store(p, tag, res);
 			break;
 			break;
 		}
 		}
@@ -443,7 +467,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
 
 
 			lbValue res = {};
 			lbValue res = {};
 			res.type = type_deref(tag.type);
 			res.type = type_deref(tag.type);
-			res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals));
+			res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals));
 			lb_emit_store(p, tag, res);
 			lb_emit_store(p, tag, res);
 
 
 			// NOTE(bill): Union assignment
 			// NOTE(bill): Union assignment
@@ -467,7 +491,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
 
 
 			lbValue res = {};
 			lbValue res = {};
 			res.type = type_deref(tag.type);
 			res.type = type_deref(tag.type);
-			res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals));
+			res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals));
 			lb_emit_store(p, tag, res);
 			lb_emit_store(p, tag, res);
 			break;
 			break;
 		}
 		}
@@ -481,7 +505,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
 
 
 			lbValue res = {};
 			lbValue res = {};
 			res.type = type_deref(tag.type);
 			res.type = type_deref(tag.type);
-			res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals));
+			res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals));
 			lb_emit_store(p, tag, res);
 			lb_emit_store(p, tag, res);
 			break;
 			break;
 		}
 		}
@@ -506,7 +530,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
 
 
 			lbValue res = {};
 			lbValue res = {};
 			res.type = type_deref(tag.type);
 			res.type = type_deref(tag.type);
-			res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals));
+			res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals));
 			lb_emit_store(p, tag, res);
 			lb_emit_store(p, tag, res);
 			break;
 			break;
 		}
 		}
@@ -545,7 +569,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
 
 
 			lbValue res = {};
 			lbValue res = {};
 			res.type = type_deref(tag.type);
 			res.type = type_deref(tag.type);
-			res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals));
+			res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals));
 			lb_emit_store(p, tag, res);
 			lb_emit_store(p, tag, res);
 
 
 			break;
 			break;
@@ -596,7 +620,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
 
 
 				lbValue res = {};
 				lbValue res = {};
 				res.type = type_deref(tag.type);
 				res.type = type_deref(tag.type);
-				res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals));
+				res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals));
 				lb_emit_store(p, tag, res);
 				lb_emit_store(p, tag, res);
 			}
 			}
 			break;
 			break;
@@ -650,7 +674,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
 
 
 				lbValue res = {};
 				lbValue res = {};
 				res.type = type_deref(tag.type);
 				res.type = type_deref(tag.type);
-				res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals));
+				res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals));
 				lb_emit_store(p, tag, res);
 				lb_emit_store(p, tag, res);
 			}
 			}
 
 
@@ -688,7 +712,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
 					vals[11] = soa_len.value;
 					vals[11] = soa_len.value;
 				}
 				}
 			}
 			}
-
+			
 			isize count = t->Struct.fields.count;
 			isize count = t->Struct.fields.count;
 			if (count > 0) {
 			if (count > 0) {
 				lbValue memory_types   = lb_type_info_member_types_offset  (p, count);
 				lbValue memory_types   = lb_type_info_member_types_offset  (p, count);
@@ -743,11 +767,10 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
 					vals[i]  = LLVMConstNull(lb_type(m, get_struct_field_type(tag.type, i)));
 					vals[i]  = LLVMConstNull(lb_type(m, get_struct_field_type(tag.type, i)));
 				}
 				}
 			}
 			}
-
-
+			
 			lbValue res = {};
 			lbValue res = {};
 			res.type = type_deref(tag.type);
 			res.type = type_deref(tag.type);
-			res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals));
+			res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals));
 			lb_emit_store(p, tag, res);
 			lb_emit_store(p, tag, res);
 
 
 			break;
 			break;
@@ -767,7 +790,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
 
 
 			lbValue res = {};
 			lbValue res = {};
 			res.type = type_deref(tag.type);
 			res.type = type_deref(tag.type);
-			res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals));
+			res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals));
 			lb_emit_store(p, tag, res);
 			lb_emit_store(p, tag, res);
 			break;
 			break;
 		}
 		}
@@ -791,7 +814,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
 
 
 				lbValue res = {};
 				lbValue res = {};
 				res.type = type_deref(tag.type);
 				res.type = type_deref(tag.type);
-				res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals));
+				res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals));
 				lb_emit_store(p, tag, res);
 				lb_emit_store(p, tag, res);
 			}
 			}
 			break;
 			break;
@@ -808,7 +831,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
 
 
 				lbValue res = {};
 				lbValue res = {};
 				res.type = type_deref(tag.type);
 				res.type = type_deref(tag.type);
-				res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals));
+				res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals));
 				lb_emit_store(p, tag, res);
 				lb_emit_store(p, tag, res);
 			}
 			}
 			break;
 			break;
@@ -823,7 +846,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
 
 
 				lbValue res = {};
 				lbValue res = {};
 				res.type = type_deref(tag.type);
 				res.type = type_deref(tag.type);
-				res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals));
+				res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals));
 				lb_emit_store(p, tag, res);
 				lb_emit_store(p, tag, res);
 			}
 			}
 			break;
 			break;
@@ -837,7 +860,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
 
 
 				lbValue res = {};
 				lbValue res = {};
 				res.type = type_deref(tag.type);
 				res.type = type_deref(tag.type);
-				res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals));
+				res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals));
 				lb_emit_store(p, tag, res);
 				lb_emit_store(p, tag, res);
 			}
 			}
 			break;
 			break;
@@ -856,4 +879,10 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
 			}
 			}
 		}
 		}
 	}
 	}
+	
+	for_array(i, entries_handled) {
+		if (!entries_handled[i]) {
+			GB_PANIC("UNHANDLED ENTRY %td (%td)", i, entries_handled.count);
+		}
+	}
 }
 }

+ 49 - 6
src/llvm_backend_utility.cpp

@@ -807,13 +807,47 @@ lbValue lb_address_from_load(lbProcedure *p, lbValue value) {
 	return {};
 	return {};
 }
 }
 
 
-i32 lb_convert_struct_index(Type *t, i32 index) {
-	if (t->kind == Type_Struct && t->Struct.custom_align != 0) {
-		index += 1;
+bool lb_struct_has_padding_prefix(Type *t) {
+	Type *bt = base_type(t);
+	GB_ASSERT(bt->kind == Type_Struct);
+	return bt->Struct.custom_align != 0 && bt->Struct.fields.count == 0;
+}
+
+i32 lb_convert_struct_index(lbModule *m, Type *t, i32 index) {
+	if (t->kind == Type_Struct) {
+		index = index*2 + 1;
+		if (lb_struct_has_padding_prefix(t)) {
+			index += 1;
+		}
+		
+		unsigned count = LLVMCountStructElementTypes(lb_type(m, t));
+		GB_ASSERT(count >= cast(unsigned)index);
 	}
 	}
 	return index;
 	return index;
 }
 }
 
 
+char const *llvm_type_kinds[] = {
+	"LLVMVoidTypeKind",
+	"LLVMHalfTypeKind",
+	"LLVMFloatTypeKind",
+	"LLVMDoubleTypeKind",
+	"LLVMX86_FP80TypeKind",
+	"LLVMFP128TypeKind",
+	"LLVMPPC_FP128TypeKind",
+	"LLVMLabelTypeKind",
+	"LLVMIntegerTypeKind",
+	"LLVMFunctionTypeKind",
+	"LLVMStructTypeKind",
+	"LLVMArrayTypeKind",
+	"LLVMPointerTypeKind",
+	"LLVMVectorTypeKind",
+	"LLVMMetadataTypeKind",
+	"LLVMX86_MMXTypeKind",
+	"LLVMTokenTypeKind",
+	"LLVMScalableVectorTypeKind",
+	"LLVMBFloatTypeKind",
+};
+
 lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) {
 lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) {
 	GB_ASSERT(is_type_pointer(s.type));
 	GB_ASSERT(is_type_pointer(s.type));
 	Type *t = base_type(type_deref(s.type));
 	Type *t = base_type(type_deref(s.type));
@@ -878,6 +912,7 @@ lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) {
 		case 0: result_type = get_struct_field_type(gst, 0); break;
 		case 0: result_type = get_struct_field_type(gst, 0); break;
 		case 1: result_type = get_struct_field_type(gst, 1); break;
 		case 1: result_type = get_struct_field_type(gst, 1); break;
 		}
 		}
+		index = index*2 + 1;
 	} else if (is_type_array(t)) {
 	} else if (is_type_array(t)) {
 		return lb_emit_array_epi(p, s, index);
 		return lb_emit_array_epi(p, s, index);
 	} else if (is_type_relative_slice(t)) {
 	} else if (is_type_relative_slice(t)) {
@@ -891,7 +926,7 @@ lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) {
 
 
 	GB_ASSERT_MSG(result_type != nullptr, "%s %d", type_to_string(t), index);
 	GB_ASSERT_MSG(result_type != nullptr, "%s %d", type_to_string(t), index);
 	
 	
-	index = lb_convert_struct_index(t, index);
+	index = lb_convert_struct_index(p->module, t, index);
 	
 	
 	if (lb_is_const(s)) {
 	if (lb_is_const(s)) {
 		lbModule *m = p->module;
 		lbModule *m = p->module;
@@ -902,6 +937,14 @@ lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) {
 		return res;
 		return res;
 	} else {
 	} else {
 		lbValue res = {};
 		lbValue res = {};
+		LLVMTypeRef st = LLVMGetElementType(LLVMTypeOf(s.value));
+		// gb_printf_err("%s\n", type_to_string(s.type));
+		// gb_printf_err("%s\n", LLVMPrintTypeToString(LLVMTypeOf(s.value)));
+		// gb_printf_err("%d\n", index);
+		GB_ASSERT_MSG(LLVMGetTypeKind(st) == LLVMStructTypeKind, "%s", llvm_type_kinds[LLVMGetTypeKind(st)]);
+		unsigned count = LLVMCountStructElementTypes(st);
+		GB_ASSERT(count >= cast(unsigned)index);
+		
 		res.value = LLVMBuildStructGEP(p->builder, s.value, cast(unsigned)index, "");
 		res.value = LLVMBuildStructGEP(p->builder, s.value, cast(unsigned)index, "");
 		res.type = alloc_type_pointer(result_type);
 		res.type = alloc_type_pointer(result_type);
 		return res;
 		return res;
@@ -1013,7 +1056,7 @@ lbValue lb_emit_struct_ev(lbProcedure *p, lbValue s, i32 index) {
 
 
 	GB_ASSERT_MSG(result_type != nullptr, "%s, %d", type_to_string(s.type), index);
 	GB_ASSERT_MSG(result_type != nullptr, "%s, %d", type_to_string(s.type), index);
 	
 	
-	index = lb_convert_struct_index(t, index);
+	index = lb_convert_struct_index(p->module, t, index);
 
 
 	lbValue res = {};
 	lbValue res = {};
 	res.value = LLVMBuildExtractValue(p->builder, s.value, cast(unsigned)index, "");
 	res.value = LLVMBuildExtractValue(p->builder, s.value, cast(unsigned)index, "");
@@ -1232,7 +1275,7 @@ lbValue lb_map_entries_ptr(lbProcedure *p, lbValue value) {
 	GB_ASSERT_MSG(t->kind == Type_Map, "%s", type_to_string(t));
 	GB_ASSERT_MSG(t->kind == Type_Map, "%s", type_to_string(t));
 	init_map_internal_types(t);
 	init_map_internal_types(t);
 	i32 index = 1;
 	i32 index = 1;
-	lbValue entries = lb_emit_struct_ep(p, value, index);
+	lbValue entries = lb_emit_struct_ep(p, value, index);	
 	return entries;
 	return entries;
 }
 }