| ... | @@ -99,14 +99,78 @@ static bool eval_bool_bin_op_bool(bool a, BinOpType bin_op, bool b) { | ... | @@ -99,14 +99,78 @@ static bool eval_bool_bin_op_bool(bool a, BinOpType bin_op, bool b) { |
| 99 | } | 99 | } |
| 100 | } | 100 | } |
| 101 | | 101 | |
| | 102 | static uint64_t max_unsigned_val(TypeTableEntry *type_entry) { |
| | 103 | assert(type_entry->id == TypeTableEntryIdInt); |
| | 104 | if (type_entry->data.integral.bit_count == 64) { |
| | 105 | return UINT64_MAX; |
| | 106 | } else if (type_entry->data.integral.bit_count == 32) { |
| | 107 | return UINT32_MAX; |
| | 108 | } else if (type_entry->data.integral.bit_count == 16) { |
| | 109 | return UINT16_MAX; |
| | 110 | } else if (type_entry->data.integral.bit_count == 8) { |
| | 111 | return UINT8_MAX; |
| | 112 | } else { |
| | 113 | zig_unreachable(); |
| | 114 | } |
| | 115 | } |
| | 116 | |
| | 117 | static int64_t max_signed_val(TypeTableEntry *type_entry) { |
| | 118 | assert(type_entry->id == TypeTableEntryIdInt); |
| | 119 | if (type_entry->data.integral.bit_count == 64) { |
| | 120 | return INT64_MAX; |
| | 121 | } else if (type_entry->data.integral.bit_count == 32) { |
| | 122 | return INT32_MAX; |
| | 123 | } else if (type_entry->data.integral.bit_count == 16) { |
| | 124 | return INT16_MAX; |
| | 125 | } else if (type_entry->data.integral.bit_count == 8) { |
| | 126 | return INT8_MAX; |
| | 127 | } else { |
| | 128 | zig_unreachable(); |
| | 129 | } |
| | 130 | } |
| | 131 | |
| | 132 | static int64_t min_signed_val(TypeTableEntry *type_entry) { |
| | 133 | assert(type_entry->id == TypeTableEntryIdInt); |
| | 134 | if (type_entry->data.integral.bit_count == 64) { |
| | 135 | return INT64_MIN; |
| | 136 | } else if (type_entry->data.integral.bit_count == 32) { |
| | 137 | return INT32_MIN; |
| | 138 | } else if (type_entry->data.integral.bit_count == 16) { |
| | 139 | return INT16_MIN; |
| | 140 | } else if (type_entry->data.integral.bit_count == 8) { |
| | 141 | return INT8_MIN; |
| | 142 | } else { |
| | 143 | zig_unreachable(); |
| | 144 | } |
| | 145 | } |
| | 146 | |
| 102 | static int eval_const_expr_bin_op_bignum(ConstExprValue *op1_val, ConstExprValue *op2_val, | 147 | static int eval_const_expr_bin_op_bignum(ConstExprValue *op1_val, ConstExprValue *op2_val, |
| 103 | ConstExprValue *out_val, bool (*bignum_fn)(BigNum *, BigNum *, BigNum *)) | 148 | ConstExprValue *out_val, bool (*bignum_fn)(BigNum *, BigNum *, BigNum *), |
| | 149 | TypeTableEntry *type) |
| 104 | { | 150 | { |
| 105 | bool overflow = bignum_fn(&out_val->data.x_bignum, &op1_val->data.x_bignum, &op2_val->data.x_bignum); | 151 | bool overflow = bignum_fn(&out_val->data.x_bignum, &op1_val->data.x_bignum, &op2_val->data.x_bignum); |
| 106 | if (overflow) { | 152 | if (overflow) { |
| 107 | return ErrorOverflow; | 153 | return ErrorOverflow; |
| 108 | } | 154 | } |
| 109 | | 155 | |
| | 156 | if (type->id == TypeTableEntryIdInt && !bignum_fits_in_bits(&out_val->data.x_bignum, |
| | 157 | type->data.integral.bit_count, type->data.integral.is_signed)) |
| | 158 | { |
| | 159 | if (type->data.integral.is_wrapping) { |
| | 160 | if (type->data.integral.is_signed) { |
| | 161 | out_val->data.x_bignum.data.x_uint = max_unsigned_val(type) - out_val->data.x_bignum.data.x_uint + 1; |
| | 162 | out_val->data.x_bignum.is_negative = !out_val->data.x_bignum.is_negative; |
| | 163 | } else if (out_val->data.x_bignum.is_negative) { |
| | 164 | out_val->data.x_bignum.data.x_uint = max_unsigned_val(type) - out_val->data.x_bignum.data.x_uint + 1; |
| | 165 | out_val->data.x_bignum.is_negative = false; |
| | 166 | } else { |
| | 167 | bignum_truncate(&out_val->data.x_bignum, type->data.integral.bit_count); |
| | 168 | } |
| | 169 | } else { |
| | 170 | return ErrorOverflow; |
| | 171 | } |
| | 172 | } |
| | 173 | |
| 110 | out_val->ok = true; | 174 | out_val->ok = true; |
| 111 | out_val->depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var; | 175 | out_val->depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var; |
| 112 | return 0; | 176 | return 0; |
| ... | @@ -117,6 +181,8 @@ int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type, | ... | @@ -117,6 +181,8 @@ int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type, |
| 117 | { | 181 | { |
| 118 | assert(op1_val->ok); | 182 | assert(op1_val->ok); |
| 119 | assert(op2_val->ok); | 183 | assert(op2_val->ok); |
| | 184 | assert(op1_type->id != TypeTableEntryIdInvalid); |
| | 185 | assert(op2_type->id != TypeTableEntryIdInvalid); |
| 120 | | 186 | |
| 121 | switch (bin_op) { | 187 | switch (bin_op) { |
| 122 | case BinOpTypeAssign: | 188 | case BinOpTypeAssign: |
| ... | @@ -132,8 +198,7 @@ int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type, | ... | @@ -132,8 +198,7 @@ int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type, |
| 132 | case BinOpTypeAssignBitOr: | 198 | case BinOpTypeAssignBitOr: |
| 133 | case BinOpTypeAssignBoolAnd: | 199 | case BinOpTypeAssignBoolAnd: |
| 134 | case BinOpTypeAssignBoolOr: | 200 | case BinOpTypeAssignBoolOr: |
| 135 | out_val->ok = true; | 201 | zig_unreachable(); |
| 136 | return 0; | | |
| 137 | case BinOpTypeBoolOr: | 202 | case BinOpTypeBoolOr: |
| 138 | case BinOpTypeBoolAnd: | 203 | case BinOpTypeBoolAnd: |
| 139 | assert(op1_type->id == TypeTableEntryIdBool); | 204 | assert(op1_type->id == TypeTableEntryIdBool); |
| ... | @@ -191,21 +256,21 @@ int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type, | ... | @@ -191,21 +256,21 @@ int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type, |
| 191 | return 0; | 256 | return 0; |
| 192 | } | 257 | } |
| 193 | case BinOpTypeAdd: | 258 | case BinOpTypeAdd: |
| 194 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_add); | 259 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_add, op1_type); |
| 195 | case BinOpTypeBinOr: | 260 | case BinOpTypeBinOr: |
| 196 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_or); | 261 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_or, op1_type); |
| 197 | case BinOpTypeBinXor: | 262 | case BinOpTypeBinXor: |
| 198 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_xor); | 263 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_xor, op1_type); |
| 199 | case BinOpTypeBinAnd: | 264 | case BinOpTypeBinAnd: |
| 200 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_and); | 265 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_and, op1_type); |
| 201 | case BinOpTypeBitShiftLeft: | 266 | case BinOpTypeBitShiftLeft: |
| 202 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_shl); | 267 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_shl, op1_type); |
| 203 | case BinOpTypeBitShiftRight: | 268 | case BinOpTypeBitShiftRight: |
| 204 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_shr); | 269 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_shr, op1_type); |
| 205 | case BinOpTypeSub: | 270 | case BinOpTypeSub: |
| 206 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_sub); | 271 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_sub, op1_type); |
| 207 | case BinOpTypeMult: | 272 | case BinOpTypeMult: |
| 208 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_mul); | 273 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_mul, op1_type); |
| 209 | case BinOpTypeDiv: | 274 | case BinOpTypeDiv: |
| 210 | { | 275 | { |
| 211 | bool is_int = false; | 276 | bool is_int = false; |
| ... | @@ -224,11 +289,11 @@ int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type, | ... | @@ -224,11 +289,11 @@ int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type, |
| 224 | { | 289 | { |
| 225 | return ErrorDivByZero; | 290 | return ErrorDivByZero; |
| 226 | } else { | 291 | } else { |
| 227 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_div); | 292 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_div, op1_type); |
| 228 | } | 293 | } |
| 229 | } | 294 | } |
| 230 | case BinOpTypeMod: | 295 | case BinOpTypeMod: |
| 231 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_mod); | 296 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_mod, op1_type); |
| 232 | case BinOpTypeUnwrapMaybe: | 297 | case BinOpTypeUnwrapMaybe: |
| 233 | zig_panic("TODO"); | 298 | zig_panic("TODO"); |
| 234 | case BinOpTypeStrCat: | 299 | case BinOpTypeStrCat: |
| ... | @@ -244,18 +309,61 @@ static bool eval_bin_op_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) | ... | @@ -244,18 +309,61 @@ static bool eval_bin_op_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) |
| 244 | | 309 | |
| 245 | AstNode *op1 = node->data.bin_op_expr.op1; | 310 | AstNode *op1 = node->data.bin_op_expr.op1; |
| 246 | AstNode *op2 = node->data.bin_op_expr.op2; | 311 | AstNode *op2 = node->data.bin_op_expr.op2; |
| | 312 | BinOpType bin_op = node->data.bin_op_expr.bin_op; |
| | 313 | |
| | 314 | switch (bin_op) { |
| | 315 | case BinOpTypeAssign: |
| | 316 | case BinOpTypeAssignTimes: |
| | 317 | case BinOpTypeAssignDiv: |
| | 318 | case BinOpTypeAssignMod: |
| | 319 | case BinOpTypeAssignPlus: |
| | 320 | case BinOpTypeAssignMinus: |
| | 321 | case BinOpTypeAssignBitShiftLeft: |
| | 322 | case BinOpTypeAssignBitShiftRight: |
| | 323 | case BinOpTypeAssignBitAnd: |
| | 324 | case BinOpTypeAssignBitXor: |
| | 325 | case BinOpTypeAssignBitOr: |
| | 326 | case BinOpTypeAssignBoolAnd: |
| | 327 | case BinOpTypeAssignBoolOr: |
| | 328 | zig_panic("TODO"); |
| | 329 | case BinOpTypeBoolOr: |
| | 330 | case BinOpTypeBoolAnd: |
| | 331 | case BinOpTypeCmpEq: |
| | 332 | case BinOpTypeCmpNotEq: |
| | 333 | case BinOpTypeCmpLessThan: |
| | 334 | case BinOpTypeCmpGreaterThan: |
| | 335 | case BinOpTypeCmpLessOrEq: |
| | 336 | case BinOpTypeCmpGreaterOrEq: |
| | 337 | case BinOpTypeBinOr: |
| | 338 | case BinOpTypeBinXor: |
| | 339 | case BinOpTypeBinAnd: |
| | 340 | case BinOpTypeBitShiftLeft: |
| | 341 | case BinOpTypeBitShiftRight: |
| | 342 | case BinOpTypeAdd: |
| | 343 | case BinOpTypeSub: |
| | 344 | case BinOpTypeMult: |
| | 345 | case BinOpTypeDiv: |
| | 346 | case BinOpTypeMod: |
| | 347 | case BinOpTypeUnwrapMaybe: |
| | 348 | case BinOpTypeStrCat: |
| | 349 | case BinOpTypeArrayMult: |
| | 350 | break; |
| | 351 | case BinOpTypeInvalid: |
| | 352 | zig_unreachable(); |
| | 353 | } |
| 247 | | 354 | |
| 248 | TypeTableEntry *op1_type = get_resolved_expr(op1)->type_entry; | 355 | TypeTableEntry *op1_type = get_resolved_expr(op1)->type_entry; |
| 249 | TypeTableEntry *op2_type = get_resolved_expr(op2)->type_entry; | 356 | TypeTableEntry *op2_type = get_resolved_expr(op2)->type_entry; |
| 250 | | 357 | |
| | 358 | assert(op1_type); |
| | 359 | assert(op2_type); |
| | 360 | |
| 251 | ConstExprValue op1_val = {0}; | 361 | ConstExprValue op1_val = {0}; |
| 252 | if (eval_expr(ef, op1, &op1_val)) return true; | 362 | if (eval_expr(ef, op1, &op1_val)) return true; |
| 253 | | 363 | |
| 254 | ConstExprValue op2_val = {0}; | 364 | ConstExprValue op2_val = {0}; |
| 255 | if (eval_expr(ef, op2, &op2_val)) return true; | 365 | if (eval_expr(ef, op2, &op2_val)) return true; |
| 256 | | 366 | |
| 257 | BinOpType bin_op = node->data.bin_op_expr.bin_op; | | |
| 258 | | | |
| 259 | int err; | 367 | int err; |
| 260 | if ((err = eval_const_expr_bin_op(&op1_val, op1_type, bin_op, &op2_val, op2_type, out_val))) { | 368 | if ((err = eval_const_expr_bin_op(&op1_val, op1_type, bin_op, &op2_val, op2_type, out_val))) { |
| 261 | ef->root->abort = true; | 369 | ef->root->abort = true; |
| ... | @@ -568,48 +676,15 @@ void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue * | ... | @@ -568,48 +676,15 @@ void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue * |
| 568 | const_val->depends_on_compile_var = int_type_depends_on_compile_var(g, type_entry); | 676 | const_val->depends_on_compile_var = int_type_depends_on_compile_var(g, type_entry); |
| 569 | if (is_max) { | 677 | if (is_max) { |
| 570 | if (type_entry->data.integral.is_signed) { | 678 | if (type_entry->data.integral.is_signed) { |
| 571 | int64_t val; | 679 | int64_t val = max_signed_val(type_entry); |
| 572 | if (type_entry->data.integral.bit_count == 64) { | | |
| 573 | val = INT64_MAX; | | |
| 574 | } else if (type_entry->data.integral.bit_count == 32) { | | |
| 575 | val = INT32_MAX; | | |
| 576 | } else if (type_entry->data.integral.bit_count == 16) { | | |
| 577 | val = INT16_MAX; | | |
| 578 | } else if (type_entry->data.integral.bit_count == 8) { | | |
| 579 | val = INT8_MAX; | | |
| 580 | } else { | | |
| 581 | zig_unreachable(); | | |
| 582 | } | | |
| 583 | bignum_init_signed(&const_val->data.x_bignum, val); | 680 | bignum_init_signed(&const_val->data.x_bignum, val); |
| 584 | } else { | 681 | } else { |
| 585 | uint64_t val; | 682 | uint64_t val = max_unsigned_val(type_entry); |
| 586 | if (type_entry->data.integral.bit_count == 64) { | | |
| 587 | val = UINT64_MAX; | | |
| 588 | } else if (type_entry->data.integral.bit_count == 32) { | | |
| 589 | val = UINT32_MAX; | | |
| 590 | } else if (type_entry->data.integral.bit_count == 16) { | | |
| 591 | val = UINT16_MAX; | | |
| 592 | } else if (type_entry->data.integral.bit_count == 8) { | | |
| 593 | val = UINT8_MAX; | | |
| 594 | } else { | | |
| 595 | zig_unreachable(); | | |
| 596 | } | | |
| 597 | bignum_init_unsigned(&const_val->data.x_bignum, val); | 683 | bignum_init_unsigned(&const_val->data.x_bignum, val); |
| 598 | } | 684 | } |
| 599 | } else { | 685 | } else { |
| 600 | if (type_entry->data.integral.is_signed) { | 686 | if (type_entry->data.integral.is_signed) { |
| 601 | int64_t val; | 687 | int64_t val = min_signed_val(type_entry); |
| 602 | if (type_entry->data.integral.bit_count == 64) { | | |
| 603 | val = INT64_MIN; | | |
| 604 | } else if (type_entry->data.integral.bit_count == 32) { | | |
| 605 | val = INT32_MIN; | | |
| 606 | } else if (type_entry->data.integral.bit_count == 16) { | | |
| 607 | val = INT16_MIN; | | |
| 608 | } else if (type_entry->data.integral.bit_count == 8) { | | |
| 609 | val = INT8_MIN; | | |
| 610 | } else { | | |
| 611 | zig_unreachable(); | | |
| 612 | } | | |
| 613 | bignum_init_signed(&const_val->data.x_bignum, val); | 688 | bignum_init_signed(&const_val->data.x_bignum, val); |
| 614 | } else { | 689 | } else { |
| 615 | bignum_init_unsigned(&const_val->data.x_bignum, 0); | 690 | bignum_init_unsigned(&const_val->data.x_bignum, 0); |
| ... | @@ -687,6 +762,8 @@ static bool eval_fn_call_builtin(EvalFn *ef, AstNode *node, ConstExprValue *out_ | ... | @@ -687,6 +762,8 @@ static bool eval_fn_call_builtin(EvalFn *ef, AstNode *node, ConstExprValue *out_ |
| 687 | return eval_fn_with_overflow(ef, node, out_val, bignum_add); | 762 | return eval_fn_with_overflow(ef, node, out_val, bignum_add); |
| 688 | case BuiltinFnIdSubWithOverflow: | 763 | case BuiltinFnIdSubWithOverflow: |
| 689 | return eval_fn_with_overflow(ef, node, out_val, bignum_sub); | 764 | return eval_fn_with_overflow(ef, node, out_val, bignum_sub); |
| | 765 | case BuiltinFnIdShlWithOverflow: |
| | 766 | return eval_fn_with_overflow(ef, node, out_val, bignum_shl); |
| 690 | case BuiltinFnIdFence: | 767 | case BuiltinFnIdFence: |
| 691 | return false; | 768 | return false; |
| 692 | case BuiltinFnIdMemcpy: | 769 | case BuiltinFnIdMemcpy: |
| ... | @@ -707,7 +784,6 @@ static bool eval_fn_call_builtin(EvalFn *ef, AstNode *node, ConstExprValue *out_ | ... | @@ -707,7 +784,6 @@ static bool eval_fn_call_builtin(EvalFn *ef, AstNode *node, ConstExprValue *out_ |
| 707 | case BuiltinFnIdErrName: | 784 | case BuiltinFnIdErrName: |
| 708 | case BuiltinFnIdEmbedFile: | 785 | case BuiltinFnIdEmbedFile: |
| 709 | case BuiltinFnIdCmpExchange: | 786 | case BuiltinFnIdCmpExchange: |
| 710 | case BuiltinFnIdShlWithOverflow: | | |
| 711 | zig_panic("TODO"); | 787 | zig_panic("TODO"); |
| 712 | case BuiltinFnIdBreakpoint: | 788 | case BuiltinFnIdBreakpoint: |
| 713 | case BuiltinFnIdInvalid: | 789 | case BuiltinFnIdInvalid: |
| ... | @@ -962,8 +1038,31 @@ static bool eval_prefix_op_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_v | ... | @@ -962,8 +1038,31 @@ static bool eval_prefix_op_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_v |
| 962 | out_val->ok = true; | 1038 | out_val->ok = true; |
| 963 | break; | 1039 | break; |
| 964 | } | 1040 | } |
| 965 | case PrefixOpBinNot: | | |
| 966 | case PrefixOpNegation: | 1041 | case PrefixOpNegation: |
| | 1042 | if (expr_type->id == TypeTableEntryIdInt) { |
| | 1043 | assert(expr_type->data.integral.is_signed); |
| | 1044 | bignum_negate(&out_val->data.x_bignum, &expr_val.data.x_bignum); |
| | 1045 | out_val->ok = true; |
| | 1046 | bool overflow = !bignum_fits_in_bits(&out_val->data.x_bignum, |
| | 1047 | expr_type->data.integral.bit_count, expr_type->data.integral.is_signed); |
| | 1048 | if (expr_type->data.integral.is_wrapping) { |
| | 1049 | if (overflow) { |
| | 1050 | out_val->data.x_bignum.is_negative = true; |
| | 1051 | } |
| | 1052 | } else if (overflow) { |
| | 1053 | ErrorMsg *msg = add_node_error(ef->root->codegen, ef->root->fn->fn_def_node, |
| | 1054 | buf_sprintf("function evaluation caused overflow")); |
| | 1055 | add_error_note(ef->root->codegen, msg, ef->root->call_node, buf_sprintf("called from here")); |
| | 1056 | add_error_note(ef->root->codegen, msg, node, buf_sprintf("overflow occurred here")); |
| | 1057 | return true; |
| | 1058 | } |
| | 1059 | } else if (expr_type->id == TypeTableEntryIdFloat) { |
| | 1060 | zig_panic("TODO"); |
| | 1061 | } else { |
| | 1062 | zig_unreachable(); |
| | 1063 | } |
| | 1064 | break; |
| | 1065 | case PrefixOpBinNot: |
| 967 | case PrefixOpMaybe: | 1066 | case PrefixOpMaybe: |
| 968 | case PrefixOpError: | 1067 | case PrefixOpError: |
| 969 | case PrefixOpUnwrapError: | 1068 | case PrefixOpUnwrapError: |