فهرست منبع

Start work on very basic LLVM debug type information

gingerBill 4 سال پیش
والد
کامیت
0355908af8
2فایلهای تغییر یافته به همراه310 افزوده شده و 31 حذف شده
  1. 292 31
      src/llvm_backend.cpp
  2. 18 0
      src/llvm_backend.hpp

+ 292 - 31
src/llvm_backend.cpp

@@ -1485,6 +1485,10 @@ LLVMMetadataRef lb_debug_location_from_token_pos(lbProcedure *p, TokenPos pos) {
 	GB_ASSERT_MSG(scope != nullptr, "%.*s", LIT(p->name));
 	return LLVMDIBuilderCreateDebugLocation(p->module->ctx, cast(unsigned)pos.line, cast(unsigned)pos.column, scope, nullptr);
 }
+LLVMMetadataRef lb_debug_location_from_ast(lbProcedure *p, Ast *node) {
+	GB_ASSERT(node != nullptr);
+	return lb_debug_location_from_token_pos(p, ast_token(node).pos);
+}
 
 LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
 	Type *original_type = type;
@@ -1620,15 +1624,17 @@ LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
 		case Basic_f64be: return LLVMDIBuilderCreateBasicType(m->debug_builder,  "f64be",  5,  64, LLVMDWARFTypeEncoding_Float, LLVMDIFlagLittleEndian);
 
 		// Untyped types
-		case Basic_UntypedBool:       GB_PANIC("Basic_UntypedBool"); break;
-		case Basic_UntypedInteger:    GB_PANIC("Basic_UntypedInteger"); break;
-		case Basic_UntypedFloat:      GB_PANIC("Basic_UntypedFloat"); break;
-		case Basic_UntypedComplex:    GB_PANIC("Basic_UntypedComplex"); break;
+		case Basic_UntypedBool:       GB_PANIC("Basic_UntypedBool");       break;
+		case Basic_UntypedInteger:    GB_PANIC("Basic_UntypedInteger");    break;
+		case Basic_UntypedFloat:      GB_PANIC("Basic_UntypedFloat");      break;
+		case Basic_UntypedComplex:    GB_PANIC("Basic_UntypedComplex");    break;
 		case Basic_UntypedQuaternion: GB_PANIC("Basic_UntypedQuaternion"); break;
-		case Basic_UntypedString:     GB_PANIC("Basic_UntypedString"); break;
-		case Basic_UntypedRune:       GB_PANIC("Basic_UntypedRune"); break;
-		case Basic_UntypedNil:        GB_PANIC("Basic_UntypedNil"); break;
-		case Basic_UntypedUndef:      GB_PANIC("Basic_UntypedUndef"); break;
+		case Basic_UntypedString:     GB_PANIC("Basic_UntypedString");     break;
+		case Basic_UntypedRune:       GB_PANIC("Basic_UntypedRune");       break;
+		case Basic_UntypedNil:        GB_PANIC("Basic_UntypedNil");        break;
+		case Basic_UntypedUndef:      GB_PANIC("Basic_UntypedUndef");      break;
+
+		default: GB_PANIC("Basic Unhandled"); break;
 		}
 		break;
 
@@ -1908,6 +1914,7 @@ LLVMMetadataRef lb_debug_type(lbModule *m, Type *type) {
 			if (scope != nullptr) {
 				file = LLVMDIScopeGetFile(scope);
 			}
+			line = cast(unsigned)e->token.pos.line;
 		}
 		// TODO(bill): location data for Type_Named
 
@@ -1916,29 +1923,51 @@ LLVMMetadataRef lb_debug_type(lbModule *m, Type *type) {
 		String name = type->Named.name;
 		char const *name_text = cast(char const *)name.text;
 		size_t name_len = cast(size_t)name.len;
-		unsigned tag = 0;
+		unsigned tag = DW_TAG_structure_type;
+		if (is_type_raw_union(type) || is_type_union(type)) {
+			tag = DW_TAG_union_type;
+		}
 		LLVMDIFlags flags = LLVMDIFlagZero;
 
 		Type *bt = base_type(type->Named.base);
 
-		if (is_type_struct(type) || is_type_union(type)) {
-			LLVMMetadataRef temp_forward_decl = LLVMDIBuilderCreateReplaceableCompositeType(m->debug_builder, tag, name_text, name_len, scope, file, line, 0, size_in_bits, align_in_bits, flags, "", 0);
-			lb_set_llvm_metadata(m, type, temp_forward_decl);
+		lbIncompleteDebugType idt = {};
+		idt.type = type;
 
-			LLVMMetadataRef debug_bt = lb_debug_type(m, bt);
+		switch (bt->kind) {
+		case Type_Basic:
+		case Type_Pointer:
+		case Type_Array:
+		case Type_EnumeratedArray:
+		case Type_Enum:
+		case Type_Tuple:
+		case Type_Proc:
+		case Type_BitSet:
+		case Type_SimdVector:
+		case Type_RelativePointer:
+		case Type_RelativeSlice:
 
-			LLVMMetadataRef final_decl = LLVMDIBuilderCreateTypedef(m->debug_builder, debug_bt, name_text, name_len, file, line, scope, align_in_bits);
+		case Type_Map: // TODO(bill): Is this okay?
+			{
+				LLVMMetadataRef debug_bt = lb_debug_type(m, bt);
+				LLVMMetadataRef final_decl = LLVMDIBuilderCreateTypedef(m->debug_builder, debug_bt, name_text, name_len, file, line, scope, align_in_bits);
+				lb_set_llvm_metadata(m, type, final_decl);
+				return final_decl;
+			}
 
-			LLVMMetadataReplaceAllUsesWith(temp_forward_decl, final_decl);
-			lb_set_llvm_metadata(m, type, final_decl);
-			return final_decl;
-		} else {
-			LLVMMetadataRef debug_bt = lb_debug_type(m, bt);
-			LLVMMetadataRef final_decl = LLVMDIBuilderCreateTypedef(m->debug_builder, debug_bt, name_text, name_len, file, line, scope, align_in_bits);
-			lb_set_llvm_metadata(m, type, final_decl);
-			return final_decl;
-		}
+		case Type_Slice:
+		case Type_DynamicArray:
+		case Type_Struct:
+		case Type_Union:
+			LLVMMetadataRef temp_forward_decl = LLVMDIBuilderCreateReplaceableCompositeType(
+				m->debug_builder, tag, name_text, name_len, nullptr, nullptr, 0, 0, size_in_bits, align_in_bits, flags, "", 0
+			);
+			idt.metadata = temp_forward_decl;
 
+			array_add(&m->debug_incomplete_types, idt);
+			lb_set_llvm_metadata(m, type, temp_forward_decl);
+			return temp_forward_decl;
+		}
 	}
 
 
@@ -1947,6 +1976,189 @@ LLVMMetadataRef lb_debug_type(lbModule *m, Type *type) {
 	return dt;
 }
 
+void lb_debug_complete_types(lbModule *m) {
+	unsigned const word_size = cast(unsigned)build_context.word_size;
+	unsigned const word_bits = cast(unsigned)(8*build_context.word_size);
+
+	for_array(debug_incomplete_type_index, m->debug_incomplete_types) {
+		auto const &idt = m->debug_incomplete_types[debug_incomplete_type_index];
+		GB_ASSERT(idt.type != nullptr);
+		GB_ASSERT(idt.metadata != nullptr);
+
+		Type *t = idt.type;
+		Type *bt = base_type(t);
+
+		LLVMMetadataRef parent_scope = nullptr;
+		LLVMMetadataRef file = nullptr;
+		unsigned line_number = 0;
+		u64 size_in_bits  = 8*type_size_of(t);
+		u32 align_in_bits = cast(u32)(8*type_align_of(t));
+		LLVMDIFlags flags = LLVMDIFlagZero;
+
+		LLVMMetadataRef derived_from = nullptr;
+
+		LLVMMetadataRef *elements = nullptr;
+		unsigned element_count = 0;
+
+
+		unsigned runtime_lang = 0; // Objective-C runtime version
+		char const *unique_id = "";
+		LLVMMetadataRef vtable_holder = nullptr;
+		size_t unique_id_len = 0;
+
+
+		LLVMMetadataRef record_scope = nullptr;
+
+		switch (bt->kind) {
+		case Type_Slice:
+		case Type_DynamicArray:
+		case Type_Map:
+		case Type_Struct:
+		case Type_Union: {
+			bool is_union = is_type_raw_union(bt) || is_type_union(bt);
+
+			String name = str_lit("<anonymous-struct>");
+			if (t->kind == Type_Named) {
+				name = t->Named.name;
+
+				LLVMMetadataRef file = nullptr;
+				unsigned line = 0;
+				LLVMMetadataRef file_scope = nullptr;
+
+				if (t->Named.type_name != nullptr) {
+					Entity *e = t->Named.type_name;
+					file_scope = lb_get_llvm_metadata(m, e->scope);
+					if (file_scope != nullptr) {
+						file = LLVMDIScopeGetFile(file_scope);
+					}
+					line = cast(unsigned)e->token.pos.line;
+				}
+				// TODO(bill): location data for Type_Named
+
+			} else {
+				switch (bt->kind) {
+				case Type_Slice:        name = str_lit("<anonymous-slice>");          break;
+				case Type_DynamicArray: name = str_lit("<anonymous-dynamic-array>");  break;
+				case Type_Map:          name = str_lit("<anonymous-map>");            break;
+				case Type_Struct:       name = str_lit("<anonymous-struct>");         break;
+				case Type_Union:        name = str_lit("<anonymous-union>");          break;
+				}
+			}
+
+			switch (bt->kind) {
+			case Type_Slice:
+				element_count = 2;
+				elements = gb_alloc_array(temporary_allocator(), LLVMMetadataRef, element_count);
+				elements[0] = LLVMDIBuilderCreatePointerType(m->debug_builder, lb_debug_type(m, bt->Slice.elem), word_bits, word_bits, 0, nullptr, 0);
+				elements[1] = lb_debug_type(m, t_int);
+				break;
+			case Type_DynamicArray:
+				element_count = 4;
+				elements = gb_alloc_array(temporary_allocator(), LLVMMetadataRef, element_count);
+				elements[0] = LLVMDIBuilderCreatePointerType(m->debug_builder, lb_debug_type(m, bt->DynamicArray.elem), word_bits, word_bits, 0, nullptr, 0);
+				elements[1] = lb_debug_type(m, t_int);
+				elements[2] = lb_debug_type(m, t_int);
+				elements[3] = lb_debug_type(m, t_allocator);
+				break;
+			case Type_Map:
+				break;
+			case Type_Struct:
+				type_set_offsets(bt);
+
+				/*
+				record_scope = lb_get_llvm_metadata(m, bt->Struct.scope);
+				element_count = cast(unsigned)bt->Struct.fields.count;
+				elements = gb_alloc_array(temporary_allocator(), LLVMMetadataRef, element_count);
+				for_array(j, bt->Struct.fields) {
+					Entity *f = bt->Struct.fields[j];
+					String fname = f->token.string;
+
+					unsigned field_line = 0;
+					LLVMDIFlags field_flags = LLVMDIFlagZero;
+					u64 offset_in_bits = 8*cast(u64)bt->Struct.offsets[j];
+
+					elements[j] = LLVMDIBuilderCreateMemberType(
+						m->debug_builder, record_scope,
+						cast(char const *)fname.text, cast(size_t)fname.len,
+						file, field_line,
+						8*cast(u64)type_size_of(f->type), 8*cast(u32)type_align_of(f->type),
+						offset_in_bits,
+						field_flags, lb_debug_type(m, f->type)
+					);
+				}
+				*/
+				break;
+			case Type_Union:
+				/*
+				record_scope = lb_get_llvm_metadata(m, bt->Union.scope);
+				element_count = cast(unsigned)bt->Union.variants.count;
+				elements = gb_alloc_array(temporary_allocator(), LLVMMetadataRef, element_count);
+				for_array(j, bt->Union.variants) {
+					Type *variant = bt->Union.variants[j];
+
+					char name[16] = {};
+					gb_snprintf(name, gb_size_of(name), "v%u", cast(unsigned)j);
+					isize name_len = gb_strlen(name);
+
+					unsigned field_line = 0;
+					LLVMDIFlags field_flags = LLVMDIFlagZero;
+					u64 offset_in_bits = 0;
+
+					elements[j] = LLVMDIBuilderCreateMemberType(
+						m->debug_builder, record_scope,
+						name, name_len,
+						file, field_line,
+						8*cast(u64)type_size_of(variant), 8*cast(u32)type_align_of(variant),
+						offset_in_bits,
+						field_flags, lb_debug_type(m, variant)
+					);
+				}
+				*/
+				break;
+			}
+
+
+			LLVMMetadataRef final_metadata = nullptr;
+			if (is_union) {
+				final_metadata = LLVMDIBuilderCreateUnionType(
+					m->debug_builder,
+					parent_scope,
+					cast(char const *)name.text, cast(size_t)name.len,
+					file, line_number,
+					size_in_bits, align_in_bits,
+					flags,
+					elements, element_count,
+					runtime_lang,
+					unique_id, unique_id_len
+				);
+			} else {
+				final_metadata = LLVMDIBuilderCreateStructType(
+					m->debug_builder,
+					parent_scope,
+					cast(char const *)name.text, cast(size_t)name.len,
+					file, line_number,
+					size_in_bits, align_in_bits,
+					flags,
+					derived_from,
+					elements, element_count,
+					runtime_lang,
+					vtable_holder,
+					unique_id, unique_id_len
+				);
+			}
+
+			LLVMMetadataReplaceAllUsesWith(idt.metadata, final_metadata);
+			lb_set_llvm_metadata(m, idt.type, final_metadata);
+		} break;
+		default:
+			GB_PANIC("invalid incomplete debug type");
+			break;
+		}
+	}
+	array_clear(&m->debug_incomplete_types);
+}
+
+
 void lb_add_entity(lbModule *m, Entity *e, lbValue val) {
 	if (e != nullptr) {
 		map_set(&m->values, hash_entity(e), val);
@@ -2256,7 +2468,7 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity) {
 			is_optimized = false;
 		}
 
-		{
+		if (p->body != nullptr) {
 			p->debug_info = LLVMDIBuilderCreateFunction(m->debug_builder, scope,
 				cast(char const *)entity->token.string.text, entity->token.string.len,
 				cast(char const *)p->name.text, p->name.len,
@@ -2665,6 +2877,21 @@ void lb_begin_procedure_body(lbProcedure *p) {
 	}
 
 	lb_start_block(p, p->entry_block);
+
+	if (p->debug_info != nullptr) {
+		TokenPos pos = {};
+		if (p->body != nullptr) {
+			pos = ast_token(p->body).pos;
+		} else if (p->type_expr != nullptr) {
+			pos = ast_token(p->type_expr).pos;
+		} else if (p->entity != nullptr) {
+			pos = p->entity->token.pos;
+		}
+		if (pos.file_id != 0) {
+			LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_token_pos(p, pos));
+		}
+	}
+
 }
 
 void lb_end_procedure_body(lbProcedure *p) {
@@ -4117,6 +4344,15 @@ void lb_build_stmt(lbProcedure *p, Ast *node) {
 		}
 	}
 
+	LLVMMetadataRef prev_debug_location = nullptr;
+	if (p->debug_info != nullptr) {
+		prev_debug_location = LLVMGetCurrentDebugLocation2(p->builder);
+		LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_ast(p, node));
+	}
+	defer (if (prev_debug_location != nullptr) {
+		LLVMSetCurrentDebugLocation2(p->builder, prev_debug_location);
+	});
+
 	u64 prev_state_flags = p->module->state_flags;
 	defer (p->module->state_flags = prev_state_flags);
 
@@ -9808,7 +10044,16 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
 		return lb_const_value(p->module, tv.type, tv.value);
 	}
 
-
+	#if 0
+	LLVMMetadataRef prev_debug_location = nullptr;
+	if (p->debug_info != nullptr) {
+		prev_debug_location = LLVMGetCurrentDebugLocation2(p->builder);
+		LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_ast(p, expr));
+	}
+	defer (if (prev_debug_location != nullptr) {
+		LLVMSetCurrentDebugLocation2(p->builder, prev_debug_location);
+	});
+	#endif
 
 	switch (expr->kind) {
 	case_ast_node(bl, BasicLit, expr);
@@ -11545,8 +11790,19 @@ void lb_init_module(lbModule *m, Checker *c) {
 
 	m->ctx = LLVMGetGlobalContext();
 	m->mod = LLVMModuleCreateWithNameInContext("odin_module", m->ctx);
-	m->debug_builder = nullptr;
-	// m->debug_builder = build_context.ODIN_DEBUG ? LLVMCreateDIBuilder(m->mod) : nullptr;
+	// m->debug_builder = nullptr;
+	if (build_context.ODIN_DEBUG) {
+		enum {DEBUG_METADATA_VERSION = 3};
+
+		LLVMMetadataRef debug_ref = LLVMValueAsMetadata(LLVMConstInt(LLVMInt32TypeInContext(m->ctx), DEBUG_METADATA_VERSION, true));
+		LLVMAddModuleFlag(m->mod, LLVMModuleFlagBehaviorWarning, "Debug Info Version", 18, debug_ref);
+
+		if (build_context.metrics.os == TargetOs_windows) {
+			LLVMMetadataRef ref = LLVMValueAsMetadata(LLVMConstInt(LLVMInt32TypeInContext(m->ctx), 1, true));
+			LLVMAddModuleFlag(m->mod, LLVMModuleFlagBehaviorWarning, "CodeView", 8, ref);
+			m->debug_builder = LLVMCreateDIBuilder(m->mod);
+		}
+	}
 
 	m->state_flags = 0;
 	m->state_flags |= StateFlag_bounds_check;
@@ -11564,10 +11820,11 @@ void lb_init_module(lbModule *m, Checker *c) {
 	map_init(&m->function_type_map, a);
 	map_init(&m->equal_procs, a);
 	map_init(&m->hasher_procs, a);
-	array_init(&m->procedures_to_generate, a);
-	array_init(&m->foreign_library_paths, a);
+	array_init(&m->procedures_to_generate, a, 0, 1024);
+	array_init(&m->foreign_library_paths,  a, 0, 1024);
 
 	map_init(&m->debug_values, a);
+	array_init(&m->debug_incomplete_types, a, 0, 1024);
 
 }
 
@@ -12528,14 +12785,15 @@ void lb_generate_code(lbGenerator *gen) {
 		}
 
 		LLVMBool split_debug_inlining = false;
-		LLVMBool debug_info_for_profiling = true;
+		LLVMBool debug_info_for_profiling = false;
 
 		m->debug_compile_unit = LLVMDIBuilderCreateCompileUnit(m->debug_builder, LLVMDWARFSourceLanguageC99,
 			lb_get_llvm_metadata(m, init_file),
 			producer, gb_string_length(producer),
 			is_optimized, "", 0,
 			1, split_name, gb_string_length(split_name),
-			LLVMDWARFEmissionFull, 0, split_debug_inlining,
+			LLVMDWARFEmissionFull,
+			0, split_debug_inlining,
 			debug_info_for_profiling,
 			"", 0, // sys_root
 			"", 0  // SDK
@@ -13183,6 +13441,9 @@ void lb_generate_code(lbGenerator *gen) {
 
 
 	if (m->debug_builder != nullptr) {
+		TIME_SECTION("LLVM Debug Info Complete Types");
+		lb_debug_complete_types(m);
+
 		TIME_SECTION("LLVM Debug Info Builder Finalize");
 		LLVMDIBuilderFinalize(m->debug_builder);
 	}

+ 18 - 0
src/llvm_backend.hpp

@@ -78,6 +78,11 @@ struct lbAddr {
 	};
 };
 
+struct lbIncompleteDebugType {
+	Type *type;
+	LLVMMetadataRef metadata;
+};
+
 struct lbModule {
 	LLVMModuleRef mod;
 	LLVMContextRef ctx;
@@ -117,6 +122,8 @@ struct lbModule {
 	LLVMDIBuilderRef debug_builder;
 	LLVMMetadataRef debug_compile_unit;
 	Map<LLVMMetadataRef> debug_values; // Key: Pointer
+
+	Array<lbIncompleteDebugType> debug_incomplete_types;
 };
 
 struct lbGenerator {
@@ -480,3 +487,14 @@ enum : LLVMDWARFTypeEncoding {
 	LLVMDWARFTypeEncoding_LoUser = 128,
 	LLVMDWARFTypeEncoding_HiUser = 255
 };
+
+
+enum {
+	DW_TAG_array_type       = 1,
+	DW_TAG_enumeration_type = 4,
+	DW_TAG_structure_type   = 19,
+	DW_TAG_union_type       = 23,
+	DW_TAG_vector_type      = 259,
+	DW_TAG_subroutine_type  = 21,
+	DW_TAG_inheritance      = 28,
+};