diff options
| author | Andrew Kelley <superjoe30@gmail.com> | 2016-12-07 01:23:38 -0500 |
|---|---|---|
| committer | Andrew Kelley <superjoe30@gmail.com> | 2016-12-07 01:23:38 -0500 |
| commit | 0ad580f001eb151d0feb7ad884e237b237220800 (patch) | |
| tree | 79eee5e187dfb183113187d88360446941cc3791 /src | |
| parent | 5e4ee659a6796f7cc327c5e1cf1e10b1c032e85e (diff) | |
| download | zig-0ad580f001eb151d0feb7ad884e237b237220800.tar.gz zig-0ad580f001eb151d0feb7ad884e237b237220800.zip | |
IR: add minValue, maxValue, and negation
Diffstat (limited to 'src')
| -rw-r--r-- | src/all_types.hpp | 14 | ||||
| -rw-r--r-- | src/codegen.cpp | 2 | ||||
| -rw-r--r-- | src/eval.cpp | 2 | ||||
| -rw-r--r-- | src/ir.cpp | 250 | ||||
| -rw-r--r-- | src/ir_print.cpp | 18 |
5 files changed, 204 insertions, 82 deletions
diff --git a/src/all_types.hpp b/src/all_types.hpp index fb1392abb4..7947820590 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1393,6 +1393,8 @@ enum IrInstructionId { IrInstructionIdImport, IrInstructionIdArrayLen, IrInstructionIdRef, + IrInstructionIdMinValue, + IrInstructionIdMaxValue, }; struct IrInstruction { @@ -1791,6 +1793,18 @@ struct IrInstructionRef { LLVMValueRef tmp_ptr; }; +struct IrInstructionMinValue { + IrInstruction base; + + IrInstruction *value; +}; + +struct IrInstructionMaxValue { + IrInstruction base; + + IrInstruction *value; +}; + enum LValPurpose { LValPurposeNone, LValPurposeAssign, diff --git a/src/codegen.cpp b/src/codegen.cpp index d6a619efe7..0fe7604a51 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1821,6 +1821,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdStaticEval: case IrInstructionIdImport: case IrInstructionIdContainerInitFields: + case IrInstructionIdMinValue: + case IrInstructionIdMaxValue: zig_unreachable(); case IrInstructionIdReturn: return ir_render_return(g, executable, (IrInstructionReturn *)instruction); diff --git a/src/eval.cpp b/src/eval.cpp index 0d4bf6863c..c900882d90 100644 --- a/src/eval.cpp +++ b/src/eval.cpp @@ -431,6 +431,8 @@ void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue * } else if (type_entry->id == TypeTableEntryIdBool) { const_val->special = ConstValSpecialStatic; const_val->data.x_bool = is_max; + } else if (type_entry->id == TypeTableEntryIdVoid) { + // nothing to do } else { zig_unreachable(); } diff --git a/src/ir.cpp b/src/ir.cpp index 9d8dbba475..cc270a012d 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -306,6 +306,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionStructInit *) { return IrInstructionIdStructInit; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionMinValue *) { + return IrInstructionIdMinValue; +} + +static constexpr IrInstructionId ir_instruction_id(IrInstructionMaxValue *) { + return IrInstructionIdMaxValue; +} + template<typename T> static T *ir_create_instruction(IrExecutable *exec, Scope *scope, AstNode *source_node) { T *special_instruction = allocate<T>(1); @@ -1241,6 +1249,25 @@ static IrInstruction *ir_build_ref_from(IrBuilder *irb, IrInstruction *old_instr return new_instruction; } +static IrInstruction *ir_build_min_value(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) { + IrInstructionMinValue *instruction = ir_build_instruction<IrInstructionMinValue>(irb, scope, source_node); + instruction->value = value; + + ir_ref_instruction(value); + + return &instruction->base; +} + +static IrInstruction *ir_build_max_value(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) { + IrInstructionMaxValue *instruction = ir_build_instruction<IrInstructionMaxValue>(irb, scope, source_node); + instruction->value = value; + + ir_ref_instruction(value); + + 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) { @@ -1879,11 +1906,27 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return ir_build_import(irb, scope, node, arg0_value); } + case BuiltinFnIdMaxValue: + { + 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_max_value(irb, scope, node, arg0_value); + } + case BuiltinFnIdMinValue: + { + 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_min_value(irb, scope, node, arg0_value); + } case BuiltinFnIdMemcpy: case BuiltinFnIdMemset: case BuiltinFnIdAlignof: - case BuiltinFnIdMaxValue: - case BuiltinFnIdMinValue: case BuiltinFnIdMemberCount: case BuiltinFnIdAddWithOverflow: case BuiltinFnIdSubWithOverflow: @@ -4670,7 +4713,7 @@ static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstruction if (is_inline || fn_ref->static_value.special != ConstValSpecialRuntime) { if (fn_ref->type_entry->id == TypeTableEntryIdMetaType) { TypeTableEntry *dest_type = ir_resolve_type(ira, fn_ref); - if (!dest_type) + if (dest_type->id == TypeTableEntryIdInvalid) return ira->codegen->builtin_types.entry_invalid; size_t actual_param_count = call_instruction->arg_count; @@ -4958,6 +5001,48 @@ static TypeTableEntry *ir_analyze_unwrap_maybe(IrAnalyze *ira, IrInstructionUnOp } } +static TypeTableEntry *ir_analyze_negation(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) { + IrInstruction *value = un_op_instruction->value->other; + TypeTableEntry *expr_type = value->type_entry; + if (expr_type->id == TypeTableEntryIdInvalid) + return ira->codegen->builtin_types.entry_invalid; + + bool is_wrap_op = (un_op_instruction->op_id == IrUnOpNegationWrap); + + if ((expr_type->id == TypeTableEntryIdInt && expr_type->data.integral.is_signed) || + expr_type->id == TypeTableEntryIdNumLitInt || + ((expr_type->id == TypeTableEntryIdFloat || expr_type->id == TypeTableEntryIdNumLitFloat) && + !is_wrap_op)) + { + ConstExprValue *target_const_val = &value->static_value; + if (target_const_val->special != ConstValSpecialRuntime) { + bool depends_on_compile_var = value->static_value.depends_on_compile_var; + ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base, depends_on_compile_var); + bignum_negate(&out_val->data.x_bignum, &target_const_val->data.x_bignum); + if (expr_type->id == TypeTableEntryIdFloat || + expr_type->id == TypeTableEntryIdNumLitFloat || + expr_type->id == TypeTableEntryIdNumLitInt) + { + return expr_type; + } + + bool overflow = !bignum_fits_in_bits(&out_val->data.x_bignum, expr_type->data.integral.bit_count, true); + if (is_wrap_op) { + if (overflow) + out_val->data.x_bignum.is_negative = true; + } else if (overflow) { + ir_add_error(ira, &un_op_instruction->base, buf_sprintf("negation caused overflow")); + return ira->codegen->builtin_types.entry_invalid; + } + return expr_type; + } + } + + const char *fmt = is_wrap_op ? "invalid wrapping negation type: '%s'" : "invalid negation type: '%s'"; + ir_add_error(ira, &un_op_instruction->base, buf_sprintf(fmt, buf_ptr(&expr_type->name))); + return ira->codegen->builtin_types.entry_invalid; +} + static TypeTableEntry *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) { IrUnOp op_id = un_op_instruction->op_id; switch (op_id) { @@ -4983,51 +5068,7 @@ static TypeTableEntry *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstructio //} case IrUnOpNegation: case IrUnOpNegationWrap: - zig_panic("TODO analyze PrefixOpNegation[Wrap]"); - //{ - // TypeTableEntry *expr_type = analyze_expression(g, import, context, nullptr, *expr_node); - // if (expr_type->id == TypeTableEntryIdInvalid) { - // return expr_type; - // } else if ((expr_type->id == TypeTableEntryIdInt && - // expr_type->data.integral.is_signed) || - // expr_type->id == TypeTableEntryIdNumLitInt || - // ((expr_type->id == TypeTableEntryIdFloat || - // expr_type->id == TypeTableEntryIdNumLitFloat) && - // prefix_op != PrefixOpNegationWrap)) - // { - // ConstExprValue *target_const_val = &get_resolved_expr(*expr_node)->const_val; - // if (!target_const_val->ok) { - // return expr_type; - // } - // ConstExprValue *const_val = &get_resolved_expr(node)->const_val; - // const_val->ok = true; - // const_val->depends_on_compile_var = target_const_val->depends_on_compile_var; - // bignum_negate(&const_val->data.x_bignum, &target_const_val->data.x_bignum); - // if (expr_type->id == TypeTableEntryIdFloat || - // expr_type->id == TypeTableEntryIdNumLitFloat || - // expr_type->id == TypeTableEntryIdNumLitInt) - // { - // return expr_type; - // } - - // bool overflow = !bignum_fits_in_bits(&const_val->data.x_bignum, - // expr_type->data.integral.bit_count, expr_type->data.integral.is_signed); - // if (prefix_op == PrefixOpNegationWrap) { - // if (overflow) { - // const_val->data.x_bignum.is_negative = true; - // } - // } else if (overflow) { - // add_node_error(g, *expr_node, buf_sprintf("negation caused overflow")); - // return g->builtin_types.entry_invalid; - // } - // return expr_type; - // } else { - // const char *fmt = (prefix_op == PrefixOpNegationWrap) ? - // "invalid wrapping negation type: '%s'" : "invalid negation type: '%s'"; - // add_node_error(g, node, buf_sprintf(fmt, buf_ptr(&expr_type->name))); - // return g->builtin_types.entry_invalid; - // } - //} + return ir_analyze_negation(ira, un_op_instruction); case IrUnOpAddressOf: case IrUnOpConstAddressOf: return ir_analyze_unary_address_of(ira, un_op_instruction, op_id == IrUnOpConstAddressOf); @@ -6575,7 +6616,7 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira, IrInstructionContainerInitList *instruction) { IrInstruction *container_type_value = instruction->container_type->other; TypeTableEntry *container_type = ir_resolve_type(ira, container_type_value); - if (!container_type) + if (container_type->id == TypeTableEntryIdInvalid) return ira->codegen->builtin_types.entry_invalid; size_t elem_count = instruction->item_count; @@ -6661,7 +6702,7 @@ static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira static TypeTableEntry *ir_analyze_instruction_container_init_fields(IrAnalyze *ira, IrInstructionContainerInitFields *instruction) { IrInstruction *container_type_value = instruction->container_type->other; TypeTableEntry *container_type = ir_resolve_type(ira, container_type_value); - if (!container_type) + if (container_type->id == TypeTableEntryIdInvalid) return ira->codegen->builtin_types.entry_invalid; bool depends_on_compile_var = container_type_value->static_value.depends_on_compile_var; @@ -6670,6 +6711,77 @@ static TypeTableEntry *ir_analyze_instruction_container_init_fields(IrAnalyze *i instruction->field_count, instruction->fields, depends_on_compile_var); } +static TypeTableEntry *ir_analyze_min_max(IrAnalyze *ira, IrInstruction *source_instruction, + IrInstruction *target_type_value, bool is_max) +{ + TypeTableEntry *target_type = ir_resolve_type(ira, target_type_value); + bool depends_on_compile_var = target_type_value->static_value.depends_on_compile_var; + switch (target_type->id) { + case TypeTableEntryIdInvalid: + return ira->codegen->builtin_types.entry_invalid; + case TypeTableEntryIdInt: + { + ConstExprValue *out_val = ir_build_const_from(ira, source_instruction, depends_on_compile_var); + eval_min_max_value(ira->codegen, target_type, out_val, is_max); + return ira->codegen->builtin_types.entry_num_lit_int; + } + case TypeTableEntryIdFloat: + { + ConstExprValue *out_val = ir_build_const_from(ira, source_instruction, depends_on_compile_var); + eval_min_max_value(ira->codegen, target_type, out_val, is_max); + return ira->codegen->builtin_types.entry_num_lit_float; + } + case TypeTableEntryIdBool: + case TypeTableEntryIdVoid: + { + ConstExprValue *out_val = ir_build_const_from(ira, source_instruction, depends_on_compile_var); + eval_min_max_value(ira->codegen, target_type, out_val, is_max); + return target_type; + } + case TypeTableEntryIdVar: + case TypeTableEntryIdMetaType: + case TypeTableEntryIdUnreachable: + case TypeTableEntryIdPointer: + case TypeTableEntryIdArray: + case TypeTableEntryIdStruct: + case TypeTableEntryIdNumLitFloat: + case TypeTableEntryIdNumLitInt: + case TypeTableEntryIdUndefLit: + case TypeTableEntryIdNullLit: + case TypeTableEntryIdMaybe: + case TypeTableEntryIdErrorUnion: + case TypeTableEntryIdPureError: + case TypeTableEntryIdEnum: + case TypeTableEntryIdUnion: + case TypeTableEntryIdFn: + case TypeTableEntryIdTypeDecl: + case TypeTableEntryIdNamespace: + case TypeTableEntryIdBlock: + case TypeTableEntryIdBoundFn: + { + const char *err_format = is_max ? + "no max value available for type '%s'" : + "no min value available for type '%s'"; + ir_add_error(ira, source_instruction, + buf_sprintf(err_format, buf_ptr(&target_type->name))); + return ira->codegen->builtin_types.entry_invalid; + } + } + zig_unreachable(); +} + +static TypeTableEntry *ir_analyze_instruction_min_value(IrAnalyze *ira, + IrInstructionMinValue *instruction) +{ + return ir_analyze_min_max(ira, &instruction->base, instruction->value->other, false); +} + +static TypeTableEntry *ir_analyze_instruction_max_value(IrAnalyze *ira, + IrInstructionMaxValue *instruction) +{ + return ir_analyze_min_max(ira, &instruction->base, instruction->value->other, true); +} + static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { switch (instruction->id) { case IrInstructionIdInvalid: @@ -6754,6 +6866,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi return ir_analyze_instruction_container_init_list(ira, (IrInstructionContainerInitList *)instruction); case IrInstructionIdContainerInitFields: return ir_analyze_instruction_container_init_fields(ira, (IrInstructionContainerInitFields *)instruction); + case IrInstructionIdMinValue: + return ir_analyze_instruction_min_value(ira, (IrInstructionMinValue *)instruction); + case IrInstructionIdMaxValue: + return ir_analyze_instruction_max_value(ira, (IrInstructionMaxValue *)instruction); case IrInstructionIdCast: case IrInstructionIdStructFieldPtr: case IrInstructionIdEnumFieldPtr: @@ -6880,6 +6996,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdEnumTag: case IrInstructionIdStaticEval: case IrInstructionIdRef: + case IrInstructionIdMinValue: + case IrInstructionIdMaxValue: return false; case IrInstructionIdAsm: { @@ -6892,32 +7010,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { // TODO port over all this commented out code into new IR way of doing things -//static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *import, BlockContext *context, -// AstNode *node, const char *err_format, bool is_max) -//{ -// assert(node->type == NodeTypeFnCallExpr); -// assert(node->data.fn_call_expr.params.length == 1); -// -// 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 g->builtin_types.entry_invalid; -// } else if (type_entry->id == TypeTableEntryIdInt) { -// eval_min_max_value(g, type_entry, &get_resolved_expr(node)->const_val, is_max); -// return g->builtin_types.entry_num_lit_int; -// } else if (type_entry->id == TypeTableEntryIdFloat) { -// eval_min_max_value(g, type_entry, &get_resolved_expr(node)->const_val, is_max); -// return g->builtin_types.entry_num_lit_float; -// } else if (type_entry->id == TypeTableEntryIdBool) { -// eval_min_max_value(g, type_entry, &get_resolved_expr(node)->const_val, is_max); -// return type_entry; -// } else { -// add_node_error(g, node, -// buf_sprintf(err_format, buf_ptr(&type_entry->name))); -// return g->builtin_types.entry_invalid; -// } -//} //static TypeTableEntry *analyze_c_import(CodeGen *g, ImportTableEntry *parent_import, // BlockContext *parent_context, AstNode *node) @@ -7393,12 +7485,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { // align_in_bytes, false); // } // } -// case BuiltinFnIdMaxValue: -// return analyze_min_max_value(g, import, context, node, -// "no max value available for type '%s'", true); -// case BuiltinFnIdMinValue: -// return analyze_min_max_value(g, import, context, node, -// "no min value available for type '%s'", false); // case BuiltinFnIdMemberCount: // { // AstNode *type_node = node->data.fn_call_expr.params.at(0); diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 16a0ae3c78..8310cdf636 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -658,6 +658,18 @@ static void ir_print_ref(IrPrint *irp, IrInstructionRef *instruction) { ir_print_other_instruction(irp, instruction->value); } +static void ir_print_min_value(IrPrint *irp, IrInstructionMinValue *instruction) { + fprintf(irp->f, "@minValue("); + ir_print_other_instruction(irp, instruction->value); + fprintf(irp->f, ")"); +} + +static void ir_print_max_value(IrPrint *irp, IrInstructionMaxValue *instruction) { + fprintf(irp->f, "@maxValue("); + ir_print_other_instruction(irp, instruction->value); + fprintf(irp->f, ")"); +} + static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { ir_print_prefix(irp, instruction); switch (instruction->id) { @@ -795,6 +807,12 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdRef: ir_print_ref(irp, (IrInstructionRef *)instruction); break; + case IrInstructionIdMinValue: + ir_print_min_value(irp, (IrInstructionMinValue *)instruction); + break; + case IrInstructionIdMaxValue: + ir_print_max_value(irp, (IrInstructionMaxValue *)instruction); + break; } fprintf(irp->f, "\n"); } |
