diff options
| author | Andrew Kelley <superjoe30@gmail.com> | 2017-04-08 17:45:22 -0400 |
|---|---|---|
| committer | Andrew Kelley <superjoe30@gmail.com> | 2017-04-08 17:45:22 -0400 |
| commit | 095591f0b0f0d09bb1589fc404c2e7fdeac4bee4 (patch) | |
| tree | d98a149b0a2472bdaef45b15bdcd42e4d6a42566 /src/codegen.cpp | |
| parent | 7611ed3484ad810fe10d3c303a04d66bfa0bd6fd (diff) | |
| download | zig-095591f0b0f0d09bb1589fc404c2e7fdeac4bee4.tar.gz zig-095591f0b0f0d09bb1589fc404c2e7fdeac4bee4.zip | |
add enumTagName builtin function
closes #299
Diffstat (limited to 'src/codegen.cpp')
| -rw-r--r-- | src/codegen.cpp | 70 |
1 files changed, 69 insertions, 1 deletions
diff --git a/src/codegen.cpp b/src/codegen.cpp index edd2cd181e..575010c9d6 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2134,6 +2134,29 @@ static LLVMValueRef ir_render_err_name(CodeGen *g, IrExecutable *executable, IrI return LLVMBuildInBoundsGEP(g->builder, g->err_name_table, indices, 2, ""); } +static LLVMValueRef ir_render_enum_tag_name(CodeGen *g, IrExecutable *executable, + IrInstructionEnumTagName *instruction) +{ + TypeTableEntry *enum_tag_type = instruction->target->value.type; + assert(enum_tag_type->data.enum_tag.generate_name_table); + + LLVMValueRef enum_tag_value = ir_llvm_value(g, instruction->target); + if (ir_want_debug_safety(g, &instruction->base)) { + TypeTableEntry *enum_type = enum_tag_type->data.enum_tag.enum_type; + size_t field_count = enum_type->data.enumeration.src_field_count; + LLVMValueRef zero = LLVMConstNull(LLVMTypeOf(enum_tag_value)); + LLVMValueRef end_val = LLVMConstInt(LLVMTypeOf(enum_tag_value), field_count, false); + add_bounds_check(g, enum_tag_value, LLVMIntUGE, zero, LLVMIntULT, end_val); + } + + LLVMValueRef indices[] = { + LLVMConstNull(g->builtin_types.entry_usize->type_ref), + enum_tag_value, + }; + return LLVMBuildInBoundsGEP(g->builder, enum_tag_type->data.enum_tag.name_table, indices, 2, ""); +} + + static LLVMAtomicOrdering to_LLVMAtomicOrdering(AtomicOrder atomic_order) { switch (atomic_order) { case AtomicOrderUnordered: return LLVMAtomicOrderingUnordered; @@ -2830,6 +2853,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_container_init_list(g, executable, (IrInstructionContainerInitList *)instruction); case IrInstructionIdPanic: return ir_render_panic(g, executable, (IrInstructionPanic *)instruction); + case IrInstructionIdEnumTagName: + return ir_render_enum_tag_name(g, executable, (IrInstructionEnumTagName *)instruction); } zig_unreachable(); } @@ -3390,6 +3415,46 @@ static void generate_error_name_table(CodeGen *g) { LLVMSetUnnamedAddr(g->err_name_table, true); } +static void generate_enum_name_tables(CodeGen *g) { + TypeTableEntry *str_type = get_slice_type(g, g->builtin_types.entry_u8, true); + TypeTableEntry *u8_ptr_type = str_type->data.structure.fields[0].type_entry; + + for (size_t enum_i = 0; enum_i < g->name_table_enums.length; enum_i += 1) { + TypeTableEntry *enum_tag_type = g->name_table_enums.at(enum_i); + assert(enum_tag_type->id == TypeTableEntryIdEnumTag); + TypeTableEntry *enum_type = enum_tag_type->data.enum_tag.enum_type; + + size_t field_count = enum_type->data.enumeration.src_field_count; + LLVMValueRef *values = allocate<LLVMValueRef>(field_count); + for (size_t field_i = 0; field_i < field_count; field_i += 1) { + Buf *name = enum_type->data.enumeration.fields[field_i].name; + + LLVMValueRef str_init = LLVMConstString(buf_ptr(name), buf_len(name), true); + LLVMValueRef str_global = LLVMAddGlobal(g->module, LLVMTypeOf(str_init), ""); + LLVMSetInitializer(str_global, str_init); + LLVMSetLinkage(str_global, LLVMPrivateLinkage); + LLVMSetGlobalConstant(str_global, true); + LLVMSetUnnamedAddr(str_global, true); + + LLVMValueRef fields[] = { + LLVMConstBitCast(str_global, u8_ptr_type->type_ref), + LLVMConstInt(g->builtin_types.entry_usize->type_ref, buf_len(name), false), + }; + values[field_i] = LLVMConstNamedStruct(str_type->type_ref, fields, 2); + } + + LLVMValueRef name_table_init = LLVMConstArray(str_type->type_ref, values, field_count); + + Buf *table_name = buf_sprintf("%s_name_table", buf_ptr(&enum_type->name)); + LLVMValueRef name_table = LLVMAddGlobal(g->module, LLVMTypeOf(name_table_init), buf_ptr(table_name)); + LLVMSetInitializer(name_table, name_table_init); + LLVMSetLinkage(name_table, LLVMPrivateLinkage); + LLVMSetGlobalConstant(name_table, true); + LLVMSetUnnamedAddr(name_table, true); + enum_tag_type->data.enum_tag.name_table = name_table; + } +} + static void build_all_basic_blocks(CodeGen *g, FnTableEntry *fn) { IrExecutable *executable = &fn->analyzed_executable; assert(executable->basic_block_list.length > 0); @@ -3428,6 +3493,7 @@ static void do_code_gen(CodeGen *g) { delete_unused_builtin_fns(g); generate_error_name_table(g); + generate_enum_name_tables(g); // Generate module level variables for (size_t i = 0; i < g->global_vars.length; i += 1) { @@ -3800,7 +3866,8 @@ static const GlobalLinkageValue global_linkage_values[] = { static void init_enum_debug_info(CodeGen *g, TypeTableEntry *enum_type) { uint32_t field_count = enum_type->data.enumeration.src_field_count; - TypeTableEntry *tag_type_entry = get_smallest_unsigned_int_type(g, field_count); + TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count); + TypeTableEntry *tag_type_entry = create_enum_tag_type(g, enum_type, tag_int_type); enum_type->data.enumeration.tag_type = tag_type_entry; ZigLLVMDIEnumerator **di_enumerators = allocate<ZigLLVMDIEnumerator*>(field_count); @@ -4327,6 +4394,7 @@ static void define_builtin_fns(CodeGen *g) { create_builtin_fn(g, BuiltinFnIdPanic, "panic", 1); create_builtin_fn(g, BuiltinFnIdPtrCast, "ptrcast", 2); create_builtin_fn(g, BuiltinFnIdIntToPtr, "intToPtr", 2); + create_builtin_fn(g, BuiltinFnIdEnumTagName, "enumTagName", 1); } static void add_compile_var(CodeGen *g, const char *name, ConstExprValue *value) { |
