mirror of
https://github.com/ziglang/zig.git
synced 2025-12-22 06:03:16 +00:00
IR: implement memberCount builtin
This commit is contained in:
parent
ef63bc9cca
commit
76a849b1f2
@ -1418,6 +1418,7 @@ enum IrInstructionId {
|
|||||||
IrInstructionIdMemset,
|
IrInstructionIdMemset,
|
||||||
IrInstructionIdMemcpy,
|
IrInstructionIdMemcpy,
|
||||||
IrInstructionIdSlice,
|
IrInstructionIdSlice,
|
||||||
|
IrInstructionIdMemberCount,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct IrInstruction {
|
struct IrInstruction {
|
||||||
@ -1953,6 +1954,12 @@ struct IrInstructionSlice {
|
|||||||
LLVMValueRef tmp_ptr;
|
LLVMValueRef tmp_ptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct IrInstructionMemberCount {
|
||||||
|
IrInstruction base;
|
||||||
|
|
||||||
|
IrInstruction *container;
|
||||||
|
};
|
||||||
|
|
||||||
enum LValPurpose {
|
enum LValPurpose {
|
||||||
LValPurposeNone,
|
LValPurposeNone,
|
||||||
LValPurposeAssign,
|
LValPurposeAssign,
|
||||||
|
|||||||
@ -1648,10 +1648,10 @@ static void resolve_decl_container(CodeGen *g, TldContainer *tld_container) {
|
|||||||
case TypeTableEntryIdStruct:
|
case TypeTableEntryIdStruct:
|
||||||
resolve_struct_type(g, tld_container->type_entry);
|
resolve_struct_type(g, tld_container->type_entry);
|
||||||
return;
|
return;
|
||||||
case ContainerKindEnum:
|
case TypeTableEntryIdEnum:
|
||||||
resolve_enum_type(g, tld_container->type_entry);
|
resolve_enum_type(g, tld_container->type_entry);
|
||||||
return;
|
return;
|
||||||
case ContainerKindUnion:
|
case TypeTableEntryIdUnion:
|
||||||
resolve_union_type(g, tld_container->type_entry);
|
resolve_union_type(g, tld_container->type_entry);
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@ -2094,6 +2094,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
|
|||||||
case IrInstructionIdCUndef:
|
case IrInstructionIdCUndef:
|
||||||
case IrInstructionIdEmbedFile:
|
case IrInstructionIdEmbedFile:
|
||||||
case IrInstructionIdIntType:
|
case IrInstructionIdIntType:
|
||||||
|
case IrInstructionIdMemberCount:
|
||||||
zig_unreachable();
|
zig_unreachable();
|
||||||
case IrInstructionIdReturn:
|
case IrInstructionIdReturn:
|
||||||
return ir_render_return(g, executable, (IrInstructionReturn *)instruction);
|
return ir_render_return(g, executable, (IrInstructionReturn *)instruction);
|
||||||
|
|||||||
71
src/ir.cpp
71
src/ir.cpp
@ -387,6 +387,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSlice *) {
|
|||||||
return IrInstructionIdSlice;
|
return IrInstructionIdSlice;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static constexpr IrInstructionId ir_instruction_id(IrInstructionMemberCount *) {
|
||||||
|
return IrInstructionIdMemberCount;
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static T *ir_create_instruction(IrExecutable *exec, Scope *scope, AstNode *source_node) {
|
static T *ir_create_instruction(IrExecutable *exec, Scope *scope, AstNode *source_node) {
|
||||||
T *special_instruction = allocate<T>(1);
|
T *special_instruction = allocate<T>(1);
|
||||||
@ -1596,6 +1600,15 @@ static IrInstruction *ir_build_slice_from(IrBuilder *irb, IrInstruction *old_ins
|
|||||||
return new_instruction;
|
return new_instruction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static IrInstruction *ir_build_member_count(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *container) {
|
||||||
|
IrInstructionMemberCount *instruction = ir_build_instruction<IrInstructionMemberCount>(irb, scope, source_node);
|
||||||
|
instruction->container = container;
|
||||||
|
|
||||||
|
ir_ref_instruction(container);
|
||||||
|
|
||||||
|
return &instruction->base;
|
||||||
|
}
|
||||||
|
|
||||||
static void ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope,
|
static void ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope,
|
||||||
bool gen_error_defers, bool gen_maybe_defers)
|
bool gen_error_defers, bool gen_maybe_defers)
|
||||||
{
|
{
|
||||||
@ -2469,8 +2482,16 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
|
|||||||
|
|
||||||
return ir_build_memset(irb, scope, node, arg0_value, arg1_value, arg2_value);
|
return ir_build_memset(irb, scope, node, arg0_value, arg1_value, arg2_value);
|
||||||
}
|
}
|
||||||
case BuiltinFnIdAlignof:
|
|
||||||
case BuiltinFnIdMemberCount:
|
case BuiltinFnIdMemberCount:
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
|
||||||
|
return ir_build_member_count(irb, scope, node, arg0_value);
|
||||||
|
}
|
||||||
|
case BuiltinFnIdAlignof:
|
||||||
case BuiltinFnIdAddWithOverflow:
|
case BuiltinFnIdAddWithOverflow:
|
||||||
case BuiltinFnIdSubWithOverflow:
|
case BuiltinFnIdSubWithOverflow:
|
||||||
case BuiltinFnIdMulWithOverflow:
|
case BuiltinFnIdMulWithOverflow:
|
||||||
@ -8408,6 +8429,33 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio
|
|||||||
return return_type;
|
return return_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static TypeTableEntry *ir_analyze_instruction_member_count(IrAnalyze *ira, IrInstructionMemberCount *instruction) {
|
||||||
|
IrInstruction *container = instruction->container->other;
|
||||||
|
if (container->type_entry->id == TypeTableEntryIdInvalid)
|
||||||
|
return ira->codegen->builtin_types.entry_invalid;
|
||||||
|
TypeTableEntry *container_type = ir_resolve_type(ira, container);
|
||||||
|
TypeTableEntry *canon_type = get_underlying_type(container_type);
|
||||||
|
|
||||||
|
uint64_t result;
|
||||||
|
if (canon_type->id == TypeTableEntryIdInvalid) {
|
||||||
|
return ira->codegen->builtin_types.entry_invalid;
|
||||||
|
} else if (canon_type->id == TypeTableEntryIdEnum) {
|
||||||
|
result = canon_type->data.enumeration.src_field_count;
|
||||||
|
} else if (canon_type->id == TypeTableEntryIdStruct) {
|
||||||
|
result = canon_type->data.structure.src_field_count;
|
||||||
|
} else if (canon_type->id == TypeTableEntryIdUnion) {
|
||||||
|
result = canon_type->data.unionation.src_field_count;
|
||||||
|
} else {
|
||||||
|
ir_add_error(ira, &instruction->base, buf_sprintf("no value count available for type '%s'", buf_ptr(&container_type->name)));
|
||||||
|
return ira->codegen->builtin_types.entry_invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool depends_on_compile_var = container->static_value.depends_on_compile_var;
|
||||||
|
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, depends_on_compile_var);
|
||||||
|
bignum_init_unsigned(&out_val->data.x_bignum, result);
|
||||||
|
return ira->codegen->builtin_types.entry_num_lit_int;
|
||||||
|
}
|
||||||
|
|
||||||
static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
|
static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
|
||||||
switch (instruction->id) {
|
switch (instruction->id) {
|
||||||
case IrInstructionIdInvalid:
|
case IrInstructionIdInvalid:
|
||||||
@ -8530,6 +8578,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
|
|||||||
return ir_analyze_instruction_memcpy(ira, (IrInstructionMemcpy *)instruction);
|
return ir_analyze_instruction_memcpy(ira, (IrInstructionMemcpy *)instruction);
|
||||||
case IrInstructionIdSlice:
|
case IrInstructionIdSlice:
|
||||||
return ir_analyze_instruction_slice(ira, (IrInstructionSlice *)instruction);
|
return ir_analyze_instruction_slice(ira, (IrInstructionSlice *)instruction);
|
||||||
|
case IrInstructionIdMemberCount:
|
||||||
|
return ir_analyze_instruction_member_count(ira, (IrInstructionMemberCount *)instruction);
|
||||||
case IrInstructionIdCast:
|
case IrInstructionIdCast:
|
||||||
case IrInstructionIdStructFieldPtr:
|
case IrInstructionIdStructFieldPtr:
|
||||||
case IrInstructionIdEnumFieldPtr:
|
case IrInstructionIdEnumFieldPtr:
|
||||||
@ -8675,6 +8725,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
|
|||||||
case IrInstructionIdBoolNot:
|
case IrInstructionIdBoolNot:
|
||||||
case IrInstructionIdAlloca:
|
case IrInstructionIdAlloca:
|
||||||
case IrInstructionIdSlice:
|
case IrInstructionIdSlice:
|
||||||
|
case IrInstructionIdMemberCount:
|
||||||
return false;
|
return false;
|
||||||
case IrInstructionIdAsm:
|
case IrInstructionIdAsm:
|
||||||
{
|
{
|
||||||
@ -8736,23 +8787,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
|
|||||||
// align_in_bytes, false);
|
// align_in_bytes, false);
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// case BuiltinFnIdMemberCount:
|
|
||||||
// {
|
|
||||||
// AstNode *type_node = node->data.fn_call_expr.params.at(0);
|
|
||||||
// TypeTableEntry *type_entry = analyze_type_expr(g, import, context, type_node);
|
|
||||||
//
|
|
||||||
// if (type_entry->id == TypeTableEntryIdInvalid) {
|
|
||||||
// return type_entry;
|
|
||||||
// } else if (type_entry->id == TypeTableEntryIdEnum) {
|
|
||||||
// uint64_t value_count = type_entry->data.enumeration.src_field_count;
|
|
||||||
// return resolve_expr_const_val_as_unsigned_num_lit(g, node, expected_type,
|
|
||||||
// value_count, false);
|
|
||||||
// } else {
|
|
||||||
// add_node_error(g, node,
|
|
||||||
// buf_sprintf("no value count available for type '%s'", buf_ptr(&type_entry->name)));
|
|
||||||
// return g->builtin_types.entry_invalid;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// case BuiltinFnIdBreakpoint:
|
// case BuiltinFnIdBreakpoint:
|
||||||
// mark_impure_fn(g, context, node);
|
// mark_impure_fn(g, context, node);
|
||||||
// return g->builtin_types.entry_void;
|
// return g->builtin_types.entry_void;
|
||||||
@ -8997,7 +9031,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
|
|||||||
// case BuiltinFnIdAlignof:
|
// case BuiltinFnIdAlignof:
|
||||||
// case BuiltinFnIdMinValue:
|
// case BuiltinFnIdMinValue:
|
||||||
// case BuiltinFnIdMaxValue:
|
// case BuiltinFnIdMaxValue:
|
||||||
// case BuiltinFnIdMemberCount:
|
|
||||||
// // caught by constant expression eval codegen
|
// // caught by constant expression eval codegen
|
||||||
// zig_unreachable();
|
// zig_unreachable();
|
||||||
// case BuiltinFnIdCompileVar:
|
// case BuiltinFnIdCompileVar:
|
||||||
|
|||||||
@ -806,6 +806,12 @@ static void ir_print_slice(IrPrint *irp, IrInstructionSlice *instruction) {
|
|||||||
fprintf(irp->f, "const");
|
fprintf(irp->f, "const");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ir_print_member_count(IrPrint *irp, IrInstructionMemberCount *instruction) {
|
||||||
|
fprintf(irp->f, "@memberCount(");
|
||||||
|
ir_print_other_instruction(irp, instruction->container);
|
||||||
|
fprintf(irp->f, ")");
|
||||||
|
}
|
||||||
|
|
||||||
static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
||||||
ir_print_prefix(irp, instruction);
|
ir_print_prefix(irp, instruction);
|
||||||
switch (instruction->id) {
|
switch (instruction->id) {
|
||||||
@ -1000,6 +1006,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
|||||||
case IrInstructionIdSlice:
|
case IrInstructionIdSlice:
|
||||||
ir_print_slice(irp, (IrInstructionSlice *)instruction);
|
ir_print_slice(irp, (IrInstructionSlice *)instruction);
|
||||||
break;
|
break;
|
||||||
|
case IrInstructionIdMemberCount:
|
||||||
|
ir_print_member_count(irp, (IrInstructionMemberCount *)instruction);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
fprintf(irp->f, "\n");
|
fprintf(irp->f, "\n");
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user