diff options
| author | Andrew Kelley <superjoe30@gmail.com> | 2017-11-29 16:34:50 -0500 |
|---|---|---|
| committer | Andrew Kelley <superjoe30@gmail.com> | 2017-11-29 16:34:50 -0500 |
| commit | 91ef68f9b1121d2a08f175a81f88321664c90a61 (patch) | |
| tree | 73e2c9cf0b1f24b9855095757e65c4ac981517ef /src/ir.cpp | |
| parent | 9a4da6c8d8d55f47609b8e900e9a4bb1ac34d5e7 (diff) | |
| parent | 70662830044418fc2d637c166fc100fe72d60fcf (diff) | |
| download | zig-91ef68f9b1121d2a08f175a81f88321664c90a61.tar.gz zig-91ef68f9b1121d2a08f175a81f88321664c90a61.zip | |
Merge remote-tracking branch 'origin/master' into llvm6
Diffstat (limited to 'src/ir.cpp')
| -rw-r--r-- | src/ir.cpp | 259 |
1 files changed, 221 insertions, 38 deletions
diff --git a/src/ir.cpp b/src/ir.cpp index fdaced6806..7c15b48bee 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -11,7 +11,7 @@ #include "ir.hpp" #include "ir_print.hpp" #include "os.hpp" -#include "parsec.hpp" +#include "translate_c.hpp" #include "range_set.hpp" #include "softfloat.hpp" @@ -227,6 +227,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionEnumFieldPtr *) return IrInstructionIdEnumFieldPtr; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionUnionFieldPtr *) { + return IrInstructionIdUnionFieldPtr; +} + static constexpr IrInstructionId ir_instruction_id(IrInstructionElemPtr *) { return IrInstructionIdElemPtr; } @@ -351,6 +355,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionStructInit *) { return IrInstructionIdStructInit; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionUnionInit *) { + return IrInstructionIdUnionInit; +} + static constexpr IrInstructionId ir_instruction_id(IrInstructionMinValue *) { return IrInstructionIdMinValue; } @@ -922,6 +930,27 @@ static IrInstruction *ir_build_enum_field_ptr_from(IrBuilder *irb, IrInstruction return new_instruction; } +static IrInstruction *ir_build_union_field_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *union_ptr, TypeUnionField *field) +{ + IrInstructionUnionFieldPtr *instruction = ir_build_instruction<IrInstructionUnionFieldPtr>(irb, scope, source_node); + instruction->union_ptr = union_ptr; + instruction->field = field; + + ir_ref_instruction(union_ptr, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstruction *ir_build_union_field_ptr_from(IrBuilder *irb, IrInstruction *old_instruction, + IrInstruction *union_ptr, TypeUnionField *type_union_field) +{ + IrInstruction *new_instruction = ir_build_union_field_ptr(irb, old_instruction->scope, + old_instruction->source_node, union_ptr, type_union_field); + ir_link_new_instruction(new_instruction, old_instruction); + return new_instruction; +} + static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *source_node, FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args, bool is_comptime, bool is_inline) @@ -1112,6 +1141,28 @@ static IrInstruction *ir_build_struct_init_from(IrBuilder *irb, IrInstruction *o return new_instruction; } +static IrInstruction *ir_build_union_init(IrBuilder *irb, Scope *scope, AstNode *source_node, + TypeTableEntry *union_type, TypeUnionField *field, IrInstruction *init_value) +{ + IrInstructionUnionInit *union_init_instruction = ir_build_instruction<IrInstructionUnionInit>(irb, scope, source_node); + union_init_instruction->union_type = union_type; + union_init_instruction->field = field; + union_init_instruction->init_value = init_value; + + ir_ref_instruction(init_value, irb->current_basic_block); + + return &union_init_instruction->base; +} + +static IrInstruction *ir_build_union_init_from(IrBuilder *irb, IrInstruction *old_instruction, + TypeTableEntry *union_type, TypeUnionField *field, IrInstruction *init_value) +{ + IrInstruction *new_instruction = ir_build_union_init(irb, old_instruction->scope, + old_instruction->source_node, union_type, field, init_value); + ir_link_new_instruction(new_instruction, old_instruction); + return new_instruction; +} + static IrInstruction *ir_build_unreachable(IrBuilder *irb, Scope *scope, AstNode *source_node) { IrInstructionUnreachable *unreachable_instruction = ir_build_instruction<IrInstructionUnreachable>(irb, scope, source_node); @@ -2422,6 +2473,13 @@ static IrInstruction *ir_instruction_enumfieldptr_get_dep(IrInstructionEnumField } } +static IrInstruction *ir_instruction_unionfieldptr_get_dep(IrInstructionUnionFieldPtr *instruction, size_t index) { + switch (index) { + case 0: return instruction->union_ptr; + default: return nullptr; + } +} + static IrInstruction *ir_instruction_elemptr_get_dep(IrInstructionElemPtr *instruction, size_t index) { switch (index) { case 0: return instruction->array_ptr; @@ -2485,6 +2543,13 @@ static IrInstruction *ir_instruction_structinit_get_dep(IrInstructionStructInit return nullptr; } +static IrInstruction *ir_instruction_unioninit_get_dep(IrInstructionUnionInit *instruction, size_t index) { + switch (index) { + case 0: return instruction->init_value; + default: return nullptr; + } +} + static IrInstruction *ir_instruction_unreachable_get_dep(IrInstructionUnreachable *instruction, size_t index) { return nullptr; } @@ -3099,6 +3164,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t return ir_instruction_structfieldptr_get_dep((IrInstructionStructFieldPtr *) instruction, index); case IrInstructionIdEnumFieldPtr: return ir_instruction_enumfieldptr_get_dep((IrInstructionEnumFieldPtr *) instruction, index); + case IrInstructionIdUnionFieldPtr: + return ir_instruction_unionfieldptr_get_dep((IrInstructionUnionFieldPtr *) instruction, index); case IrInstructionIdElemPtr: return ir_instruction_elemptr_get_dep((IrInstructionElemPtr *) instruction, index); case IrInstructionIdVarPtr: @@ -3117,6 +3184,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t return ir_instruction_containerinitfields_get_dep((IrInstructionContainerInitFields *) instruction, index); case IrInstructionIdStructInit: return ir_instruction_structinit_get_dep((IrInstructionStructInit *) instruction, index); + case IrInstructionIdUnionInit: + return ir_instruction_unioninit_get_dep((IrInstructionUnionInit *) instruction, index); case IrInstructionIdUnreachable: return ir_instruction_unreachable_get_dep((IrInstructionUnreachable *) instruction, index); case IrInstructionIdTypeOf: @@ -6233,8 +6302,9 @@ static Buf *get_anon_type_name(CodeGen *codegen, IrExecutable *exec, const char buf_appendf(name, ")"); return name; } else { + //Note: C-imports do not have valid location information return buf_sprintf("(anonymous %s at %s:%" ZIG_PRI_usize ":%" ZIG_PRI_usize ")", kind_name, - buf_ptr(source_node->owner->path), source_node->line + 1, source_node->column + 1); + (source_node->owner->path != nullptr) ? buf_ptr(source_node->owner->path) : "(null)", source_node->line + 1, source_node->column + 1); } } } @@ -6263,6 +6333,9 @@ static IrInstruction *ir_gen_container_decl(IrBuilder *irb, Scope *parent_scope, } irb->codegen->resolve_queue.append(&tld_container->base); + // Add this to the list to mark as invalid if analyzing this exec fails. + irb->exec->tld_list.append(&tld_container->base); + return ir_build_const_type(irb, parent_scope, node, container_type); } @@ -6485,6 +6558,20 @@ static bool ir_goto_pass2(IrBuilder *irb) { return true; } +static void invalidate_exec(IrExecutable *exec) { + if (exec->invalid) + return; + + exec->invalid = true; + + for (size_t i = 0; i < exec->tld_list.length; i += 1) { + exec->tld_list.items[i]->resolution = TldResolutionInvalid; + } + + if (exec->source_exec != nullptr) + invalidate_exec(exec->source_exec); +} + bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_executable) { assert(node->owner); @@ -6508,7 +6595,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec } if (!ir_goto_pass2(irb)) { - irb->exec->invalid = true; + invalidate_exec(ir_executable); return false; } @@ -6534,7 +6621,7 @@ static void add_call_stack_errors(CodeGen *codegen, IrExecutable *exec, ErrorMsg } static ErrorMsg *exec_add_error_node(CodeGen *codegen, IrExecutable *exec, AstNode *source_node, Buf *msg) { - exec->invalid = true; + invalidate_exec(exec); ErrorMsg *err_msg = add_node_error(codegen, source_node, msg); if (exec->parent_exec) { add_call_stack_errors(codegen, exec, err_msg, 10); @@ -7897,6 +7984,9 @@ static IrInstruction *ir_get_const_ptr(IrAnalyze *ira, IrInstruction *instructio ConstExprValue *const_val = &const_instr->value; const_val->type = pointee_type; type_ensure_zero_bits_known(ira->codegen, type_entry); + if (type_is_invalid(type_entry)) { + return ira->codegen->invalid_instruction; + } const_val->data.x_type = get_pointer_to_type_extra(ira->codegen, type_entry, ptr_is_const, ptr_is_volatile, get_abi_alignment(ira->codegen, type_entry), 0, 0); return const_instr; @@ -7984,6 +8074,7 @@ IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node IrExecutable analyzed_executable = {0}; analyzed_executable.source_node = source_node; analyzed_executable.parent_exec = parent_exec; + analyzed_executable.source_exec = &ir_executable; analyzed_executable.name = exec_name; analyzed_executable.is_inline = true; analyzed_executable.fn_entry = fn_entry; @@ -10279,30 +10370,40 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, bool is_const = (var->value->type->id == TypeTableEntryIdMetaType) ? is_const_ptr : var->src_is_const; bool is_volatile = (var->value->type->id == TypeTableEntryIdMetaType) ? is_volatile_ptr : false; - if (mem_slot && mem_slot->special != ConstValSpecialRuntime) { - ConstPtrMut ptr_mut; - if (comptime_var_mem) { - ptr_mut = ConstPtrMutComptimeVar; - } else if (var->gen_is_const) { - ptr_mut = ConstPtrMutComptimeConst; - } else { - assert(!comptime_var_mem); - ptr_mut = ConstPtrMutRuntimeVar; + if (mem_slot != nullptr) { + switch (mem_slot->special) { + case ConstValSpecialRuntime: + goto no_mem_slot; + case ConstValSpecialStatic: // fallthrough + case ConstValSpecialUndef: { + ConstPtrMut ptr_mut; + if (comptime_var_mem) { + ptr_mut = ConstPtrMutComptimeVar; + } else if (var->gen_is_const) { + ptr_mut = ConstPtrMutComptimeConst; + } else { + assert(!comptime_var_mem); + ptr_mut = ConstPtrMutRuntimeVar; + } + return ir_get_const_ptr(ira, instruction, mem_slot, var->value->type, + ptr_mut, is_const, is_volatile, var->align_bytes); + } } - return ir_get_const_ptr(ira, instruction, mem_slot, var->value->type, - ptr_mut, is_const, is_volatile, var->align_bytes); - } else { - IrInstruction *var_ptr_instruction = ir_build_var_ptr(&ira->new_irb, - instruction->scope, instruction->source_node, var, is_const, is_volatile); - var_ptr_instruction->value.type = get_pointer_to_type_extra(ira->codegen, var->value->type, - var->src_is_const, is_volatile, var->align_bytes, 0, 0); - type_ensure_zero_bits_known(ira->codegen, var->value->type); + zig_unreachable(); + } - bool in_fn_scope = (scope_fn_entry(var->parent_scope) != nullptr); - var_ptr_instruction->value.data.rh_ptr = in_fn_scope ? RuntimeHintPtrStack : RuntimeHintPtrNonStack; +no_mem_slot: - return var_ptr_instruction; - } + IrInstruction *var_ptr_instruction = ir_build_var_ptr(&ira->new_irb, + instruction->scope, instruction->source_node, var, is_const, is_volatile); + var_ptr_instruction->value.type = get_pointer_to_type_extra(ira->codegen, var->value->type, + var->src_is_const, is_volatile, var->align_bytes, 0, 0); + type_ensure_zero_bits_known(ira->codegen, var->value->type); + + bool in_fn_scope = (scope_fn_entry(var->parent_scope) != nullptr); + var_ptr_instruction->value.data.rh_ptr = in_fn_scope ? RuntimeHintPtrStack : RuntimeHintPtrNonStack; + + return var_ptr_instruction; } static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call_instruction, @@ -10408,10 +10509,11 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal result = ir_eval_const_value(ira->codegen, exec_scope, body_node, return_type, ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, fn_entry, nullptr, call_instruction->base.source_node, nullptr, ira->new_irb.exec); - if (type_is_invalid(result->value.type)) - return ira->codegen->builtin_types.entry_invalid; ira->codegen->memoized_fn_eval_table.put(exec_scope, result); + + if (type_is_invalid(result->value.type)) + return ira->codegen->builtin_types.entry_invalid; } ConstExprValue *out_val = ir_build_const_from(ira, &call_instruction->base); @@ -11417,8 +11519,20 @@ static TypeTableEntry *ir_analyze_container_member_access_inner(IrAnalyze *ira, return ir_analyze_ref(ira, &field_ptr_instruction->base, bound_fn_value, true, false); } } + const char *prefix_name; + if (is_slice(bare_struct_type)) { + prefix_name = ""; + } else if (bare_struct_type->id == TypeTableEntryIdStruct) { + prefix_name = "struct "; + } else if (bare_struct_type->id == TypeTableEntryIdEnum) { + prefix_name = "enum "; + } else if (bare_struct_type->id == TypeTableEntryIdUnion) { + prefix_name = "union "; + } else { + prefix_name = ""; + } ir_add_error_node(ira, field_ptr_instruction->base.source_node, - buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name), buf_ptr(&bare_struct_type->name))); + buf_sprintf("no member named '%s' in %s'%s'", buf_ptr(field_name), prefix_name, buf_ptr(&bare_struct_type->name))); return ira->codegen->builtin_types.entry_invalid; } @@ -11428,14 +11542,13 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field { TypeTableEntry *bare_type = container_ref_type(container_type); ensure_complete_type(ira->codegen, bare_type); + if (type_is_invalid(bare_type)) + return ira->codegen->builtin_types.entry_invalid; assert(container_ptr->value.type->id == TypeTableEntryIdPointer); bool is_const = container_ptr->value.type->data.pointer.is_const; bool is_volatile = container_ptr->value.type->data.pointer.is_volatile; if (bare_type->id == TypeTableEntryIdStruct) { - if (bare_type->data.structure.is_invalid) - return ira->codegen->builtin_types.entry_invalid; - TypeStructField *field = find_struct_type_field(bare_type, field_name); if (field) { bool is_packed = (bare_type->data.structure.layout == ContainerLayoutPacked); @@ -11476,9 +11589,6 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field field_ptr_instruction, container_ptr, container_type); } } else if (bare_type->id == TypeTableEntryIdEnum) { - if (bare_type->data.enumeration.is_invalid) - return ira->codegen->builtin_types.entry_invalid; - TypeEnumField *field = find_enum_type_field(bare_type, field_name); if (field) { ir_build_enum_field_ptr_from(&ira->new_irb, &field_ptr_instruction->base, container_ptr, field); @@ -11489,7 +11599,15 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field field_ptr_instruction, container_ptr, container_type); } } else if (bare_type->id == TypeTableEntryIdUnion) { - zig_panic("TODO"); + TypeUnionField *field = find_union_type_field(bare_type, field_name); + if (field) { + ir_build_union_field_ptr_from(&ira->new_irb, &field_ptr_instruction->base, container_ptr, field); + return get_pointer_to_type_extra(ira->codegen, field->type_entry, is_const, is_volatile, + get_abi_alignment(ira->codegen, field->type_entry), 0, 0); + } else { + return ir_analyze_container_member_access_inner(ira, bare_type, field_name, + field_ptr_instruction, container_ptr, container_type); + } } else { zig_unreachable(); } @@ -13033,9 +13151,71 @@ static TypeTableEntry *ir_analyze_instruction_ref(IrAnalyze *ira, IrInstructionR return ir_analyze_ref(ira, &ref_instruction->base, value, ref_instruction->is_const, ref_instruction->is_volatile); } +static TypeTableEntry *ir_analyze_container_init_fields_union(IrAnalyze *ira, IrInstruction *instruction, + TypeTableEntry *container_type, size_t instr_field_count, IrInstructionContainerInitFieldsField *fields) +{ + assert(container_type->id == TypeTableEntryIdUnion); + + ensure_complete_type(ira->codegen, container_type); + + if (instr_field_count != 1) { + ir_add_error(ira, instruction, + buf_sprintf("union initialization expects exactly one field")); + return ira->codegen->builtin_types.entry_invalid; + } + + IrInstructionContainerInitFieldsField *field = &fields[0]; + IrInstruction *field_value = field->value->other; + if (type_is_invalid(field_value->value.type)) + return ira->codegen->builtin_types.entry_invalid; + + TypeUnionField *type_field = find_union_type_field(container_type, field->name); + if (!type_field) { + ir_add_error_node(ira, field->source_node, + buf_sprintf("no member named '%s' in union '%s'", + buf_ptr(field->name), buf_ptr(&container_type->name))); + return ira->codegen->builtin_types.entry_invalid; + } + + if (type_is_invalid(type_field->type_entry)) + return ira->codegen->builtin_types.entry_invalid; + + IrInstruction *casted_field_value = ir_implicit_cast(ira, field_value, type_field->type_entry); + if (casted_field_value == ira->codegen->invalid_instruction) + return ira->codegen->builtin_types.entry_invalid; + + bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->scope); + if (is_comptime || casted_field_value->value.special != ConstValSpecialRuntime) { + ConstExprValue *field_val = ir_resolve_const(ira, casted_field_value, UndefOk); + if (!field_val) + return ira->codegen->builtin_types.entry_invalid; + + ConstExprValue *out_val = ir_build_const_from(ira, instruction); + out_val->data.x_union.payload = field_val; + out_val->data.x_union.tag = type_field->value; + + ConstParent *parent = get_const_val_parent(ira->codegen, field_val); + if (parent != nullptr) { + parent->id = ConstParentIdUnion; + parent->data.p_union.union_val = out_val; + } + + return container_type; + } + + IrInstruction *new_instruction = ir_build_union_init_from(&ira->new_irb, instruction, + container_type, type_field, casted_field_value); + + ir_add_alloca(ira, new_instruction, container_type); + return container_type; +} + static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruction *instruction, TypeTableEntry *container_type, size_t instr_field_count, IrInstructionContainerInitFieldsField *fields) { + if (container_type->id == TypeTableEntryIdUnion) { + return ir_analyze_container_init_fields_union(ira, instruction, container_type, instr_field_count, fields); + } if (container_type->id != TypeTableEntryIdStruct || is_slice(container_type)) { ir_add_error(ira, instruction, buf_sprintf("type '%s' does not support struct initialization syntax", @@ -13043,8 +13223,7 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru return ira->codegen->builtin_types.entry_invalid; } - if (!type_is_complete(container_type)) - resolve_container_type(ira->codegen, container_type); + ensure_complete_type(ira->codegen, container_type); size_t actual_field_count = container_type->data.structure.src_field_count; @@ -13070,7 +13249,7 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru TypeStructField *type_field = find_struct_type_field(container_type, field->name); if (!type_field) { ir_add_error_node(ira, field->source_node, - buf_sprintf("no member named '%s' in '%s'", + buf_sprintf("no member named '%s' in struct '%s'", buf_ptr(field->name), buf_ptr(&container_type->name))); return ira->codegen->builtin_types.entry_invalid; } @@ -15657,8 +15836,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi case IrInstructionIdIntToErr: case IrInstructionIdErrToInt: case IrInstructionIdStructInit: + case IrInstructionIdUnionInit: case IrInstructionIdStructFieldPtr: case IrInstructionIdEnumFieldPtr: + case IrInstructionIdUnionFieldPtr: case IrInstructionIdInitEnum: case IrInstructionIdMaybeWrap: case IrInstructionIdErrWrapCode: @@ -15968,6 +16149,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdContainerInitList: case IrInstructionIdContainerInitFields: case IrInstructionIdStructInit: + case IrInstructionIdUnionInit: case IrInstructionIdFieldPtr: case IrInstructionIdElemPtr: case IrInstructionIdVarPtr: @@ -15977,6 +16159,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdArrayLen: case IrInstructionIdStructFieldPtr: case IrInstructionIdEnumFieldPtr: + case IrInstructionIdUnionFieldPtr: case IrInstructionIdArrayType: case IrInstructionIdSliceType: case IrInstructionIdSizeOf: |
