authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-12-07 01:23:38-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-12-07 01:23:38-05:00
log0ad580f001eb151d0feb7ad884e237b237220800
tree79eee5e187dfb183113187d88360446941cc3791
parent5e4ee659a6796f7cc327c5e1cf1e10b1c032e85e

IR: add minValue, maxValue, and negation


6 files changed, 239 insertions(+), 82 deletions(-)

src/all_types.hpp+14
......@@ -1393,6 +1393,8 @@ enum IrInstructionId {
13931393 IrInstructionIdImport,
13941394 IrInstructionIdArrayLen,
13951395 IrInstructionIdRef,
1396 IrInstructionIdMinValue,
1397 IrInstructionIdMaxValue,
13961398};
13971399
13981400struct IrInstruction {
......@@ -1791,6 +1793,18 @@ struct IrInstructionRef {
17911793 LLVMValueRef tmp_ptr;
17921794};
17931795
1796struct IrInstructionMinValue {
1797 IrInstruction base;
1798
1799 IrInstruction *value;
1800};
1801
1802struct IrInstructionMaxValue {
1803 IrInstruction base;
1804
1805 IrInstruction *value;
1806};
1807
17941808enum LValPurpose {
17951809 LValPurposeNone,
17961810 LValPurposeAssign,
src/codegen.cpp+2
......@@ -1821,6 +1821,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
18211821 case IrInstructionIdStaticEval:
18221822 case IrInstructionIdImport:
18231823 case IrInstructionIdContainerInitFields:
1824 case IrInstructionIdMinValue:
1825 case IrInstructionIdMaxValue:
18241826 zig_unreachable();
18251827 case IrInstructionIdReturn:
18261828 return ir_render_return(g, executable, (IrInstructionReturn *)instruction);
src/eval.cpp+2
......@@ -431,6 +431,8 @@ void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *
431431 } else if (type_entry->id == TypeTableEntryIdBool) {
432432 const_val->special = ConstValSpecialStatic;
433433 const_val->data.x_bool = is_max;
434 } else if (type_entry->id == TypeTableEntryIdVoid) {
435 // nothing to do
434436 } else {
435437 zig_unreachable();
436438 }
src/ir.cpp+168-82
......@@ -306,6 +306,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionStructInit *) {
306306 return IrInstructionIdStructInit;
307307}
308308
309static constexpr IrInstructionId ir_instruction_id(IrInstructionMinValue *) {
310 return IrInstructionIdMinValue;
311}
312
313static constexpr IrInstructionId ir_instruction_id(IrInstructionMaxValue *) {
314 return IrInstructionIdMaxValue;
315}
316
309317template<typename T>
310318static T *ir_create_instruction(IrExecutable *exec, Scope *scope, AstNode *source_node) {
311319 T *special_instruction = allocate<T>(1);
......@@ -1241,6 +1249,25 @@ static IrInstruction *ir_build_ref_from(IrBuilder *irb, IrInstruction *old_instr
12411249 return new_instruction;
12421250}
12431251
1252static IrInstruction *ir_build_min_value(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) {
1253 IrInstructionMinValue *instruction = ir_build_instruction<IrInstructionMinValue>(irb, scope, source_node);
1254 instruction->value = value;
1255
1256 ir_ref_instruction(value);
1257
1258 return &instruction->base;
1259}
1260
1261static IrInstruction *ir_build_max_value(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) {
1262 IrInstructionMaxValue *instruction = ir_build_instruction<IrInstructionMaxValue>(irb, scope, source_node);
1263 instruction->value = value;
1264
1265 ir_ref_instruction(value);
1266
1267 return &instruction->base;
1268}
1269
1270
12441271static void ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope,
12451272 bool gen_error_defers, bool gen_maybe_defers)
12461273{
......@@ -1879,11 +1906,27 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
18791906
18801907 return ir_build_import(irb, scope, node, arg0_value);
18811908 }
1909 case BuiltinFnIdMaxValue:
1910 {
1911 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
1912 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
1913 if (arg0_value == irb->codegen->invalid_instruction)
1914 return arg0_value;
1915
1916 return ir_build_max_value(irb, scope, node, arg0_value);
1917 }
1918 case BuiltinFnIdMinValue:
1919 {
1920 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
1921 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
1922 if (arg0_value == irb->codegen->invalid_instruction)
1923 return arg0_value;
1924
1925 return ir_build_min_value(irb, scope, node, arg0_value);
1926 }
18821927 case BuiltinFnIdMemcpy:
18831928 case BuiltinFnIdMemset:
18841929 case BuiltinFnIdAlignof:
1885 case BuiltinFnIdMaxValue:
1886 case BuiltinFnIdMinValue:
18871930 case BuiltinFnIdMemberCount:
18881931 case BuiltinFnIdAddWithOverflow:
18891932 case BuiltinFnIdSubWithOverflow:
......@@ -4670,7 +4713,7 @@ static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstruction
46704713 if (is_inline || fn_ref->static_value.special != ConstValSpecialRuntime) {
46714714 if (fn_ref->type_entry->id == TypeTableEntryIdMetaType) {
46724715 TypeTableEntry *dest_type = ir_resolve_type(ira, fn_ref);
4673 if (!dest_type)
4716 if (dest_type->id == TypeTableEntryIdInvalid)
46744717 return ira->codegen->builtin_types.entry_invalid;
46754718
46764719 size_t actual_param_count = call_instruction->arg_count;
......@@ -4958,6 +5001,48 @@ static TypeTableEntry *ir_analyze_unwrap_maybe(IrAnalyze *ira, IrInstructionUnOp
49585001 }
49595002}
49605003
5004static TypeTableEntry *ir_analyze_negation(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) {
5005 IrInstruction *value = un_op_instruction->value->other;
5006 TypeTableEntry *expr_type = value->type_entry;
5007 if (expr_type->id == TypeTableEntryIdInvalid)
5008 return ira->codegen->builtin_types.entry_invalid;
5009
5010 bool is_wrap_op = (un_op_instruction->op_id == IrUnOpNegationWrap);
5011
5012 if ((expr_type->id == TypeTableEntryIdInt && expr_type->data.integral.is_signed) ||
5013 expr_type->id == TypeTableEntryIdNumLitInt ||
5014 ((expr_type->id == TypeTableEntryIdFloat || expr_type->id == TypeTableEntryIdNumLitFloat) &&
5015 !is_wrap_op))
5016 {
5017 ConstExprValue *target_const_val = &value->static_value;
5018 if (target_const_val->special != ConstValSpecialRuntime) {
5019 bool depends_on_compile_var = value->static_value.depends_on_compile_var;
5020 ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base, depends_on_compile_var);
5021 bignum_negate(&out_val->data.x_bignum, &target_const_val->data.x_bignum);
5022 if (expr_type->id == TypeTableEntryIdFloat ||
5023 expr_type->id == TypeTableEntryIdNumLitFloat ||
5024 expr_type->id == TypeTableEntryIdNumLitInt)
5025 {
5026 return expr_type;
5027 }
5028
5029 bool overflow = !bignum_fits_in_bits(&out_val->data.x_bignum, expr_type->data.integral.bit_count, true);
5030 if (is_wrap_op) {
5031 if (overflow)
5032 out_val->data.x_bignum.is_negative = true;
5033 } else if (overflow) {
5034 ir_add_error(ira, &un_op_instruction->base, buf_sprintf("negation caused overflow"));
5035 return ira->codegen->builtin_types.entry_invalid;
5036 }
5037 return expr_type;
5038 }
5039 }
5040
5041 const char *fmt = is_wrap_op ? "invalid wrapping negation type: '%s'" : "invalid negation type: '%s'";
5042 ir_add_error(ira, &un_op_instruction->base, buf_sprintf(fmt, buf_ptr(&expr_type->name)));
5043 return ira->codegen->builtin_types.entry_invalid;
5044}
5045
49615046static TypeTableEntry *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) {
49625047 IrUnOp op_id = un_op_instruction->op_id;
49635048 switch (op_id) {
......@@ -4983,51 +5068,7 @@ static TypeTableEntry *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstructio
49835068 //}
49845069 case IrUnOpNegation:
49855070 case IrUnOpNegationWrap:
4986 zig_panic("TODO analyze PrefixOpNegation[Wrap]");
4987 //{
4988 // TypeTableEntry *expr_type = analyze_expression(g, import, context, nullptr, *expr_node);
4989 // if (expr_type->id == TypeTableEntryIdInvalid) {
4990 // return expr_type;
4991 // } else if ((expr_type->id == TypeTableEntryIdInt &&
4992 // expr_type->data.integral.is_signed) ||
4993 // expr_type->id == TypeTableEntryIdNumLitInt ||
4994 // ((expr_type->id == TypeTableEntryIdFloat ||
4995 // expr_type->id == TypeTableEntryIdNumLitFloat) &&
4996 // prefix_op != PrefixOpNegationWrap))
4997 // {
4998 // ConstExprValue *target_const_val = &get_resolved_expr(*expr_node)->const_val;
4999 // if (!target_const_val->ok) {
5000 // return expr_type;
5001 // }
5002 // ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
5003 // const_val->ok = true;
5004 // const_val->depends_on_compile_var = target_const_val->depends_on_compile_var;
5005 // bignum_negate(&const_val->data.x_bignum, &target_const_val->data.x_bignum);
5006 // if (expr_type->id == TypeTableEntryIdFloat ||
5007 // expr_type->id == TypeTableEntryIdNumLitFloat ||
5008 // expr_type->id == TypeTableEntryIdNumLitInt)
5009 // {
5010 // return expr_type;
5011 // }
5012
5013 // bool overflow = !bignum_fits_in_bits(&const_val->data.x_bignum,
5014 // expr_type->data.integral.bit_count, expr_type->data.integral.is_signed);
5015 // if (prefix_op == PrefixOpNegationWrap) {
5016 // if (overflow) {
5017 // const_val->data.x_bignum.is_negative = true;
5018 // }
5019 // } else if (overflow) {
5020 // add_node_error(g, *expr_node, buf_sprintf("negation caused overflow"));
5021 // return g->builtin_types.entry_invalid;
5022 // }
5023 // return expr_type;
5024 // } else {
5025 // const char *fmt = (prefix_op == PrefixOpNegationWrap) ?
5026 // "invalid wrapping negation type: '%s'" : "invalid negation type: '%s'";
5027 // add_node_error(g, node, buf_sprintf(fmt, buf_ptr(&expr_type->name)));
5028 // return g->builtin_types.entry_invalid;
5029 // }
5030 //}
5071 return ir_analyze_negation(ira, un_op_instruction);
50315072 case IrUnOpAddressOf:
50325073 case IrUnOpConstAddressOf:
50335074 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
65756616static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira, IrInstructionContainerInitList *instruction) {
65766617 IrInstruction *container_type_value = instruction->container_type->other;
65776618 TypeTableEntry *container_type = ir_resolve_type(ira, container_type_value);
6578 if (!container_type)
6619 if (container_type->id == TypeTableEntryIdInvalid)
65796620 return ira->codegen->builtin_types.entry_invalid;
65806621
65816622 size_t elem_count = instruction->item_count;
......@@ -6661,7 +6702,7 @@ static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira
66616702static TypeTableEntry *ir_analyze_instruction_container_init_fields(IrAnalyze *ira, IrInstructionContainerInitFields *instruction) {
66626703 IrInstruction *container_type_value = instruction->container_type->other;
66636704 TypeTableEntry *container_type = ir_resolve_type(ira, container_type_value);
6664 if (!container_type)
6705 if (container_type->id == TypeTableEntryIdInvalid)
66656706 return ira->codegen->builtin_types.entry_invalid;
66666707
66676708 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
66706711 instruction->field_count, instruction->fields, depends_on_compile_var);
66716712}
66726713
6714static TypeTableEntry *ir_analyze_min_max(IrAnalyze *ira, IrInstruction *source_instruction,
6715 IrInstruction *target_type_value, bool is_max)
6716{
6717 TypeTableEntry *target_type = ir_resolve_type(ira, target_type_value);
6718 bool depends_on_compile_var = target_type_value->static_value.depends_on_compile_var;
6719 switch (target_type->id) {
6720 case TypeTableEntryIdInvalid:
6721 return ira->codegen->builtin_types.entry_invalid;
6722 case TypeTableEntryIdInt:
6723 {
6724 ConstExprValue *out_val = ir_build_const_from(ira, source_instruction, depends_on_compile_var);
6725 eval_min_max_value(ira->codegen, target_type, out_val, is_max);
6726 return ira->codegen->builtin_types.entry_num_lit_int;
6727 }
6728 case TypeTableEntryIdFloat:
6729 {
6730 ConstExprValue *out_val = ir_build_const_from(ira, source_instruction, depends_on_compile_var);
6731 eval_min_max_value(ira->codegen, target_type, out_val, is_max);
6732 return ira->codegen->builtin_types.entry_num_lit_float;
6733 }
6734 case TypeTableEntryIdBool:
6735 case TypeTableEntryIdVoid:
6736 {
6737 ConstExprValue *out_val = ir_build_const_from(ira, source_instruction, depends_on_compile_var);
6738 eval_min_max_value(ira->codegen, target_type, out_val, is_max);
6739 return target_type;
6740 }
6741 case TypeTableEntryIdVar:
6742 case TypeTableEntryIdMetaType:
6743 case TypeTableEntryIdUnreachable:
6744 case TypeTableEntryIdPointer:
6745 case TypeTableEntryIdArray:
6746 case TypeTableEntryIdStruct:
6747 case TypeTableEntryIdNumLitFloat:
6748 case TypeTableEntryIdNumLitInt:
6749 case TypeTableEntryIdUndefLit:
6750 case TypeTableEntryIdNullLit:
6751 case TypeTableEntryIdMaybe:
6752 case TypeTableEntryIdErrorUnion:
6753 case TypeTableEntryIdPureError:
6754 case TypeTableEntryIdEnum:
6755 case TypeTableEntryIdUnion:
6756 case TypeTableEntryIdFn:
6757 case TypeTableEntryIdTypeDecl:
6758 case TypeTableEntryIdNamespace:
6759 case TypeTableEntryIdBlock:
6760 case TypeTableEntryIdBoundFn:
6761 {
6762 const char *err_format = is_max ?
6763 "no max value available for type '%s'" :
6764 "no min value available for type '%s'";
6765 ir_add_error(ira, source_instruction,
6766 buf_sprintf(err_format, buf_ptr(&target_type->name)));
6767 return ira->codegen->builtin_types.entry_invalid;
6768 }
6769 }
6770 zig_unreachable();
6771}
6772
6773static TypeTableEntry *ir_analyze_instruction_min_value(IrAnalyze *ira,
6774 IrInstructionMinValue *instruction)
6775{
6776 return ir_analyze_min_max(ira, &instruction->base, instruction->value->other, false);
6777}
6778
6779static TypeTableEntry *ir_analyze_instruction_max_value(IrAnalyze *ira,
6780 IrInstructionMaxValue *instruction)
6781{
6782 return ir_analyze_min_max(ira, &instruction->base, instruction->value->other, true);
6783}
6784
66736785static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
66746786 switch (instruction->id) {
66756787 case IrInstructionIdInvalid:
......@@ -6754,6 +6866,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
67546866 return ir_analyze_instruction_container_init_list(ira, (IrInstructionContainerInitList *)instruction);
67556867 case IrInstructionIdContainerInitFields:
67566868 return ir_analyze_instruction_container_init_fields(ira, (IrInstructionContainerInitFields *)instruction);
6869 case IrInstructionIdMinValue:
6870 return ir_analyze_instruction_min_value(ira, (IrInstructionMinValue *)instruction);
6871 case IrInstructionIdMaxValue:
6872 return ir_analyze_instruction_max_value(ira, (IrInstructionMaxValue *)instruction);
67576873 case IrInstructionIdCast:
67586874 case IrInstructionIdStructFieldPtr:
67596875 case IrInstructionIdEnumFieldPtr:
......@@ -6880,6 +6996,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
68806996 case IrInstructionIdEnumTag:
68816997 case IrInstructionIdStaticEval:
68826998 case IrInstructionIdRef:
6999 case IrInstructionIdMinValue:
7000 case IrInstructionIdMaxValue:
68837001 return false;
68847002 case IrInstructionIdAsm:
68857003 {
......@@ -6892,32 +7010,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
68927010
68937011// TODO port over all this commented out code into new IR way of doing things
68947012
6895//static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *import, BlockContext *context,
6896// AstNode *node, const char *err_format, bool is_max)
6897//{
6898// assert(node->type == NodeTypeFnCallExpr);
6899// assert(node->data.fn_call_expr.params.length == 1);
6900//
6901// AstNode *type_node = node->data.fn_call_expr.params.at(0);
6902// TypeTableEntry *type_entry = analyze_type_expr(g, import, context, type_node);
6903//
6904// if (type_entry->id == TypeTableEntryIdInvalid) {
6905// return g->builtin_types.entry_invalid;
6906// } else if (type_entry->id == TypeTableEntryIdInt) {
6907// eval_min_max_value(g, type_entry, &get_resolved_expr(node)->const_val, is_max);
6908// return g->builtin_types.entry_num_lit_int;
6909// } else if (type_entry->id == TypeTableEntryIdFloat) {
6910// eval_min_max_value(g, type_entry, &get_resolved_expr(node)->const_val, is_max);
6911// return g->builtin_types.entry_num_lit_float;
6912// } else if (type_entry->id == TypeTableEntryIdBool) {
6913// eval_min_max_value(g, type_entry, &get_resolved_expr(node)->const_val, is_max);
6914// return type_entry;
6915// } else {
6916// add_node_error(g, node,
6917// buf_sprintf(err_format, buf_ptr(&type_entry->name)));
6918// return g->builtin_types.entry_invalid;
6919// }
6920//}
69217013
69227014//static TypeTableEntry *analyze_c_import(CodeGen *g, ImportTableEntry *parent_import,
69237015// BlockContext *parent_context, AstNode *node)
......@@ -7393,12 +7485,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
73937485// align_in_bytes, false);
73947486// }
73957487// }
7396// case BuiltinFnIdMaxValue:
7397// return analyze_min_max_value(g, import, context, node,
7398// "no max value available for type '%s'", true);
7399// case BuiltinFnIdMinValue:
7400// return analyze_min_max_value(g, import, context, node,
7401// "no min value available for type '%s'", false);
74027488// case BuiltinFnIdMemberCount:
74037489// {
74047490// AstNode *type_node = node->data.fn_call_expr.params.at(0);
src/ir_print.cpp+18
......@@ -658,6 +658,18 @@ static void ir_print_ref(IrPrint *irp, IrInstructionRef *instruction) {
658658 ir_print_other_instruction(irp, instruction->value);
659659}
660660
661static void ir_print_min_value(IrPrint *irp, IrInstructionMinValue *instruction) {
662 fprintf(irp->f, "@minValue(");
663 ir_print_other_instruction(irp, instruction->value);
664 fprintf(irp->f, ")");
665}
666
667static void ir_print_max_value(IrPrint *irp, IrInstructionMaxValue *instruction) {
668 fprintf(irp->f, "@maxValue(");
669 ir_print_other_instruction(irp, instruction->value);
670 fprintf(irp->f, ")");
671}
672
661673static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
662674 ir_print_prefix(irp, instruction);
663675 switch (instruction->id) {
......@@ -795,6 +807,12 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
795807 case IrInstructionIdRef:
796808 ir_print_ref(irp, (IrInstructionRef *)instruction);
797809 break;
810 case IrInstructionIdMinValue:
811 ir_print_min_value(irp, (IrInstructionMinValue *)instruction);
812 break;
813 case IrInstructionIdMaxValue:
814 ir_print_max_value(irp, (IrInstructionMaxValue *)instruction);
815 break;
798816 }
799817 fprintf(irp->f, "\n");
800818}
test/self_hosted2.zig+35
......@@ -204,6 +204,39 @@ fn testStaticAddOne() {
204204 assert(should_be_1235 == 1235);
205205}
206206
207fn gimme1or2(inline a: bool) -> i32 {
208 const x: i32 = 1;
209 const y: i32 = 2;
210 inline var z: i32 = inline if (a) x else y;
211 return z;
212}
213
214fn testInlineVarsAgain() {
215 assert(gimme1or2(true) == 1);
216 assert(gimme1or2(false) == 2);
217}
218
219fn testMinValueAndMaxValue() {
220 assert(@maxValue(u8) == 255);
221 assert(@maxValue(u16) == 65535);
222 assert(@maxValue(u32) == 4294967295);
223 assert(@maxValue(u64) == 18446744073709551615);
224
225 assert(@maxValue(i8) == 127);
226 assert(@maxValue(i16) == 32767);
227 assert(@maxValue(i32) == 2147483647);
228 assert(@maxValue(i64) == 9223372036854775807);
229
230 assert(@minValue(u8) == 0);
231 assert(@minValue(u16) == 0);
232 assert(@minValue(u32) == 0);
233 assert(@minValue(u64) == 0);
234
235 assert(@minValue(i8) == -128);
236 assert(@minValue(i16) == -32768);
237 assert(@minValue(i32) == -2147483648);
238 assert(@minValue(i64) == -9223372036854775808);
239}
207240
208241fn assert(ok: bool) {
209242 if (!ok)
......@@ -228,6 +261,8 @@ fn runAllTests() {
228261 shortCircuit();
229262 testGotoLeaveDeferScope(true);
230263 testStaticAddOne();
264 testInlineVarsAgain();
265 testMinValueAndMaxValue();
231266}
232267
233268export nakedcc fn _start() -> unreachable {