From 05de70017d8bf15a37f1d1be4e23f5d3f3f9b146 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 7 Nov 2016 18:58:01 -0500 Subject: IR: support slice types --- src/ir.cpp | 450 +++++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 301 insertions(+), 149 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 96bf78bdf5..84c0332c9b 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -189,6 +189,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSetFnTest *) { return IrInstructionIdSetFnTest; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionArrayType *) { + return IrInstructionIdArrayType; +} + +static constexpr IrInstructionId ir_instruction_id(IrInstructionSliceType *) { + return IrInstructionIdSliceType; +} + template static T *ir_create_instruction(IrExecutable *exec, AstNode *source_node) { T *special_instruction = allocate(1); @@ -716,19 +724,30 @@ static IrInstruction *ir_build_set_fn_test(IrBuilder *irb, AstNode *source_node, return &instruction->base; } -//static size_t get_conditional_defer_count(BlockContext *inner_block, BlockContext *outer_block) { -// size_t result = 0; -// while (inner_block != outer_block) { -// if (inner_block->node->type == NodeTypeDefer && -// (inner_block->node->data.defer.kind == ReturnKindError || -// inner_block->node->data.defer.kind == ReturnKindMaybe)) -// { -// result += 1; -// } -// inner_block = inner_block->parent; -// } -// return result; -//} +static IrInstruction *ir_build_array_type(IrBuilder *irb, AstNode *source_node, IrInstruction *size, + IrInstruction *child_type) +{ + IrInstructionArrayType *instruction = ir_build_instruction(irb, source_node); + instruction->size = size; + instruction->child_type = child_type; + + ir_ref_instruction(size); + ir_ref_instruction(child_type); + + return &instruction->base; +} + +static IrInstruction *ir_build_slice_type(IrBuilder *irb, AstNode *source_node, bool is_const, + IrInstruction *child_type) +{ + IrInstructionSliceType *instruction = ir_build_instruction(irb, source_node); + instruction->is_const = is_const; + instruction->child_type = child_type; + + ir_ref_instruction(child_type); + + return &instruction->base; +} static void ir_gen_defers_for_block(IrBuilder *irb, BlockContext *inner_block, BlockContext *outer_block, bool gen_error_defers, bool gen_maybe_defers) @@ -777,23 +796,6 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, AstNode *node) { zig_unreachable(); } -//static IrInstruction *ir_gen_return(IrBuilder *irb, AstNode *source_node, IrInstruction *value, ReturnKnowledge rk) { -// BlockContext *defer_inner_block = source_node->block_context; -// BlockContext *defer_outer_block = irb->node->block_context; -// if (rk == ReturnKnowledgeUnknown) { -// if (get_conditional_defer_count(defer_inner_block, defer_outer_block) > 0) { -// // generate branching code that checks the return value and generates defers -// // if the return value is error -// zig_panic("TODO"); -// } -// } else if (rk != ReturnKnowledgeSkipDefers) { -// ir_gen_defers_for_block(irb, defer_inner_block, defer_outer_block, -// rk == ReturnKnowledgeKnownError, rk == ReturnKnowledgeKnownNull); -// } -// -// return ir_build_return(irb, source_node, value); -//} - static void ir_set_cursor_at_end(IrBuilder *irb, IrBasicBlock *basic_block) { assert(basic_block); @@ -1588,6 +1590,38 @@ static IrInstruction *ir_gen_bool_literal(IrBuilder *irb, AstNode *node) { return ir_build_const_bool(irb, node, node->data.bool_literal.value); } +static IrInstruction *ir_gen_array_type(IrBuilder *irb, AstNode *node) { + assert(node->type == NodeTypeArrayType); + + AstNode *size_node = node->data.array_type.size; + AstNode *child_type_node = node->data.array_type.child_type; + bool is_const = node->data.array_type.is_const; + + if (size_node) { + if (is_const) { + add_node_error(irb->codegen, node, buf_create_from_str("const qualifier invalid on array type")); + return irb->codegen->invalid_instruction; + } + + IrInstruction *size_value = ir_gen_node(irb, size_node, node->block_context); + if (size_value == irb->codegen->invalid_instruction) + return size_value; + + IrInstruction *child_type = ir_gen_node(irb, child_type_node, node->block_context); + if (child_type == irb->codegen->invalid_instruction) + return child_type; + + return ir_build_array_type(irb, node, size_value, child_type); + } else { + IrInstruction *child_type = ir_gen_node_extra(irb, child_type_node, + node->block_context, LValPurposeAddressOf); + if (child_type == irb->codegen->invalid_instruction) + return child_type; + + return ir_build_slice_type(irb, node, is_const, child_type); + } +} + static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockContext *block_context, LValPurpose lval) { @@ -1627,6 +1661,8 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockCont return ir_gen_this_literal(irb, node); case NodeTypeBoolLiteral: return ir_gen_bool_literal(irb, node); + case NodeTypeArrayType: + return ir_gen_array_type(irb, node); case NodeTypeUnwrapErrorExpr: case NodeTypeDefer: case NodeTypeSliceExpr: @@ -1644,7 +1680,6 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockCont case NodeTypeZeroesLiteral: case NodeTypeErrorType: case NodeTypeTypeLiteral: - case NodeTypeArrayType: case NodeTypeVarLiteral: case NodeTypeRoot: case NodeTypeFnProto: @@ -1703,51 +1738,6 @@ IrInstruction *ir_gen_fn(CodeGen *codegn, FnTableEntry *fn_entry) { return ir_gen(codegn, body_node, scope, ir_executable); } -/* -static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *node) { - assert(node->type == NodeTypeGoto); - Buf *label_name = node->data.goto_expr.name; - BlockContext *context = node->block_context; - assert(context); - LabelTableEntry *label = find_label(g, context, label_name); - - if (!label) { - add_node_error(g, node, buf_sprintf("no label in scope named '%s'", buf_ptr(label_name))); - return; - } - - label->used = true; - node->data.goto_expr.label_entry = label; -} - - for (size_t i = 0; i < fn_table_entry->goto_list.length; i += 1) { - AstNode *goto_node = fn_table_entry->goto_list.at(i); - assert(goto_node->type == NodeTypeGoto); - analyze_goto_pass2(g, import, goto_node); - } - - for (size_t i = 0; i < fn_table_entry->all_labels.length; i += 1) { - LabelTableEntry *label = fn_table_entry->all_labels.at(i); - if (!label->used) { - add_node_error(g, label->decl_node, - buf_sprintf("label '%s' defined but not used", - buf_ptr(label->decl_node->data.label.name))); - } - } -*/ - -//static LabelTableEntry *find_label(CodeGen *g, BlockContext *orig_context, Buf *name) { -// BlockContext *context = orig_context; -// while (context && context->fn_entry) { -// auto entry = context->label_table.maybe_get(name); -// if (entry) { -// return entry->value; -// } -// context = context->parent; -// } -// return nullptr; -//} - static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruction, TypeTableEntry *other_type) { TypeTableEntry *other_type_underlying = get_underlying_type(other_type); @@ -2970,6 +2960,59 @@ static TypeTableEntry *ir_analyze_unary_bool_not(IrAnalyze *ira, IrInstructionUn return bool_type; } +static TypeTableEntry *ir_analyze_unary_prefix_op_err(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) { + assert(un_op_instruction->op_id == IrUnOpError); + IrInstruction *value = un_op_instruction->value->other; + + TypeTableEntry *type_entry = value->type_entry; + if (type_entry->id == TypeTableEntryIdInvalid) + return ira->codegen->builtin_types.entry_invalid; + + TypeTableEntry *meta_type = ir_resolve_type(ira, value); + TypeTableEntry *underlying_meta_type = get_underlying_type(meta_type); + switch (underlying_meta_type->id) { + case TypeTableEntryIdTypeDecl: + zig_unreachable(); + case TypeTableEntryIdInvalid: + return ira->codegen->builtin_types.entry_invalid; + case TypeTableEntryIdVoid: + case TypeTableEntryIdBool: + case TypeTableEntryIdInt: + case TypeTableEntryIdFloat: + case TypeTableEntryIdPointer: + case TypeTableEntryIdArray: + case TypeTableEntryIdStruct: + case TypeTableEntryIdMaybe: + case TypeTableEntryIdErrorUnion: + case TypeTableEntryIdPureError: + case TypeTableEntryIdEnum: + case TypeTableEntryIdUnion: + case TypeTableEntryIdFn: + case TypeTableEntryIdGenericFn: + { + ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base, + value->static_value.depends_on_compile_var); + TypeTableEntry *result_type = get_error_type(ira->codegen, meta_type); + out_val->data.x_type = result_type; + return ira->codegen->builtin_types.entry_type; + } + case TypeTableEntryIdMetaType: + case TypeTableEntryIdNumLitFloat: + case TypeTableEntryIdNumLitInt: + case TypeTableEntryIdUndefLit: + case TypeTableEntryIdNullLit: + case TypeTableEntryIdNamespace: + case TypeTableEntryIdBlock: + case TypeTableEntryIdUnreachable: + case TypeTableEntryIdVar: + add_node_error(ira->codegen, un_op_instruction->base.source_node, + buf_sprintf("unable to wrap type '%s' in error type", buf_ptr(&meta_type->name))); + // TODO if meta_type is type decl, add note pointing to type decl declaration + return ira->codegen->builtin_types.entry_invalid; + } + zig_unreachable(); +} + static TypeTableEntry *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) { IrUnOp op_id = un_op_instruction->op_id; switch (op_id) { @@ -2977,7 +3020,6 @@ static TypeTableEntry *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstructio zig_unreachable(); case IrUnOpBoolNot: return ir_analyze_unary_bool_not(ira, un_op_instruction); - zig_panic("TODO analyze PrefixOpBoolNot"); case IrUnOpBinNot: zig_panic("TODO analyze PrefixOpBinNot"); //{ @@ -3106,31 +3148,7 @@ static TypeTableEntry *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstructio // } //} case IrUnOpError: - zig_panic("TODO analyze PrefixOpError"); - //{ - // TypeTableEntry *type_entry = analyze_expression(g, import, context, nullptr, *expr_node); - - // if (type_entry->id == TypeTableEntryIdInvalid) { - // return type_entry; - // } else if (type_entry->id == TypeTableEntryIdMetaType) { - // TypeTableEntry *meta_type = resolve_type(g, *expr_node); - // if (meta_type->id == TypeTableEntryIdInvalid) { - // return meta_type; - // } else if (meta_type->id == TypeTableEntryIdUnreachable) { - // add_node_error(g, node, buf_create_from_str("unable to wrap unreachable in error type")); - // return g->builtin_types.entry_invalid; - // } else { - // return resolve_expr_const_val_as_type(g, node, get_error_type(g, meta_type), false); - // } - // } else if (type_entry->id == TypeTableEntryIdUnreachable) { - // add_node_error(g, *expr_node, buf_sprintf("unable to wrap unreachable in error type")); - // return g->builtin_types.entry_invalid; - // } else { - // // TODO eval const expr - // return get_error_type(g, type_entry); - // } - - //} + return ir_analyze_unary_prefix_op_err(ira, un_op_instruction); case IrUnOpUnwrapError: zig_panic("TODO analyze PrefixOpUnwrapError"); //{ @@ -3691,6 +3709,59 @@ static TypeTableEntry *ir_analyze_instruction_set_fn_test(IrAnalyze *ira, return ira->codegen->builtin_types.entry_void; } +static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira, + IrInstructionSliceType *slice_type_instruction) +{ + IrInstruction *child_type = slice_type_instruction->child_type->other; + if (child_type->type_entry->id == TypeTableEntryIdInvalid) + return ira->codegen->builtin_types.entry_invalid; + bool is_const = slice_type_instruction->is_const; + + TypeTableEntry *resolved_child_type = ir_resolve_type(ira, child_type); + TypeTableEntry *canon_child_type = get_underlying_type(resolved_child_type); + switch (canon_child_type->id) { + case TypeTableEntryIdTypeDecl: + zig_unreachable(); + case TypeTableEntryIdInvalid: + return ira->codegen->builtin_types.entry_invalid; + case TypeTableEntryIdVar: + case TypeTableEntryIdUnreachable: + case TypeTableEntryIdUndefLit: + case TypeTableEntryIdNullLit: + case TypeTableEntryIdBlock: + add_node_error(ira->codegen, slice_type_instruction->base.source_node, + buf_sprintf("slice of type '%s' not allowed", buf_ptr(&resolved_child_type->name))); + // TODO if this is a typedecl, add error note showing the declaration of the type decl + return ira->codegen->builtin_types.entry_invalid; + case TypeTableEntryIdMetaType: + case TypeTableEntryIdVoid: + case TypeTableEntryIdBool: + case TypeTableEntryIdInt: + case TypeTableEntryIdFloat: + case TypeTableEntryIdPointer: + case TypeTableEntryIdArray: + case TypeTableEntryIdStruct: + case TypeTableEntryIdNumLitFloat: + case TypeTableEntryIdNumLitInt: + case TypeTableEntryIdMaybe: + case TypeTableEntryIdErrorUnion: + case TypeTableEntryIdPureError: + case TypeTableEntryIdEnum: + case TypeTableEntryIdUnion: + case TypeTableEntryIdFn: + case TypeTableEntryIdNamespace: + case TypeTableEntryIdGenericFn: + { + TypeTableEntry *result_type = get_slice_type(ira->codegen, resolved_child_type, is_const); + ConstExprValue *out_val = ir_build_const_from(ira, &slice_type_instruction->base, + child_type->static_value.depends_on_compile_var); + out_val->data.x_type = result_type; + return ira->codegen->builtin_types.entry_type; + } + } + zig_unreachable(); +} + static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { switch (instruction->id) { case IrInstructionIdInvalid: @@ -3735,11 +3806,14 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi return ir_analyze_instruction_ptr_type_child(ira, (IrInstructionPtrTypeChild *)instruction); case IrInstructionIdSetFnTest: return ir_analyze_instruction_set_fn_test(ira, (IrInstructionSetFnTest *)instruction); + case IrInstructionIdSliceType: + return ir_analyze_instruction_slice_type(ira, (IrInstructionSliceType *)instruction); case IrInstructionIdSwitchBr: case IrInstructionIdCast: case IrInstructionIdContainerInitList: case IrInstructionIdContainerInitFields: case IrInstructionIdStructFieldPtr: + case IrInstructionIdArrayType: zig_panic("TODO analyze more instructions"); } zig_unreachable(); @@ -3836,6 +3910,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdPtrTypeChild: case IrInstructionIdReadField: case IrInstructionIdStructFieldPtr: + case IrInstructionIdArrayType: + case IrInstructionIdSliceType: return false; } zig_unreachable(); @@ -6782,53 +6858,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) { // false, nullptr, false); //} // -//static TypeTableEntry *analyze_array_type(CodeGen *g, ImportTableEntry *import, BlockContext *context, -// TypeTableEntry *expected_type, AstNode *node) -//{ -// AstNode *size_node = node->data.array_type.size; -// -// TypeTableEntry *child_type = analyze_type_expr_pointer_only(g, import, context, -// node->data.array_type.child_type, true); -// -// if (child_type->id == TypeTableEntryIdUnreachable) { -// add_node_error(g, node, buf_create_from_str("array of unreachable not allowed")); -// return g->builtin_types.entry_invalid; -// } else if (child_type->id == TypeTableEntryIdInvalid) { -// return g->builtin_types.entry_invalid; -// } -// -// if (size_node) { -// child_type = analyze_type_expr(g, import, context, node->data.array_type.child_type); -// TypeTableEntry *size_type = analyze_expression(g, import, context, -// g->builtin_types.entry_usize, size_node); -// if (size_type->id == TypeTableEntryIdInvalid) { -// return g->builtin_types.entry_invalid; -// } -// -// ConstExprValue *const_val = &get_resolved_expr(size_node)->const_val; -// if (const_val->ok) { -// if (const_val->data.x_bignum.is_negative) { -// add_node_error(g, size_node, -// buf_sprintf("array size %s is negative", -// buf_ptr(bignum_to_buf(&const_val->data.x_bignum)))); -// return g->builtin_types.entry_invalid; -// } else { -// return resolve_expr_const_val_as_type(g, node, -// get_array_type(g, child_type, const_val->data.x_bignum.data.x_uint), false); -// } -// } else if (context->fn_entry) { -// return resolve_expr_const_val_as_type(g, node, -// get_slice_type(g, child_type, node->data.array_type.is_const), false); -// } else { -// add_node_error(g, first_executing_node(size_node), -// buf_sprintf("unable to evaluate constant expression")); -// return g->builtin_types.entry_invalid; -// } -// } else { -// TypeTableEntry *slice_type = get_slice_type(g, child_type, node->data.array_type.is_const); -// return resolve_expr_const_val_as_type(g, node, slice_type, false); -// } -//} // //static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, // TypeTableEntry *expected_type, AstNode *node) @@ -7218,3 +7247,126 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) { // } //} // +//static TypeTableEntry *analyze_array_type(CodeGen *g, ImportTableEntry *import, BlockContext *context, +// TypeTableEntry *expected_type, AstNode *node) +//{ +// AstNode *size_node = node->data.array_type.size; +// +// TypeTableEntry *child_type = analyze_type_expr_pointer_only(g, import, context, +// node->data.array_type.child_type, true); +// +// if (child_type->id == TypeTableEntryIdUnreachable) { +// add_node_error(g, node, buf_create_from_str("array of unreachable not allowed")); +// return g->builtin_types.entry_invalid; +// } else if (child_type->id == TypeTableEntryIdInvalid) { +// return g->builtin_types.entry_invalid; +// } +// +// if (size_node) { +// child_type = analyze_type_expr(g, import, context, node->data.array_type.child_type); +// TypeTableEntry *size_type = analyze_expression(g, import, context, +// g->builtin_types.entry_usize, size_node); +// if (size_type->id == TypeTableEntryIdInvalid) { +// return g->builtin_types.entry_invalid; +// } +// +// ConstExprValue *const_val = &get_resolved_expr(size_node)->const_val; +// if (const_val->ok) { +// if (const_val->data.x_bignum.is_negative) { +// add_node_error(g, size_node, +// buf_sprintf("array size %s is negative", +// buf_ptr(bignum_to_buf(&const_val->data.x_bignum)))); +// return g->builtin_types.entry_invalid; +// } else { +// return resolve_expr_const_val_as_type(g, node, +// get_array_type(g, child_type, const_val->data.x_bignum.data.x_uint), false); +// } +// } else if (context->fn_entry) { +// return resolve_expr_const_val_as_type(g, node, +// get_slice_type(g, child_type, node->data.array_type.is_const), false); +// } else { +// add_node_error(g, first_executing_node(size_node), +// buf_sprintf("unable to evaluate constant expression")); +// return g->builtin_types.entry_invalid; +// } +// } else { +// TypeTableEntry *slice_type = get_slice_type(g, child_type, node->data.array_type.is_const); +// return resolve_expr_const_val_as_type(g, node, slice_type, false); +// } +//} +//static size_t get_conditional_defer_count(BlockContext *inner_block, BlockContext *outer_block) { +// size_t result = 0; +// while (inner_block != outer_block) { +// if (inner_block->node->type == NodeTypeDefer && +// (inner_block->node->data.defer.kind == ReturnKindError || +// inner_block->node->data.defer.kind == ReturnKindMaybe)) +// { +// result += 1; +// } +// inner_block = inner_block->parent; +// } +// return result; +//} + + +//static IrInstruction *ir_gen_return(IrBuilder *irb, AstNode *source_node, IrInstruction *value, ReturnKnowledge rk) { +// BlockContext *defer_inner_block = source_node->block_context; +// BlockContext *defer_outer_block = irb->node->block_context; +// if (rk == ReturnKnowledgeUnknown) { +// if (get_conditional_defer_count(defer_inner_block, defer_outer_block) > 0) { +// // generate branching code that checks the return value and generates defers +// // if the return value is error +// zig_panic("TODO"); +// } +// } else if (rk != ReturnKnowledgeSkipDefers) { +// ir_gen_defers_for_block(irb, defer_inner_block, defer_outer_block, +// rk == ReturnKnowledgeKnownError, rk == ReturnKnowledgeKnownNull); +// } +// +// return ir_build_return(irb, source_node, value); +//} +/* +static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *node) { + assert(node->type == NodeTypeGoto); + Buf *label_name = node->data.goto_expr.name; + BlockContext *context = node->block_context; + assert(context); + LabelTableEntry *label = find_label(g, context, label_name); + + if (!label) { + add_node_error(g, node, buf_sprintf("no label in scope named '%s'", buf_ptr(label_name))); + return; + } + + label->used = true; + node->data.goto_expr.label_entry = label; +} + + for (size_t i = 0; i < fn_table_entry->goto_list.length; i += 1) { + AstNode *goto_node = fn_table_entry->goto_list.at(i); + assert(goto_node->type == NodeTypeGoto); + analyze_goto_pass2(g, import, goto_node); + } + + for (size_t i = 0; i < fn_table_entry->all_labels.length; i += 1) { + LabelTableEntry *label = fn_table_entry->all_labels.at(i); + if (!label->used) { + add_node_error(g, label->decl_node, + buf_sprintf("label '%s' defined but not used", + buf_ptr(label->decl_node->data.label.name))); + } + } +*/ + +//static LabelTableEntry *find_label(CodeGen *g, BlockContext *orig_context, Buf *name) { +// BlockContext *context = orig_context; +// while (context && context->fn_entry) { +// auto entry = context->label_table.maybe_get(name); +// if (entry) { +// return entry->value; +// } +// context = context->parent; +// } +// return nullptr; +//} + -- cgit v1.2.3