mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
210 lines
8.2 KiB
C
210 lines
8.2 KiB
C
// Copyright (c) 2019 Christoffer Lerno. All rights reserved.
|
|
// Use of this source code is governed by the GNU LGPLv3.0 license
|
|
// a copy of which can be found in the LICENSE file.
|
|
|
|
#include "llvm_codegen_internal.h"
|
|
|
|
|
|
|
|
static inline LLVMTypeRef create_introspection_type(GenContext *c)
|
|
{
|
|
LLVMTypeRef type = LLVMStructCreateNamed(c->context, ".introspect");
|
|
LLVMTypeRef typeid_type = llvm_get_type(c, type_typeid);
|
|
LLVMTypeRef kind_type = llvm_get_type(c, type_char);
|
|
LLVMTypeRef usize_type = llvm_get_type(c, type_usize);
|
|
LLVMTypeRef introspect_type[INTROSPECT_INDEX_TOTAL] = {
|
|
[INTROSPECT_INDEX_KIND] = kind_type,
|
|
[INTROSPECT_INDEX_SIZEOF] = usize_type,
|
|
[INTROSPECT_INDEX_INNER] = typeid_type,
|
|
[INTROSPECT_INDEX_LEN] = usize_type,
|
|
[INTROSPECT_INDEX_ADDITIONAL] = LLVMArrayType(typeid_type, 0),
|
|
};
|
|
LLVMStructSetBody(type, introspect_type, INTROSPECT_INDEX_TOTAL, false);
|
|
return type;
|
|
}
|
|
|
|
static inline LLVMTypeRef create_fault_type(GenContext *c)
|
|
{
|
|
LLVMTypeRef type = LLVMStructCreateNamed(c->context, ".fault");
|
|
LLVMTypeRef typeid_type = llvm_get_type(c, type_typeid);
|
|
LLVMTypeRef chars_type = llvm_get_type(c, type_chars);
|
|
LLVMTypeRef fault_type[] = {
|
|
[0] = typeid_type,
|
|
[1] = chars_type,
|
|
};
|
|
LLVMStructSetBody(type, fault_type, 2, false);
|
|
return type;
|
|
}
|
|
|
|
void gencontext_begin_module(GenContext *c)
|
|
{
|
|
assert(!c->module && "Expected no module");
|
|
|
|
const char *result = module_create_object_file_name(c->code_module);
|
|
c->ir_filename = str_printf("%s.ll", result);
|
|
if (active_target.llvm_file_dir) c->ir_filename = file_append_path(active_target.llvm_file_dir, c->ir_filename);
|
|
c->object_filename = str_printf("%s%s", result, get_object_extension());
|
|
if (active_target.emit_asm)
|
|
{
|
|
c->asm_filename = str_printf("%s.s", result);
|
|
if (active_target.asm_file_dir) c->asm_filename = file_append_path(active_target.asm_file_dir, c->asm_filename);
|
|
}
|
|
if (active_target.object_file_dir) c->object_filename = file_append_path(active_target.object_file_dir, c->object_filename);
|
|
c->panicfn = global_context.panic_fn;
|
|
c->module = LLVMModuleCreateWithNameInContext(c->code_module->name->module, c->context);
|
|
c->machine = llvm_target_machine_create();
|
|
c->target_data = LLVMCreateTargetDataLayout(c->machine);
|
|
LLVMSetModuleDataLayout(c->module, c->target_data);
|
|
LLVMSetSourceFileName(c->module, c->code_module->name->module, strlen(c->code_module->name->module));
|
|
LLVMTypeRef options_type = LLVMInt8TypeInContext(c->context);
|
|
|
|
static const char *pic_level = "PIC Level";
|
|
static const char *pie_level = "PIE Level";
|
|
LLVMMetadataRef setting;
|
|
switch (active_target.reloc_model)
|
|
{
|
|
case RELOC_BIG_PIE:
|
|
setting = LLVMValueAsMetadata(LLVMConstInt(options_type, (unsigned)2 /* PIE */, false));
|
|
LLVMAddModuleFlag(c->module, LLVMModuleFlagBehaviorOverride, pie_level, strlen(pie_level), setting);
|
|
FALLTHROUGH;
|
|
case RELOC_BIG_PIC:
|
|
setting = LLVMValueAsMetadata(LLVMConstInt(options_type, (unsigned)2 /* PIC */, false));
|
|
LLVMAddModuleFlag(c->module, LLVMModuleFlagBehaviorOverride, pic_level, strlen(pic_level), setting);
|
|
break;
|
|
case RELOC_SMALL_PIE:
|
|
setting = LLVMValueAsMetadata(LLVMConstInt(options_type, (unsigned)1 /* pie */, false));
|
|
LLVMAddModuleFlag(c->module, LLVMModuleFlagBehaviorOverride, pie_level, strlen(pie_level), setting);
|
|
FALLTHROUGH;
|
|
case RELOC_SMALL_PIC:
|
|
setting = LLVMValueAsMetadata(LLVMConstInt(options_type, (unsigned)1 /* pic */, false));
|
|
LLVMAddModuleFlag(c->module, LLVMModuleFlagBehaviorOverride, pic_level, strlen(pic_level), setting);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
LLVMSetTarget(c->module, platform_target.target_triple);
|
|
|
|
// Setup all types. Not thread-safe, but at this point in time we can assume a single context.
|
|
// We need to remove the context from the cache after this.
|
|
// This would seem to indicate that we should change Type / actual type.
|
|
|
|
c->block_global_unique_count = 0;
|
|
c->ast_alloca_addr_space = target_alloca_addr_space();
|
|
VECEACH(global_context.type, i)
|
|
{
|
|
Type *type = global_context.type[i];
|
|
type->backend_type = NULL;
|
|
type->backend_debug_type = NULL;
|
|
type->backend_typeid = NULL;
|
|
switch (type->type_kind)
|
|
{
|
|
case TYPE_ENUM:
|
|
case TYPE_FAULTTYPE:
|
|
{
|
|
Decl **values = type->decl->enums.values;
|
|
VECEACH(values, j)
|
|
{
|
|
values[j]->backend_ref = NULL;
|
|
}
|
|
FALLTHROUGH;
|
|
}
|
|
case TYPE_STRUCT:
|
|
case TYPE_UNION:
|
|
case TYPE_DISTINCT:
|
|
type->decl->backend_ref = NULL;
|
|
break;
|
|
case TYPE_FUNC:
|
|
// TODO
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
c->bool_type = LLVMInt1TypeInContext(c->context);
|
|
c->byte_type = LLVMInt8TypeInContext(c->context);
|
|
c->introspect_type = create_introspection_type(c);
|
|
c->fault_type = create_fault_type(c);
|
|
c->size_type = llvm_get_type(c, type_usize);
|
|
if (c->panicfn) c->panicfn->backend_ref = NULL;
|
|
|
|
if (active_target.debug_info != DEBUG_INFO_NONE)
|
|
{
|
|
c->debug.runtime_version = 1;
|
|
c->debug.builder = LLVMCreateDIBuilder(c->module);
|
|
if (active_target.debug_info == DEBUG_INFO_FULL && active_target.feature.safe_mode)
|
|
{
|
|
c->debug.stack_type = LLVMStructCreateNamed(c->context, ".$callstack");
|
|
LLVMTypeRef types[4] = { LLVMPointerType(c->debug.stack_type, 0),
|
|
LLVMPointerType(c->byte_type, 0),
|
|
LLVMPointerType(c->byte_type, 0),
|
|
llvm_get_type(c, type_uint) };
|
|
LLVMStructSetBody(c->debug.stack_type, types, 4, false);
|
|
c->debug.last_ptr = NULL;
|
|
c->debug.enable_stacktrace = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
void gencontext_init_file_emit(GenContext *c, CompilationUnit *unit)
|
|
{
|
|
if (active_target.debug_info != DEBUG_INFO_NONE)
|
|
{
|
|
const char *filename = unit->file->name;
|
|
const char *dir_path = unit->file->dir_path;
|
|
// Set runtime version here.
|
|
unit->llvm.debug_file = LLVMDIBuilderCreateFile(c->debug.builder,
|
|
filename,
|
|
strlen(filename),
|
|
dir_path,
|
|
strlen(dir_path));
|
|
|
|
bool is_optimized = active_target.optimization_level != OPTIMIZATION_NONE;
|
|
const char *dwarf_flags = "";
|
|
unsigned runtime_version = 1;
|
|
LLVMDWARFEmissionKind emission_kind =
|
|
active_target.debug_info == DEBUG_INFO_FULL ? LLVMDWARFEmissionFull : LLVMDWARFEmissionLineTablesOnly;
|
|
const char *debug_output_file = "";
|
|
bool emit_debug_info_for_profiling = false;
|
|
bool split_debug_inlining = false;
|
|
const char *sysroot = "";
|
|
const char *sdk = "";
|
|
unsigned dwo_id = 0;
|
|
if (c->debug.compile_unit)
|
|
{
|
|
unit->llvm.debug_compile_unit = c->debug.compile_unit;
|
|
return;
|
|
}
|
|
unit->llvm.debug_compile_unit = LLVMDIBuilderCreateCompileUnit(c->debug.builder,
|
|
LLVMDWARFSourceLanguageC,
|
|
unit->llvm.debug_file,
|
|
DWARF_PRODUCER_NAME,
|
|
strlen(DWARF_PRODUCER_NAME),
|
|
is_optimized,
|
|
dwarf_flags,
|
|
strlen(dwarf_flags),
|
|
runtime_version,
|
|
debug_output_file,
|
|
strlen(debug_output_file),
|
|
emission_kind,
|
|
dwo_id,
|
|
split_debug_inlining,
|
|
emit_debug_info_for_profiling,
|
|
sysroot,
|
|
strlen(sysroot),
|
|
sdk,
|
|
strlen(sdk)
|
|
);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
void gencontext_end_file_emit(GenContext *c, CompilationUnit *ast)
|
|
{
|
|
}
|
|
|
|
void gencontext_end_module(GenContext *context)
|
|
{
|
|
LLVMDisposeModule(context->module);
|
|
}
|