diff options
| author | Andrew Kelley <superjoe30@gmail.com> | 2016-12-12 01:59:55 -0500 |
|---|---|---|
| committer | Andrew Kelley <superjoe30@gmail.com> | 2016-12-12 01:59:55 -0500 |
| commit | 76a849b1f2c1bb57de4baf8dfd49fe9f9e2340f3 (patch) | |
| tree | 60b863f9ce40d7514bbdf6888a7dcd01e5c1e644 | |
| parent | ef63bc9cca6370f03d76a2a19dd7cdd7e23270d4 (diff) | |
| download | zig-76a849b1f2c1bb57de4baf8dfd49fe9f9e2340f3.tar.gz zig-76a849b1f2c1bb57de4baf8dfd49fe9f9e2340f3.zip | |
IR: implement memberCount builtin
| -rw-r--r-- | src/all_types.hpp | 7 | ||||
| -rw-r--r-- | src/analyze.cpp | 4 | ||||
| -rw-r--r-- | src/codegen.cpp | 1 | ||||
| -rw-r--r-- | src/ir.cpp | 71 | ||||
| -rw-r--r-- | src/ir_print.cpp | 9 |
5 files changed, 71 insertions, 21 deletions
diff --git a/src/all_types.hpp b/src/all_types.hpp index cecb6d4f5c..9be40971b7 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1418,6 +1418,7 @@ enum IrInstructionId { IrInstructionIdMemset, IrInstructionIdMemcpy, IrInstructionIdSlice, + IrInstructionIdMemberCount, }; struct IrInstruction { @@ -1953,6 +1954,12 @@ struct IrInstructionSlice { LLVMValueRef tmp_ptr; }; +struct IrInstructionMemberCount { + IrInstruction base; + + IrInstruction *container; +}; + enum LValPurpose { LValPurposeNone, LValPurposeAssign, diff --git a/src/analyze.cpp b/src/analyze.cpp index 57f06da842..03864ec85c 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -1648,10 +1648,10 @@ static void resolve_decl_container(CodeGen *g, TldContainer *tld_container) { case TypeTableEntryIdStruct: resolve_struct_type(g, tld_container->type_entry); return; - case ContainerKindEnum: + case TypeTableEntryIdEnum: resolve_enum_type(g, tld_container->type_entry); return; - case ContainerKindUnion: + case TypeTableEntryIdUnion: resolve_union_type(g, tld_container->type_entry); return; default: diff --git a/src/codegen.cpp b/src/codegen.cpp index 37d83c3dfc..b0f7cffff6 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2094,6 +2094,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdCUndef: case IrInstructionIdEmbedFile: case IrInstructionIdIntType: + case IrInstructionIdMemberCount: zig_unreachable(); case IrInstructionIdReturn: return ir_render_return(g, executable, (IrInstructionReturn *)instruction); diff --git a/src/ir.cpp b/src/ir.cpp index c74ba0ce47..7312c5efd6 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -387,6 +387,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSlice *) { return IrInstructionIdSlice; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionMemberCount *) { + return IrInstructionIdMemberCount; +} + template<typename T> static T *ir_create_instruction(IrExecutable *exec, Scope *scope, AstNode *source_node) { T *special_instruction = allocate<T>(1); @@ -1596,6 +1600,15 @@ static IrInstruction *ir_build_slice_from(IrBuilder *irb, IrInstruction *old_ins 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, 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); } - case BuiltinFnIdAlignof: 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 BuiltinFnIdSubWithOverflow: case BuiltinFnIdMulWithOverflow: @@ -8408,6 +8429,33 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio 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) { switch (instruction->id) { case IrInstructionIdInvalid: @@ -8530,6 +8578,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi return ir_analyze_instruction_memcpy(ira, (IrInstructionMemcpy *)instruction); case IrInstructionIdSlice: return ir_analyze_instruction_slice(ira, (IrInstructionSlice *)instruction); + case IrInstructionIdMemberCount: + return ir_analyze_instruction_member_count(ira, (IrInstructionMemberCount *)instruction); case IrInstructionIdCast: case IrInstructionIdStructFieldPtr: case IrInstructionIdEnumFieldPtr: @@ -8675,6 +8725,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdBoolNot: case IrInstructionIdAlloca: case IrInstructionIdSlice: + case IrInstructionIdMemberCount: return false; case IrInstructionIdAsm: { @@ -8736,23 +8787,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { // 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: // mark_impure_fn(g, context, node); // return g->builtin_types.entry_void; @@ -8997,7 +9031,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { // case BuiltinFnIdAlignof: // case BuiltinFnIdMinValue: // case BuiltinFnIdMaxValue: -// case BuiltinFnIdMemberCount: // // caught by constant expression eval codegen // zig_unreachable(); // case BuiltinFnIdCompileVar: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 1c62dc13fd..ede1c6461d 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -806,6 +806,12 @@ static void ir_print_slice(IrPrint *irp, IrInstructionSlice *instruction) { 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) { ir_print_prefix(irp, instruction); switch (instruction->id) { @@ -1000,6 +1006,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdSlice: ir_print_slice(irp, (IrInstructionSlice *)instruction); break; + case IrInstructionIdMemberCount: + ir_print_member_count(irp, (IrInstructionMemberCount *)instruction); + break; } fprintf(irp->f, "\n"); } |
