aboutsummaryrefslogtreecommitdiff
path: root/src/ir.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/ir.cpp')
-rw-r--r--src/ir.cpp259
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: