aboutsummaryrefslogtreecommitdiff
path: root/src/ir.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/ir.cpp')
-rw-r--r--src/ir.cpp303
1 files changed, 303 insertions, 0 deletions
diff --git a/src/ir.cpp b/src/ir.cpp
index 6c6ce676f6..ae48c1d369 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -411,6 +411,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionMemberCount *) {
return IrInstructionIdMemberCount;
}
+static constexpr IrInstructionId ir_instruction_id(IrInstructionMemberType *) {
+ return IrInstructionIdMemberType;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionMemberName *) {
+ return IrInstructionIdMemberName;
+}
+
static constexpr IrInstructionId ir_instruction_id(IrInstructionBreakpoint *) {
return IrInstructionIdBreakpoint;
}
@@ -567,6 +575,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSetAlignStack *)
return IrInstructionIdSetAlignStack;
}
+static constexpr IrInstructionId ir_instruction_id(IrInstructionArgType *) {
+ return IrInstructionIdArgType;
+}
+
template<typename T>
static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
T *special_instruction = allocate<T>(1);
@@ -1779,6 +1791,32 @@ static IrInstruction *ir_build_member_count(IrBuilder *irb, Scope *scope, AstNod
return &instruction->base;
}
+static IrInstruction *ir_build_member_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *container_type, IrInstruction *member_index)
+{
+ IrInstructionMemberType *instruction = ir_build_instruction<IrInstructionMemberType>(irb, scope, source_node);
+ instruction->container_type = container_type;
+ instruction->member_index = member_index;
+
+ ir_ref_instruction(container_type, irb->current_basic_block);
+ ir_ref_instruction(member_index, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
+static IrInstruction *ir_build_member_name(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *container_type, IrInstruction *member_index)
+{
+ IrInstructionMemberName *instruction = ir_build_instruction<IrInstructionMemberName>(irb, scope, source_node);
+ instruction->container_type = container_type;
+ instruction->member_index = member_index;
+
+ ir_ref_instruction(container_type, irb->current_basic_block);
+ ir_ref_instruction(member_index, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
static IrInstruction *ir_build_breakpoint(IrBuilder *irb, Scope *scope, AstNode *source_node) {
IrInstructionBreakpoint *instruction = ir_build_instruction<IrInstructionBreakpoint>(irb, scope, source_node);
return &instruction->base;
@@ -2263,6 +2301,19 @@ static IrInstruction *ir_build_set_align_stack(IrBuilder *irb, Scope *scope, Ast
return &instruction->base;
}
+static IrInstruction *ir_build_arg_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *fn_type, IrInstruction *arg_index)
+{
+ IrInstructionArgType *instruction = ir_build_instruction<IrInstructionArgType>(irb, scope, source_node);
+ instruction->fn_type = fn_type;
+ instruction->arg_index = arg_index;
+
+ ir_ref_instruction(fn_type, irb->current_basic_block);
+ ir_ref_instruction(arg_index, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
static IrInstruction *ir_instruction_br_get_dep(IrInstructionBr *instruction, size_t index) {
return nullptr;
}
@@ -2710,6 +2761,22 @@ static IrInstruction *ir_instruction_membercount_get_dep(IrInstructionMemberCoun
}
}
+static IrInstruction *ir_instruction_membertype_get_dep(IrInstructionMemberType *instruction, size_t index) {
+ switch (index) {
+ case 0: return instruction->container_type;
+ case 1: return instruction->member_index;
+ default: return nullptr;
+ }
+}
+
+static IrInstruction *ir_instruction_membername_get_dep(IrInstructionMemberName *instruction, size_t index) {
+ switch (index) {
+ case 0: return instruction->container_type;
+ case 1: return instruction->member_index;
+ default: return nullptr;
+ }
+}
+
static IrInstruction *ir_instruction_breakpoint_get_dep(IrInstructionBreakpoint *instruction, size_t index) {
return nullptr;
}
@@ -2992,6 +3059,14 @@ static IrInstruction *ir_instruction_setalignstack_get_dep(IrInstructionSetAlign
}
}
+static IrInstruction *ir_instruction_argtype_get_dep(IrInstructionArgType *instruction, size_t index) {
+ switch (index) {
+ case 0: return instruction->fn_type;
+ case 1: return instruction->arg_index;
+ default: return nullptr;
+ }
+}
+
static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t index) {
switch (instruction->id) {
case IrInstructionIdInvalid:
@@ -3118,6 +3193,10 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
return ir_instruction_slice_get_dep((IrInstructionSlice *) instruction, index);
case IrInstructionIdMemberCount:
return ir_instruction_membercount_get_dep((IrInstructionMemberCount *) instruction, index);
+ case IrInstructionIdMemberType:
+ return ir_instruction_membertype_get_dep((IrInstructionMemberType *) instruction, index);
+ case IrInstructionIdMemberName:
+ return ir_instruction_membername_get_dep((IrInstructionMemberName *) instruction, index);
case IrInstructionIdBreakpoint:
return ir_instruction_breakpoint_get_dep((IrInstructionBreakpoint *) instruction, index);
case IrInstructionIdReturnAddress:
@@ -3194,6 +3273,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
return ir_instruction_opaquetype_get_dep((IrInstructionOpaqueType *) instruction, index);
case IrInstructionIdSetAlignStack:
return ir_instruction_setalignstack_get_dep((IrInstructionSetAlignStack *) instruction, index);
+ case IrInstructionIdArgType:
+ return ir_instruction_argtype_get_dep((IrInstructionArgType *) instruction, index);
}
zig_unreachable();
}
@@ -4352,6 +4433,36 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return ir_build_member_count(irb, scope, node, arg0_value);
}
+ case BuiltinFnIdMemberType:
+ {
+ AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ if (arg0_value == irb->codegen->invalid_instruction)
+ return arg0_value;
+
+ AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ if (arg1_value == irb->codegen->invalid_instruction)
+ return arg1_value;
+
+
+ return ir_build_member_type(irb, scope, node, arg0_value, arg1_value);
+ }
+ case BuiltinFnIdMemberName:
+ {
+ AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ if (arg0_value == irb->codegen->invalid_instruction)
+ return arg0_value;
+
+ AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ if (arg1_value == irb->codegen->invalid_instruction)
+ return arg1_value;
+
+
+ return ir_build_member_name(irb, scope, node, arg0_value, arg1_value);
+ }
case BuiltinFnIdBreakpoint:
return ir_build_breakpoint(irb, scope, node);
case BuiltinFnIdReturnAddress:
@@ -4629,6 +4740,20 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return ir_build_set_align_stack(irb, scope, node, arg0_value);
}
+ case BuiltinFnIdArgType:
+ {
+ AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ if (arg0_value == irb->codegen->invalid_instruction)
+ return arg0_value;
+
+ AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ if (arg1_value == irb->codegen->invalid_instruction)
+ return arg1_value;
+
+ return ir_build_arg_type(irb, scope, node, arg0_value, arg1_value);
+ }
}
zig_unreachable();
}
@@ -11643,6 +11768,62 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
buf_ptr(&child_type->name), buf_ptr(field_name)));
return ira->codegen->builtin_types.entry_invalid;
}
+ } else if (child_type->id == TypeTableEntryIdErrorUnion) {
+ if (buf_eql_str(field_name, "Child")) {
+ bool ptr_is_const = true;
+ bool ptr_is_volatile = false;
+ return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
+ create_const_type(ira->codegen, child_type->data.error.child_type),
+ ira->codegen->builtin_types.entry_type,
+ ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
+ } else {
+ ir_add_error(ira, &field_ptr_instruction->base,
+ buf_sprintf("type '%s' has no member called '%s'",
+ buf_ptr(&child_type->name), buf_ptr(field_name)));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+ } else if (child_type->id == TypeTableEntryIdMaybe) {
+ if (buf_eql_str(field_name, "Child")) {
+ bool ptr_is_const = true;
+ bool ptr_is_volatile = false;
+ return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
+ create_const_type(ira->codegen, child_type->data.maybe.child_type),
+ ira->codegen->builtin_types.entry_type,
+ ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
+ } else {
+ ir_add_error(ira, &field_ptr_instruction->base,
+ buf_sprintf("type '%s' has no member called '%s'",
+ buf_ptr(&child_type->name), buf_ptr(field_name)));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+ } else if (child_type->id == TypeTableEntryIdFn) {
+ if (buf_eql_str(field_name, "ReturnType")) {
+ bool ptr_is_const = true;
+ bool ptr_is_volatile = false;
+ return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
+ create_const_type(ira->codegen, child_type->data.fn.fn_type_id.return_type),
+ ira->codegen->builtin_types.entry_type,
+ ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
+ } else if (buf_eql_str(field_name, "is_var_args")) {
+ bool ptr_is_const = true;
+ bool ptr_is_volatile = false;
+ return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
+ create_const_bool(ira->codegen, child_type->data.fn.fn_type_id.is_var_args),
+ ira->codegen->builtin_types.entry_bool,
+ ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
+ } else if (buf_eql_str(field_name, "arg_count")) {
+ bool ptr_is_const = true;
+ bool ptr_is_volatile = false;
+ return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
+ create_const_usize(ira->codegen, child_type->data.fn.fn_type_id.param_count),
+ ira->codegen->builtin_types.entry_usize,
+ ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
+ } else {
+ ir_add_error(ira, &field_ptr_instruction->base,
+ buf_sprintf("type '%s' has no member called '%s'",
+ buf_ptr(&child_type->name), buf_ptr(field_name)));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
} else {
ir_add_error(ira, &field_ptr_instruction->base,
buf_sprintf("type '%s' does not support field access", buf_ptr(&child_type->name)));
@@ -14240,6 +14421,90 @@ static TypeTableEntry *ir_analyze_instruction_member_count(IrAnalyze *ira, IrIns
return ira->codegen->builtin_types.entry_num_lit_int;
}
+static TypeTableEntry *ir_analyze_instruction_member_type(IrAnalyze *ira, IrInstructionMemberType *instruction) {
+ IrInstruction *container_type_value = instruction->container_type->other;
+ TypeTableEntry *container_type = ir_resolve_type(ira, container_type_value);
+ if (type_is_invalid(container_type))
+ return ira->codegen->builtin_types.entry_invalid;
+
+ uint64_t member_index;
+ IrInstruction *index_value = instruction->member_index->other;
+ if (!ir_resolve_usize(ira, index_value, &member_index))
+ return ira->codegen->builtin_types.entry_invalid;
+
+ if (container_type->id == TypeTableEntryIdStruct) {
+ if (member_index >= container_type->data.structure.src_field_count) {
+ ir_add_error(ira, index_value,
+ buf_sprintf("member index %" ZIG_PRI_u64 " out of bounds; '%s' has %" PRIu32 " members",
+ member_index, buf_ptr(&container_type->name), container_type->data.structure.src_field_count));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+ TypeStructField *field = &container_type->data.structure.fields[member_index];
+
+ ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
+ out_val->data.x_type = field->type_entry;
+ return ira->codegen->builtin_types.entry_type;
+ } else if (container_type->id == TypeTableEntryIdEnum) {
+ if (member_index >= container_type->data.enumeration.src_field_count) {
+ ir_add_error(ira, index_value,
+ buf_sprintf("member index %" ZIG_PRI_u64 " out of bounds; '%s' has %" PRIu32 " members",
+ member_index, buf_ptr(&container_type->name), container_type->data.enumeration.src_field_count));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+ TypeEnumField *field = &container_type->data.enumeration.fields[member_index];
+
+ ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
+ out_val->data.x_type = field->type_entry;
+ return ira->codegen->builtin_types.entry_type;
+ } else {
+ ir_add_error(ira, container_type_value,
+ buf_sprintf("type '%s' does not support @memberType", buf_ptr(&container_type->name)));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+}
+
+static TypeTableEntry *ir_analyze_instruction_member_name(IrAnalyze *ira, IrInstructionMemberName *instruction) {
+ IrInstruction *container_type_value = instruction->container_type->other;
+ TypeTableEntry *container_type = ir_resolve_type(ira, container_type_value);
+ if (type_is_invalid(container_type))
+ return ira->codegen->builtin_types.entry_invalid;
+
+ uint64_t member_index;
+ IrInstruction *index_value = instruction->member_index->other;
+ if (!ir_resolve_usize(ira, index_value, &member_index))
+ return ira->codegen->builtin_types.entry_invalid;
+
+ if (container_type->id == TypeTableEntryIdStruct) {
+ if (member_index >= container_type->data.structure.src_field_count) {
+ ir_add_error(ira, index_value,
+ buf_sprintf("member index %" ZIG_PRI_u64 " out of bounds; '%s' has %" PRIu32 " members",
+ member_index, buf_ptr(&container_type->name), container_type->data.structure.src_field_count));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+ TypeStructField *field = &container_type->data.structure.fields[member_index];
+
+ ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
+ init_const_str_lit(ira->codegen, out_val, field->name);
+ return out_val->type;
+ } else if (container_type->id == TypeTableEntryIdEnum) {
+ if (member_index >= container_type->data.enumeration.src_field_count) {
+ ir_add_error(ira, index_value,
+ buf_sprintf("member index %" ZIG_PRI_u64 " out of bounds; '%s' has %" PRIu32 " members",
+ member_index, buf_ptr(&container_type->name), container_type->data.enumeration.src_field_count));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+ TypeEnumField *field = &container_type->data.enumeration.fields[member_index];
+
+ ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
+ init_const_str_lit(ira->codegen, out_val, field->name);
+ return out_val->type;
+ } else {
+ ir_add_error(ira, container_type_value,
+ buf_sprintf("type '%s' does not support @memberName", buf_ptr(&container_type->name)));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+}
+
static TypeTableEntry *ir_analyze_instruction_breakpoint(IrAnalyze *ira, IrInstructionBreakpoint *instruction) {
ir_build_breakpoint_from(&ira->new_irb, &instruction->base);
return ira->codegen->builtin_types.entry_void;
@@ -15346,6 +15611,35 @@ static TypeTableEntry *ir_analyze_instruction_set_align_stack(IrAnalyze *ira, Ir
return ira->codegen->builtin_types.entry_void;
}
+static TypeTableEntry *ir_analyze_instruction_arg_type(IrAnalyze *ira, IrInstructionArgType *instruction) {
+ IrInstruction *fn_type_inst = instruction->fn_type->other;
+ TypeTableEntry *fn_type = ir_resolve_type(ira, fn_type_inst);
+ if (type_is_invalid(fn_type))
+ return ira->codegen->builtin_types.entry_invalid;
+
+ IrInstruction *arg_index_inst = instruction->arg_index->other;
+ uint64_t arg_index;
+ if (!ir_resolve_usize(ira, arg_index_inst, &arg_index))
+ return ira->codegen->builtin_types.entry_invalid;
+
+ if (fn_type->id != TypeTableEntryIdFn) {
+ ir_add_error(ira, fn_type_inst, buf_sprintf("expected function, found '%s'", buf_ptr(&fn_type->name)));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+
+ FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
+ if (arg_index >= fn_type_id->param_count) {
+ ir_add_error(ira, arg_index_inst,
+ buf_sprintf("arg index %" ZIG_PRI_u64 " out of bounds; '%s' has %" ZIG_PRI_usize " arguments",
+ arg_index, buf_ptr(&fn_type->name), fn_type_id->param_count));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+
+ ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
+ out_val->data.x_type = fn_type_id->param_info[arg_index].type;
+ return ira->codegen->builtin_types.entry_type;
+}
+
static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
switch (instruction->id) {
case IrInstructionIdInvalid:
@@ -15480,6 +15774,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
return ir_analyze_instruction_slice(ira, (IrInstructionSlice *)instruction);
case IrInstructionIdMemberCount:
return ir_analyze_instruction_member_count(ira, (IrInstructionMemberCount *)instruction);
+ case IrInstructionIdMemberType:
+ return ir_analyze_instruction_member_type(ira, (IrInstructionMemberType *)instruction);
+ case IrInstructionIdMemberName:
+ return ir_analyze_instruction_member_name(ira, (IrInstructionMemberName *)instruction);
case IrInstructionIdBreakpoint:
return ir_analyze_instruction_breakpoint(ira, (IrInstructionBreakpoint *)instruction);
case IrInstructionIdReturnAddress:
@@ -15536,6 +15834,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
return ir_analyze_instruction_opaque_type(ira, (IrInstructionOpaqueType *)instruction);
case IrInstructionIdSetAlignStack:
return ir_analyze_instruction_set_align_stack(ira, (IrInstructionSetAlignStack *)instruction);
+ case IrInstructionIdArgType:
+ return ir_analyze_instruction_arg_type(ira, (IrInstructionArgType *)instruction);
}
zig_unreachable();
}
@@ -15687,6 +15987,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdBoolNot:
case IrInstructionIdSlice:
case IrInstructionIdMemberCount:
+ case IrInstructionIdMemberType:
+ case IrInstructionIdMemberName:
case IrInstructionIdAlignOf:
case IrInstructionIdReturnAddress:
case IrInstructionIdFrameAddress:
@@ -15716,6 +16018,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdTypeId:
case IrInstructionIdAlignCast:
case IrInstructionIdOpaqueType:
+ case IrInstructionIdArgType:
return false;
case IrInstructionIdAsm:
{