| author | |
| committer | |
| log | d1e68c3ca84844a96d4897c857861b40751965cc |
| tree | 8866451296719e1c1c0850bb31a213d081c22352 |
| parent | 3e8af78895d313f0706389da2ad7e5c60df95964 |
25 files changed, 2095 insertions(+), 1143 deletions(-)
.gitignore+1| ... | ... | @@ -7,3 +7,4 @@ build-llvm-debug/ |
| 7 | 7 | /.cproject |
| 8 | 8 | /.project |
| 9 | 9 | /.settings/ |
| 10 | build-llvm-debug/ |
CMakeLists.txt+2-1| ... | ... | @@ -44,7 +44,8 @@ include_directories( |
| 44 | 44 | set(ZIG_SOURCES |
| 45 | 45 | "${CMAKE_SOURCE_DIR}/src/analyze.cpp" |
| 46 | 46 | "${CMAKE_SOURCE_DIR}/src/ast_render.cpp" |
| 47 | "${CMAKE_SOURCE_DIR}/src/bignum.cpp" | |
| 47 | "${CMAKE_SOURCE_DIR}/src/bigfloat.cpp" | |
| 48 | "${CMAKE_SOURCE_DIR}/src/bigint.cpp" | |
| 48 | 49 | "${CMAKE_SOURCE_DIR}/src/buffer.cpp" |
| 49 | 50 | "${CMAKE_SOURCE_DIR}/src/c_tokenizer.cpp" |
| 50 | 51 | "${CMAKE_SOURCE_DIR}/src/codegen.cpp" |
doc/langref.md+1-1| ... | ... | @@ -143,7 +143,7 @@ StructLiteralField = "." Symbol "=" Expression |
| 143 | 143 | |
| 144 | 144 | PrefixOp = "!" | "-" | "~" | "*" | ("&" option("const") option("volatile")) | "?" | "%" | "%%" | "??" | "-%" |
| 145 | 145 | |
| 146 | PrimaryExpression = Number | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) | ContainerDecl | |
| 146 | PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) | ContainerDecl | |
| 147 | 147 | |
| 148 | 148 | ArrayType = "[" option(Expression) "]" option("const") TypeExpr |
| 149 | 149 |
src/all_types.hpp+20-7| ... | ... | @@ -13,7 +13,8 @@ |
| 13 | 13 | #include "zig_llvm.hpp" |
| 14 | 14 | #include "hash_map.hpp" |
| 15 | 15 | #include "errmsg.hpp" |
| 16 | #include "bignum.hpp" | |
| 16 | #include "bigint.hpp" | |
| 17 | #include "bigfloat.hpp" | |
| 17 | 18 | #include "target.hpp" |
| 18 | 19 | |
| 19 | 20 | struct AstNode; |
| ... | ... | @@ -215,6 +216,11 @@ struct ConstGlobalRefs { |
| 215 | 216 | LLVMValueRef llvm_global; |
| 216 | 217 | }; |
| 217 | 218 | |
| 219 | enum ConstNumLitKind { | |
| 220 | ConstNumLitKindInt, | |
| 221 | ConstNumLitKindFloat, | |
| 222 | }; | |
| 223 | ||
| 218 | 224 | struct ConstExprValue { |
| 219 | 225 | TypeTableEntry *type; |
| 220 | 226 | ConstValSpecial special; |
| ... | ... | @@ -222,7 +228,8 @@ struct ConstExprValue { |
| 222 | 228 | |
| 223 | 229 | union { |
| 224 | 230 | // populated if special == ConstValSpecialStatic |
| 225 | BigNum x_bignum; | |
| 231 | BigInt x_bigint; | |
| 232 | BigFloat x_bigfloat; | |
| 226 | 233 | bool x_bool; |
| 227 | 234 | ConstFn x_fn; |
| 228 | 235 | ConstBoundFnValue x_bound_fn; |
| ... | ... | @@ -347,7 +354,8 @@ enum NodeType { |
| 347 | 354 | NodeTypeTestDecl, |
| 348 | 355 | NodeTypeBinOpExpr, |
| 349 | 356 | NodeTypeUnwrapErrorExpr, |
| 350 | NodeTypeNumberLiteral, | |
| 357 | NodeTypeFloatLiteral, | |
| 358 | NodeTypeIntLiteral, | |
| 351 | 359 | NodeTypeStringLiteral, |
| 352 | 360 | NodeTypeCharLiteral, |
| 353 | 361 | NodeTypeSymbol, |
| ... | ... | @@ -748,14 +756,18 @@ struct AstNodeCharLiteral { |
| 748 | 756 | uint8_t value; |
| 749 | 757 | }; |
| 750 | 758 | |
| 751 | struct AstNodeNumberLiteral { | |
| 752 | BigNum *bignum; | |
| 759 | struct AstNodeFloatLiteral { | |
| 760 | BigFloat *bigfloat; | |
| 753 | 761 | |
| 754 | 762 | // overflow is true if when parsing the number, we discovered it would not |
| 755 | // fit without losing data in a uint64_t or double | |
| 763 | // fit without losing data in a double | |
| 756 | 764 | bool overflow; |
| 757 | 765 | }; |
| 758 | 766 | |
| 767 | struct AstNodeIntLiteral { | |
| 768 | BigInt *bigint; | |
| 769 | }; | |
| 770 | ||
| 759 | 771 | struct AstNodeStructValueField { |
| 760 | 772 | Buf *name; |
| 761 | 773 | AstNode *expr; |
| ... | ... | @@ -854,7 +866,8 @@ struct AstNode { |
| 854 | 866 | AstNodeStructField struct_field; |
| 855 | 867 | AstNodeStringLiteral string_literal; |
| 856 | 868 | AstNodeCharLiteral char_literal; |
| 857 | AstNodeNumberLiteral number_literal; | |
| 869 | AstNodeFloatLiteral float_literal; | |
| 870 | AstNodeIntLiteral int_literal; | |
| 858 | 871 | AstNodeContainerInitExpr container_init_expr; |
| 859 | 872 | AstNodeStructValueField struct_val_field; |
| 860 | 873 | AstNodeNullLiteral null_literal; |
src/analyze.cpp+58-76| ... | ... | @@ -2194,7 +2194,8 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) { |
| 2194 | 2194 | case NodeTypeFnCallExpr: |
| 2195 | 2195 | case NodeTypeArrayAccessExpr: |
| 2196 | 2196 | case NodeTypeSliceExpr: |
| 2197 | case NodeTypeNumberLiteral: | |
| 2197 | case NodeTypeFloatLiteral: | |
| 2198 | case NodeTypeIntLiteral: | |
| 2198 | 2199 | case NodeTypeStringLiteral: |
| 2199 | 2200 | case NodeTypeCharLiteral: |
| 2200 | 2201 | case NodeTypeBoolLiteral: |
| ... | ... | @@ -3247,10 +3248,17 @@ static uint32_t hash_const_val(ConstExprValue *const_val) { |
| 3247 | 3248 | case TypeTableEntryIdInt: |
| 3248 | 3249 | case TypeTableEntryIdNumLitInt: |
| 3249 | 3250 | case TypeTableEntryIdEnumTag: |
| 3250 | return ((uint32_t)(bignum_to_twos_complement(&const_val->data.x_bignum) % UINT32_MAX)) * (uint32_t)1331471175; | |
| 3251 | { | |
| 3252 | uint32_t result = 1331471175; | |
| 3253 | for (size_t i = 0; i < const_val->data.x_bigint.digit_count; i += 1) { | |
| 3254 | uint64_t digit = bigint_ptr(&const_val->data.x_bigint)[i]; | |
| 3255 | result ^= ((uint32_t)(digit >> 32)) ^ (uint32_t)(result); | |
| 3256 | } | |
| 3257 | return result; | |
| 3258 | } | |
| 3251 | 3259 | case TypeTableEntryIdFloat: |
| 3252 | 3260 | case TypeTableEntryIdNumLitFloat: |
| 3253 | return (uint32_t)(const_val->data.x_bignum.data.x_float * (uint32_t)UINT32_MAX); | |
| 3261 | return (uint32_t)(const_val->data.x_bigfloat.value * (uint32_t)UINT32_MAX); | |
| 3254 | 3262 | case TypeTableEntryIdArgTuple: |
| 3255 | 3263 | return (uint32_t)const_val->data.x_arg_tuple.start_index * (uint32_t)281907309 + |
| 3256 | 3264 | (uint32_t)const_val->data.x_arg_tuple.end_index * (uint32_t)2290442768; |
| ... | ... | @@ -3473,7 +3481,7 @@ void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str) { |
| 3473 | 3481 | ConstExprValue *this_char = &const_val->data.x_array.s_none.elements[i]; |
| 3474 | 3482 | this_char->special = ConstValSpecialStatic; |
| 3475 | 3483 | this_char->type = g->builtin_types.entry_u8; |
| 3476 | bignum_init_unsigned(&this_char->data.x_bignum, (uint8_t)buf_ptr(str)[i]); | |
| 3484 | bigint_init_unsigned(&this_char->data.x_bigint, (uint8_t)buf_ptr(str)[i]); | |
| 3477 | 3485 | } |
| 3478 | 3486 | } |
| 3479 | 3487 | |
| ... | ... | @@ -3494,12 +3502,12 @@ void init_const_c_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str) { |
| 3494 | 3502 | ConstExprValue *this_char = &array_val->data.x_array.s_none.elements[i]; |
| 3495 | 3503 | this_char->special = ConstValSpecialStatic; |
| 3496 | 3504 | this_char->type = g->builtin_types.entry_u8; |
| 3497 | bignum_init_unsigned(&this_char->data.x_bignum, (uint8_t)buf_ptr(str)[i]); | |
| 3505 | bigint_init_unsigned(&this_char->data.x_bigint, (uint8_t)buf_ptr(str)[i]); | |
| 3498 | 3506 | } |
| 3499 | 3507 | ConstExprValue *null_char = &array_val->data.x_array.s_none.elements[len_with_null - 1]; |
| 3500 | 3508 | null_char->special = ConstValSpecialStatic; |
| 3501 | 3509 | null_char->type = g->builtin_types.entry_u8; |
| 3502 | bignum_init_unsigned(&null_char->data.x_bignum, 0); | |
| 3510 | bigint_init_unsigned(&null_char->data.x_bigint, 0); | |
| 3503 | 3511 | |
| 3504 | 3512 | // then make the pointer point to it |
| 3505 | 3513 | const_val->special = ConstValSpecialStatic; |
| ... | ... | @@ -3518,8 +3526,8 @@ ConstExprValue *create_const_c_str_lit(CodeGen *g, Buf *str) { |
| 3518 | 3526 | void init_const_unsigned_negative(ConstExprValue *const_val, TypeTableEntry *type, uint64_t x, bool negative) { |
| 3519 | 3527 | const_val->special = ConstValSpecialStatic; |
| 3520 | 3528 | const_val->type = type; |
| 3521 | bignum_init_unsigned(&const_val->data.x_bignum, x); | |
| 3522 | const_val->data.x_bignum.is_negative = negative; | |
| 3529 | bigint_init_unsigned(&const_val->data.x_bigint, x); | |
| 3530 | const_val->data.x_bigint.is_negative = negative; | |
| 3523 | 3531 | } |
| 3524 | 3532 | |
| 3525 | 3533 | ConstExprValue *create_const_unsigned_negative(TypeTableEntry *type, uint64_t x, bool negative) { |
| ... | ... | @@ -3539,7 +3547,7 @@ ConstExprValue *create_const_usize(CodeGen *g, uint64_t x) { |
| 3539 | 3547 | void init_const_signed(ConstExprValue *const_val, TypeTableEntry *type, int64_t x) { |
| 3540 | 3548 | const_val->special = ConstValSpecialStatic; |
| 3541 | 3549 | const_val->type = type; |
| 3542 | bignum_init_signed(&const_val->data.x_bignum, x); | |
| 3550 | bigint_init_signed(&const_val->data.x_bigint, x); | |
| 3543 | 3551 | } |
| 3544 | 3552 | |
| 3545 | 3553 | ConstExprValue *create_const_signed(TypeTableEntry *type, int64_t x) { |
| ... | ... | @@ -3551,7 +3559,7 @@ ConstExprValue *create_const_signed(TypeTableEntry *type, int64_t x) { |
| 3551 | 3559 | void init_const_float(ConstExprValue *const_val, TypeTableEntry *type, double value) { |
| 3552 | 3560 | const_val->special = ConstValSpecialStatic; |
| 3553 | 3561 | const_val->type = type; |
| 3554 | bignum_init_float(&const_val->data.x_bignum, value); | |
| 3562 | bigfloat_init_float(&const_val->data.x_bigfloat, value); | |
| 3555 | 3563 | } |
| 3556 | 3564 | |
| 3557 | 3565 | ConstExprValue *create_const_float(TypeTableEntry *type, double value) { |
| ... | ... | @@ -3788,12 +3796,13 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) { |
| 3788 | 3796 | return a->data.x_fn.fn_entry == b->data.x_fn.fn_entry; |
| 3789 | 3797 | case TypeTableEntryIdBool: |
| 3790 | 3798 | return a->data.x_bool == b->data.x_bool; |
| 3791 | case TypeTableEntryIdInt: | |
| 3792 | 3799 | case TypeTableEntryIdFloat: |
| 3793 | 3800 | case TypeTableEntryIdNumLitFloat: |
| 3801 | return bigfloat_cmp(&a->data.x_bigfloat, &b->data.x_bigfloat) == CmpEQ; | |
| 3802 | case TypeTableEntryIdInt: | |
| 3794 | 3803 | case TypeTableEntryIdNumLitInt: |
| 3795 | 3804 | case TypeTableEntryIdEnumTag: |
| 3796 | return bignum_cmp_eq(&a->data.x_bignum, &b->data.x_bignum); | |
| 3805 | return bigint_cmp(&a->data.x_bigint, &b->data.x_bigint) == CmpEQ; | |
| 3797 | 3806 | case TypeTableEntryIdPointer: |
| 3798 | 3807 | if (a->data.x_ptr.special != b->data.x_ptr.special) |
| 3799 | 3808 | return false; |
| ... | ... | @@ -3876,58 +3885,47 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) { |
| 3876 | 3885 | zig_unreachable(); |
| 3877 | 3886 | } |
| 3878 | 3887 | |
| 3879 | uint64_t max_unsigned_val(TypeTableEntry *type_entry) { | |
| 3880 | assert(type_entry->id == TypeTableEntryIdInt); | |
| 3881 | if (type_entry->data.integral.bit_count == 64) { | |
| 3882 | return UINT64_MAX; | |
| 3883 | } else { | |
| 3884 | return (((uint64_t)1) << type_entry->data.integral.bit_count) - 1; | |
| 3888 | void eval_min_max_value_int(CodeGen *g, TypeTableEntry *int_type, BigInt *bigint, bool is_max) { | |
| 3889 | assert(int_type->id == TypeTableEntryIdInt); | |
| 3890 | if (int_type->data.integral.bit_count == 0) { | |
| 3891 | bigint_init_unsigned(bigint, 0); | |
| 3892 | return; | |
| 3885 | 3893 | } |
| 3886 | } | |
| 3894 | if (is_max) { | |
| 3895 | // is_signed=true (1 << (bit_count - 1)) - 1 | |
| 3896 | // is_signed=false (1 << (bit_count - 0)) - 1 | |
| 3897 | BigInt one = {0}; | |
| 3898 | bigint_init_unsigned(&one, 1); | |
| 3887 | 3899 | |
| 3888 | static int64_t max_signed_val(TypeTableEntry *type_entry) { | |
| 3889 | assert(type_entry->id == TypeTableEntryIdInt); | |
| 3900 | size_t shift_amt = int_type->data.integral.bit_count - (int_type->data.integral.is_signed ? 1 : 0); | |
| 3901 | BigInt bit_count_bi = {0}; | |
| 3902 | bigint_init_unsigned(&bit_count_bi, shift_amt); | |
| 3890 | 3903 | |
| 3891 | if (type_entry->data.integral.bit_count == 64) { | |
| 3892 | return INT64_MAX; | |
| 3893 | } else { | |
| 3894 | return (((uint64_t)1) << (type_entry->data.integral.bit_count - 1)) - 1; | |
| 3895 | } | |
| 3896 | } | |
| 3904 | BigInt shifted_bi = {0}; | |
| 3905 | bigint_shl(&shifted_bi, &one, &bit_count_bi); | |
| 3897 | 3906 | |
| 3898 | int64_t min_signed_val(TypeTableEntry *type_entry) { | |
| 3899 | assert(type_entry->id == TypeTableEntryIdInt); | |
| 3900 | if (type_entry->data.integral.bit_count == 64) { | |
| 3901 | return INT64_MIN; | |
| 3902 | } else { | |
| 3903 | return -((int64_t)(((uint64_t)1) << (type_entry->data.integral.bit_count - 1))); | |
| 3904 | } | |
| 3905 | } | |
| 3907 | bigint_sub(bigint, &shifted_bi, &one); | |
| 3908 | } else if (int_type->data.integral.is_signed) { | |
| 3909 | // - (1 << (bit_count - 1)) | |
| 3910 | BigInt one = {0}; | |
| 3911 | bigint_init_unsigned(&one, 1); | |
| 3906 | 3912 | |
| 3907 | void eval_min_max_value_int(CodeGen *g, TypeTableEntry *int_type, BigNum *bignum, bool is_max) { | |
| 3908 | assert(int_type->id == TypeTableEntryIdInt); | |
| 3909 | if (is_max) { | |
| 3910 | if (int_type->data.integral.is_signed) { | |
| 3911 | int64_t val = max_signed_val(int_type); | |
| 3912 | bignum_init_signed(bignum, val); | |
| 3913 | } else { | |
| 3914 | uint64_t val = max_unsigned_val(int_type); | |
| 3915 | bignum_init_unsigned(bignum, val); | |
| 3916 | } | |
| 3913 | BigInt bit_count_bi = {0}; | |
| 3914 | bigint_init_unsigned(&bit_count_bi, int_type->data.integral.bit_count - 1); | |
| 3915 | ||
| 3916 | BigInt shifted_bi = {0}; | |
| 3917 | bigint_shl(&shifted_bi, &one, &bit_count_bi); | |
| 3918 | ||
| 3919 | bigint_negate(bigint, &shifted_bi); | |
| 3917 | 3920 | } else { |
| 3918 | if (int_type->data.integral.is_signed) { | |
| 3919 | int64_t val = min_signed_val(int_type); | |
| 3920 | bignum_init_signed(bignum, val); | |
| 3921 | } else { | |
| 3922 | bignum_init_unsigned(bignum, 0); | |
| 3923 | } | |
| 3921 | bigint_init_unsigned(bigint, 0); | |
| 3924 | 3922 | } |
| 3925 | 3923 | } |
| 3926 | 3924 | |
| 3927 | 3925 | void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val, bool is_max) { |
| 3928 | 3926 | if (type_entry->id == TypeTableEntryIdInt) { |
| 3929 | 3927 | const_val->special = ConstValSpecialStatic; |
| 3930 | eval_min_max_value_int(g, type_entry, &const_val->data.x_bignum, is_max); | |
| 3928 | eval_min_max_value_int(g, type_entry, &const_val->data.x_bigint, is_max); | |
| 3931 | 3929 | } else if (type_entry->id == TypeTableEntryIdFloat) { |
| 3932 | 3930 | zig_panic("TODO analyze_min_max_value float"); |
| 3933 | 3931 | } else if (type_entry->id == TypeTableEntryIdBool) { |
| ... | ... | @@ -3967,32 +3965,15 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { |
| 3967 | 3965 | buf_appendf(buf, "{}"); |
| 3968 | 3966 | return; |
| 3969 | 3967 | case TypeTableEntryIdNumLitFloat: |
| 3970 | buf_appendf(buf, "%f", const_val->data.x_bignum.data.x_float); | |
| 3968 | case TypeTableEntryIdFloat: | |
| 3969 | bigfloat_write_buf(buf, &const_val->data.x_bigfloat); | |
| 3971 | 3970 | return; |
| 3972 | 3971 | case TypeTableEntryIdNumLitInt: |
| 3973 | { | |
| 3974 | BigNum *bignum = &const_val->data.x_bignum; | |
| 3975 | const char *negative_str = bignum->is_negative ? "-" : ""; | |
| 3976 | buf_appendf(buf, "%s%" ZIG_PRI_llu, negative_str, bignum->data.x_uint); | |
| 3977 | return; | |
| 3978 | } | |
| 3979 | case TypeTableEntryIdMetaType: | |
| 3980 | buf_appendf(buf, "%s", buf_ptr(&const_val->data.x_type->name)); | |
| 3981 | return; | |
| 3982 | 3972 | case TypeTableEntryIdInt: |
| 3983 | { | |
| 3984 | BigNum *bignum = &const_val->data.x_bignum; | |
| 3985 | assert(bignum->kind == BigNumKindInt); | |
| 3986 | const char *negative_str = bignum->is_negative ? "-" : ""; | |
| 3987 | buf_appendf(buf, "%s%" ZIG_PRI_llu, negative_str, bignum->data.x_uint); | |
| 3988 | } | |
| 3973 | bigint_write_buf(buf, &const_val->data.x_bigint, 10); | |
| 3989 | 3974 | return; |
| 3990 | case TypeTableEntryIdFloat: | |
| 3991 | { | |
| 3992 | BigNum *bignum = &const_val->data.x_bignum; | |
| 3993 | assert(bignum->kind == BigNumKindFloat); | |
| 3994 | buf_appendf(buf, "%f", bignum->data.x_float); | |
| 3995 | } | |
| 3975 | case TypeTableEntryIdMetaType: | |
| 3976 | buf_appendf(buf, "%s", buf_ptr(&const_val->data.x_type->name)); | |
| 3996 | 3977 | return; |
| 3997 | 3978 | case TypeTableEntryIdUnreachable: |
| 3998 | 3979 | buf_appendf(buf, "@unreachable()"); |
| ... | ... | @@ -4060,7 +4041,7 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { |
| 4060 | 4041 | buf_append_char(buf, '"'); |
| 4061 | 4042 | for (uint64_t i = 0; i < len; i += 1) { |
| 4062 | 4043 | ConstExprValue *child_value = &const_val->data.x_array.s_none.elements[i]; |
| 4063 | uint64_t big_c = child_value->data.x_bignum.data.x_uint; | |
| 4044 | uint64_t big_c = bigint_as_unsigned(&child_value->data.x_bigint); | |
| 4064 | 4045 | assert(big_c <= UINT8_MAX); |
| 4065 | 4046 | uint8_t c = (uint8_t)big_c; |
| 4066 | 4047 | if (c == '"') { |
| ... | ... | @@ -4146,7 +4127,8 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { |
| 4146 | 4127 | case TypeTableEntryIdEnumTag: |
| 4147 | 4128 | { |
| 4148 | 4129 | TypeTableEntry *enum_type = type_entry->data.enum_tag.enum_type; |
| 4149 | TypeEnumField *field = &enum_type->data.enumeration.fields[const_val->data.x_bignum.data.x_uint]; | |
| 4130 | size_t field_index = bigint_as_unsigned(&const_val->data.x_bigint); | |
| 4131 | TypeEnumField *field = &enum_type->data.enumeration.fields[field_index]; | |
| 4150 | 4132 | buf_appendf(buf, "%s.%s", buf_ptr(&enum_type->name), buf_ptr(field->name)); |
| 4151 | 4133 | return; |
| 4152 | 4134 | } |
src/analyze.hpp+1-3| ... | ... | @@ -84,9 +84,7 @@ void complete_enum(CodeGen *g, TypeTableEntry *enum_type); |
| 84 | 84 | bool ir_get_var_is_comptime(VariableTableEntry *var); |
| 85 | 85 | bool const_values_equal(ConstExprValue *a, ConstExprValue *b); |
| 86 | 86 | void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val, bool is_max); |
| 87 | void eval_min_max_value_int(CodeGen *g, TypeTableEntry *int_type, BigNum *bignum, bool is_max); | |
| 88 | int64_t min_signed_val(TypeTableEntry *type_entry); | |
| 89 | uint64_t max_unsigned_val(TypeTableEntry *type_entry); | |
| 87 | void eval_min_max_value_int(CodeGen *g, TypeTableEntry *int_type, BigInt *bigint, bool is_max); | |
| 90 | 88 | |
| 91 | 89 | void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val); |
| 92 | 90 | void define_local_param_variables(CodeGen *g, FnTableEntry *fn_table_entry, VariableTableEntry **arg_vars); |
src/ast_render.cpp+18-13| ... | ... | @@ -182,8 +182,10 @@ static const char *node_type_str(NodeType node_type) { |
| 182 | 182 | return "ErrorValueDecl"; |
| 183 | 183 | case NodeTypeTestDecl: |
| 184 | 184 | return "TestDecl"; |
| 185 | case NodeTypeNumberLiteral: | |
| 186 | return "NumberLiteral"; | |
| 185 | case NodeTypeIntLiteral: | |
| 186 | return "IntLiteral"; | |
| 187 | case NodeTypeFloatLiteral: | |
| 188 | return "FloatLiteral"; | |
| 187 | 189 | case NodeTypeStringLiteral: |
| 188 | 190 | return "StringLiteral"; |
| 189 | 191 | case NodeTypeCharLiteral: |
| ... | ... | @@ -536,17 +538,20 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 536 | 538 | render_node_ungrouped(ar, node->data.bin_op_expr.op2); |
| 537 | 539 | if (!grouped) fprintf(ar->f, ")"); |
| 538 | 540 | break; |
| 539 | case NodeTypeNumberLiteral: | |
| 540 | switch (node->data.number_literal.bignum->kind) { | |
| 541 | case BigNumKindInt: | |
| 542 | { | |
| 543 | const char *negative_str = node->data.number_literal.bignum->is_negative ? "-" : ""; | |
| 544 | fprintf(ar->f, "%s%" ZIG_PRI_llu, negative_str, node->data.number_literal.bignum->data.x_uint); | |
| 545 | } | |
| 546 | break; | |
| 547 | case BigNumKindFloat: | |
| 548 | fprintf(ar->f, "%f", node->data.number_literal.bignum->data.x_float); | |
| 549 | break; | |
| 541 | case NodeTypeFloatLiteral: | |
| 542 | { | |
| 543 | Buf rendered_buf = BUF_INIT; | |
| 544 | buf_resize(&rendered_buf, 0); | |
| 545 | bigfloat_write_buf(&rendered_buf, node->data.float_literal.bigfloat); | |
| 546 | fprintf(ar->f, "%s", buf_ptr(&rendered_buf)); | |
| 547 | } | |
| 548 | break; | |
| 549 | case NodeTypeIntLiteral: | |
| 550 | { | |
| 551 | Buf rendered_buf = BUF_INIT; | |
| 552 | buf_resize(&rendered_buf, 0); | |
| 553 | bigint_write_buf(&rendered_buf, node->data.int_literal.bigint, 10); | |
| 554 | fprintf(ar->f, "%s", buf_ptr(&rendered_buf)); | |
| 550 | 555 | } |
| 551 | 556 | break; |
| 552 | 557 | case NodeTypeStringLiteral: |
src/bigfloat.cpp created+152| ... | ... | @@ -0,0 +1,152 @@ |
| 1 | /* | |
| 2 | * Copyright (c) 2017 Andrew Kelley | |
| 3 | * | |
| 4 | * This file is part of zig, which is MIT licensed. | |
| 5 | * See http://opensource.org/licenses/MIT | |
| 6 | */ | |
| 7 | ||
| 8 | #include "bigfloat.hpp" | |
| 9 | #include "bigint.hpp" | |
| 10 | #include "buffer.hpp" | |
| 11 | #include <math.h> | |
| 12 | #include <errno.h> | |
| 13 | ||
| 14 | void bigfloat_init_float(BigFloat *dest, long double x) { | |
| 15 | dest->value = x; | |
| 16 | } | |
| 17 | ||
| 18 | void bigfloat_init_bigfloat(BigFloat *dest, const BigFloat *x) { | |
| 19 | dest->value = x->value; | |
| 20 | } | |
| 21 | ||
| 22 | void bigfloat_init_bigint(BigFloat *dest, const BigInt *op) { | |
| 23 | dest->value = 0.0; | |
| 24 | if (op->digit_count == 0) | |
| 25 | return; | |
| 26 | ||
| 27 | long double base = (long double)UINT64_MAX; | |
| 28 | const uint64_t *digits = bigint_ptr(op); | |
| 29 | ||
| 30 | for (size_t i = op->digit_count - 1;;) { | |
| 31 | uint64_t digit = digits[i]; | |
| 32 | dest->value *= base; | |
| 33 | dest->value += (long double)digit; | |
| 34 | ||
| 35 | if (i == 0) { | |
| 36 | if (op->is_negative) { | |
| 37 | dest->value = -dest->value; | |
| 38 | } | |
| 39 | return; | |
| 40 | } | |
| 41 | i -= 1; | |
| 42 | } | |
| 43 | } | |
| 44 | ||
| 45 | int bigfloat_init_buf_base10(BigFloat *dest, const uint8_t *buf_ptr, size_t buf_len) { | |
| 46 | char *str_begin = (char *)buf_ptr; | |
| 47 | char *str_end; | |
| 48 | errno = 0; | |
| 49 | dest->value = strtold(str_begin, &str_end); | |
| 50 | if (errno) { | |
| 51 | return ErrorOverflow; | |
| 52 | } | |
| 53 | assert(str_end <= ((char*)buf_ptr) + buf_len); | |
| 54 | return 0; | |
| 55 | } | |
| 56 | ||
| 57 | void bigfloat_add(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { | |
| 58 | dest->value = op1->value + op2->value; | |
| 59 | } | |
| 60 | ||
| 61 | void bigfloat_negate(BigFloat *dest, const BigFloat *op) { | |
| 62 | dest->value = -op->value; | |
| 63 | } | |
| 64 | ||
| 65 | void bigfloat_sub(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { | |
| 66 | dest->value = op1->value - op2->value; | |
| 67 | } | |
| 68 | ||
| 69 | void bigfloat_mul(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { | |
| 70 | dest->value = op1->value * op2->value; | |
| 71 | } | |
| 72 | ||
| 73 | void bigfloat_div(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { | |
| 74 | dest->value = op1->value / op2->value; | |
| 75 | } | |
| 76 | ||
| 77 | void bigfloat_div_trunc(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { | |
| 78 | dest->value = op1->value / op2->value; | |
| 79 | if (dest->value >= 0.0) { | |
| 80 | dest->value = floorl(dest->value); | |
| 81 | } else { | |
| 82 | dest->value = ceill(dest->value); | |
| 83 | } | |
| 84 | } | |
| 85 | ||
| 86 | void bigfloat_div_floor(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { | |
| 87 | dest->value = floorl(op1->value / op2->value); | |
| 88 | } | |
| 89 | ||
| 90 | void bigfloat_rem(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { | |
| 91 | dest->value = fmodl(op1->value, op2->value); | |
| 92 | } | |
| 93 | ||
| 94 | void bigfloat_mod(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { | |
| 95 | dest->value = fmodl(fmodl(op1->value, op2->value) + op2->value, op2->value); | |
| 96 | } | |
| 97 | ||
| 98 | void bigfloat_write_buf(Buf *buf, const BigFloat *op) { | |
| 99 | buf_appendf(buf, "%Lf", op->value); | |
| 100 | } | |
| 101 | ||
| 102 | Cmp bigfloat_cmp(const BigFloat *op1, const BigFloat *op2) { | |
| 103 | if (op1->value > op2->value) { | |
| 104 | return CmpGT; | |
| 105 | } else if (op1->value < op2->value) { | |
| 106 | return CmpLT; | |
| 107 | } else { | |
| 108 | return CmpEQ; | |
| 109 | } | |
| 110 | } | |
| 111 | ||
| 112 | // TODO this is wrong when compiler running on big endian systems. caught by tests | |
| 113 | void bigfloat_write_ieee597(const BigFloat *op, uint8_t *buf, size_t bit_count, bool is_big_endian) { | |
| 114 | if (bit_count == 32) { | |
| 115 | float f32 = op->value; | |
| 116 | memcpy(buf, &f32, 4); | |
| 117 | } else if (bit_count == 64) { | |
| 118 | double f64 = op->value; | |
| 119 | memcpy(buf, &f64, 8); | |
| 120 | } else { | |
| 121 | zig_unreachable(); | |
| 122 | } | |
| 123 | } | |
| 124 | ||
| 125 | // TODO this is wrong when compiler running on big endian systems. caught by tests | |
| 126 | void bigfloat_read_ieee597(BigFloat *dest, const uint8_t *buf, size_t bit_count, bool is_big_endian) { | |
| 127 | if (bit_count == 32) { | |
| 128 | float f32; | |
| 129 | memcpy(&f32, buf, 4); | |
| 130 | dest->value = f32; | |
| 131 | } else if (bit_count == 64) { | |
| 132 | double f64; | |
| 133 | memcpy(&f64, buf, 8); | |
| 134 | dest->value = f64; | |
| 135 | } else { | |
| 136 | zig_unreachable(); | |
| 137 | } | |
| 138 | } | |
| 139 | ||
| 140 | double bigfloat_to_double(const BigFloat *bigfloat) { | |
| 141 | return bigfloat->value; | |
| 142 | } | |
| 143 | ||
| 144 | Cmp bigfloat_cmp_zero(const BigFloat *bigfloat) { | |
| 145 | if (bigfloat->value < 0.0) { | |
| 146 | return CmpLT; | |
| 147 | } else if (bigfloat->value > 0.0) { | |
| 148 | return CmpGT; | |
| 149 | } else { | |
| 150 | return CmpEQ; | |
| 151 | } | |
| 152 | } |
src/bigfloat.hpp created+47| ... | ... | @@ -0,0 +1,47 @@ |
| 1 | /* | |
| 2 | * Copyright (c) 2017 Andrew Kelley | |
| 3 | * | |
| 4 | * This file is part of zig, which is MIT licensed. | |
| 5 | * See http://opensource.org/licenses/MIT | |
| 6 | */ | |
| 7 | ||
| 8 | #ifndef ZIG_BIGFLOAT_HPP | |
| 9 | #define ZIG_BIGFLOAT_HPP | |
| 10 | ||
| 11 | #include "bigint.hpp" | |
| 12 | #include "error.hpp" | |
| 13 | #include <stdint.h> | |
| 14 | #include <stddef.h> | |
| 15 | ||
| 16 | struct BigFloat { | |
| 17 | long double value; | |
| 18 | }; | |
| 19 | ||
| 20 | struct Buf; | |
| 21 | ||
| 22 | void bigfloat_init_float(BigFloat *dest, long double x); | |
| 23 | void bigfloat_init_bigfloat(BigFloat *dest, const BigFloat *x); | |
| 24 | void bigfloat_init_bigint(BigFloat *dest, const BigInt *op); | |
| 25 | int bigfloat_init_buf_base10(BigFloat *dest, const uint8_t *buf_ptr, size_t buf_len); | |
| 26 | ||
| 27 | double bigfloat_to_double(const BigFloat *bigfloat); | |
| 28 | ||
| 29 | void bigfloat_add(BigFloat *dest, const BigFloat *op1, const BigFloat *op2); | |
| 30 | void bigfloat_negate(BigFloat *dest, const BigFloat *op); | |
| 31 | void bigfloat_sub(BigFloat *dest, const BigFloat *op1, const BigFloat *op2); | |
| 32 | void bigfloat_mul(BigFloat *dest, const BigFloat *op1, const BigFloat *op2); | |
| 33 | void bigfloat_div(BigFloat *dest, const BigFloat *op1, const BigFloat *op2); | |
| 34 | void bigfloat_div_trunc(BigFloat *dest, const BigFloat *op1, const BigFloat *op2); | |
| 35 | void bigfloat_div_floor(BigFloat *dest, const BigFloat *op1, const BigFloat *op2); | |
| 36 | void bigfloat_rem(BigFloat *dest, const BigFloat *op1, const BigFloat *op2); | |
| 37 | void bigfloat_mod(BigFloat *dest, const BigFloat *op1, const BigFloat *op2); | |
| 38 | void bigfloat_write_buf(Buf *buf, const BigFloat *op); | |
| 39 | Cmp bigfloat_cmp(const BigFloat *op1, const BigFloat *op2); | |
| 40 | void bigfloat_write_ieee597(const BigFloat *op, uint8_t *buf, size_t bit_count, bool is_big_endian); | |
| 41 | void bigfloat_read_ieee597(BigFloat *dest, const uint8_t *buf, size_t bit_count, bool is_big_endian); | |
| 42 | ||
| 43 | ||
| 44 | // convenience functions | |
| 45 | Cmp bigfloat_cmp_zero(const BigFloat *bigfloat); | |
| 46 | ||
| 47 | #endif |
src/bigint.cpp created+1088| ... | ... | @@ -0,0 +1,1088 @@ |
| 1 | /* | |
| 2 | * Copyright (c) 2017 Andrew Kelley | |
| 3 | * | |
| 4 | * This file is part of zig, which is MIT licensed. | |
| 5 | * See http://opensource.org/licenses/MIT | |
| 6 | */ | |
| 7 | ||
| 8 | #include "bigfloat.hpp" | |
| 9 | #include "bigint.hpp" | |
| 10 | #include "buffer.hpp" | |
| 11 | #include "list.hpp" | |
| 12 | #include "os.hpp" | |
| 13 | ||
| 14 | static void bigint_normalize(BigInt *dest) { | |
| 15 | const uint64_t *digits = bigint_ptr(dest); | |
| 16 | ||
| 17 | size_t last_nonzero_digit = SIZE_MAX; | |
| 18 | for (size_t i = 0; i < dest->digit_count; i += 1) { | |
| 19 | uint64_t digit = digits[i]; | |
| 20 | if (digit != 0) { | |
| 21 | last_nonzero_digit = i; | |
| 22 | } | |
| 23 | } | |
| 24 | if (last_nonzero_digit == SIZE_MAX) { | |
| 25 | dest->is_negative = false; | |
| 26 | dest->digit_count = 0; | |
| 27 | } else { | |
| 28 | dest->digit_count = last_nonzero_digit + 1; | |
| 29 | if (last_nonzero_digit == 0) { | |
| 30 | dest->data.digit = digits[0]; | |
| 31 | } | |
| 32 | } | |
| 33 | } | |
| 34 | ||
| 35 | static uint8_t digit_to_char(uint8_t digit, bool uppercase) { | |
| 36 | if (digit <= 9) { | |
| 37 | return digit + '0'; | |
| 38 | } else if (digit <= 35) { | |
| 39 | return digit + (uppercase ? 'A' : 'a'); | |
| 40 | } else { | |
| 41 | zig_unreachable(); | |
| 42 | } | |
| 43 | } | |
| 44 | ||
| 45 | size_t bigint_bits_needed(const BigInt *op) { | |
| 46 | size_t full_bits = op->digit_count * 64; | |
| 47 | size_t leading_zero_count = bigint_clz(op, full_bits); | |
| 48 | size_t bits_needed = full_bits - leading_zero_count; | |
| 49 | return bits_needed + op->is_negative; | |
| 50 | } | |
| 51 | ||
| 52 | static void to_twos_complement(BigInt *dest, const BigInt *op, size_t bit_count) { | |
| 53 | if (bit_count == 0 || op->digit_count == 0) { | |
| 54 | bigint_init_unsigned(dest, 0); | |
| 55 | return; | |
| 56 | } | |
| 57 | if (op->is_negative) { | |
| 58 | BigInt negated = {0}; | |
| 59 | bigint_negate(&negated, op); | |
| 60 | ||
| 61 | BigInt inverted = {0}; | |
| 62 | bigint_not(&inverted, &negated, bit_count, false); | |
| 63 | ||
| 64 | BigInt one = {0}; | |
| 65 | bigint_init_unsigned(&one, 1); | |
| 66 | ||
| 67 | bigint_add(dest, &inverted, &one); | |
| 68 | return; | |
| 69 | } | |
| 70 | ||
| 71 | dest->is_negative = false; | |
| 72 | const uint64_t *op_digits = bigint_ptr(op); | |
| 73 | if (op->digit_count == 1) { | |
| 74 | dest->data.digit = op_digits[0]; | |
| 75 | if (bit_count < 64) { | |
| 76 | dest->data.digit &= (1ULL << bit_count) - 1; | |
| 77 | } | |
| 78 | dest->digit_count = 1; | |
| 79 | bigint_normalize(dest); | |
| 80 | return; | |
| 81 | } | |
| 82 | size_t digits_to_copy = bit_count / 64; | |
| 83 | size_t leftover_bits = bit_count % 64; | |
| 84 | dest->digit_count = digits_to_copy + ((leftover_bits == 0) ? 0 : 1); | |
| 85 | dest->data.digits = allocate_nonzero<uint64_t>(dest->digit_count); | |
| 86 | for (size_t i = 0; i < digits_to_copy; i += 1) { | |
| 87 | uint64_t digit = (i < op->digit_count) ? op_digits[i] : 0; | |
| 88 | dest->data.digits[i] = digit; | |
| 89 | } | |
| 90 | if (leftover_bits != 0) { | |
| 91 | uint64_t digit = (digits_to_copy < op->digit_count) ? op_digits[digits_to_copy] : 0; | |
| 92 | dest->data.digits[digits_to_copy] = digit & ((1ULL << leftover_bits) - 1); | |
| 93 | } | |
| 94 | bigint_normalize(dest); | |
| 95 | } | |
| 96 | ||
| 97 | static bool bit_at_index(const BigInt *bi, size_t index) { | |
| 98 | size_t digit_index = bi->digit_count - (index / 64) - 1; | |
| 99 | size_t digit_bit_index = index % 64; | |
| 100 | const uint64_t *digits = bigint_ptr(bi); | |
| 101 | uint64_t digit = digits[digit_index]; | |
| 102 | return ((digit >> digit_bit_index) & 0x1) == 0x1; | |
| 103 | } | |
| 104 | ||
| 105 | static void from_twos_complement(BigInt *dest, const BigInt *src, size_t bit_count, bool is_signed) { | |
| 106 | assert(!src->is_negative); | |
| 107 | ||
| 108 | if (bit_count == 0 || src->digit_count == 0) { | |
| 109 | bigint_init_unsigned(dest, 0); | |
| 110 | return; | |
| 111 | } | |
| 112 | ||
| 113 | if (is_signed && bit_at_index(src, bit_count - 1)) { | |
| 114 | BigInt negative_one = {0}; | |
| 115 | bigint_init_signed(&negative_one, -1); | |
| 116 | ||
| 117 | BigInt minus_one = {0}; | |
| 118 | bigint_add(&minus_one, src, &negative_one); | |
| 119 | ||
| 120 | BigInt inverted = {0}; | |
| 121 | bigint_not(&inverted, &minus_one, bit_count, false); | |
| 122 | ||
| 123 | bigint_negate(dest, &inverted); | |
| 124 | return; | |
| 125 | ||
| 126 | } | |
| 127 | ||
| 128 | bigint_init_bigint(dest, src); | |
| 129 | } | |
| 130 | ||
| 131 | void bigint_init_unsigned(BigInt *dest, uint64_t x) { | |
| 132 | if (x == 0) { | |
| 133 | dest->digit_count = 0; | |
| 134 | dest->is_negative = false; | |
| 135 | return; | |
| 136 | } | |
| 137 | dest->digit_count = 1; | |
| 138 | dest->data.digit = x; | |
| 139 | dest->is_negative = false; | |
| 140 | } | |
| 141 | ||
| 142 | void bigint_init_signed(BigInt *dest, int64_t x) { | |
| 143 | if (x >= 0) { | |
| 144 | return bigint_init_unsigned(dest, x); | |
| 145 | } | |
| 146 | dest->is_negative = true; | |
| 147 | dest->digit_count = 1; | |
| 148 | dest->data.digit = ((uint64_t)(-(x + 1))) + 1; | |
| 149 | } | |
| 150 | ||
| 151 | void bigint_init_bigint(BigInt *dest, const BigInt *src) { | |
| 152 | if (src->digit_count == 0) { | |
| 153 | return bigint_init_unsigned(dest, 0); | |
| 154 | } else if (src->digit_count == 1) { | |
| 155 | dest->digit_count = 1; | |
| 156 | dest->data.digit = src->data.digit; | |
| 157 | dest->is_negative = src->is_negative; | |
| 158 | return; | |
| 159 | } | |
| 160 | dest->is_negative = src->is_negative; | |
| 161 | dest->digit_count = src->digit_count; | |
| 162 | dest->data.digits = allocate_nonzero<uint64_t>(dest->digit_count); | |
| 163 | memcpy(dest->data.digits, src->data.digits, sizeof(uint64_t) * dest->digit_count); | |
| 164 | } | |
| 165 | ||
| 166 | void bigint_init_bigfloat(BigInt *dest, const BigFloat *op) { | |
| 167 | if (op->value >= 0) { | |
| 168 | bigint_init_unsigned(dest, op->value); | |
| 169 | } else { | |
| 170 | bigint_init_unsigned(dest, -op->value); | |
| 171 | dest->is_negative = true; | |
| 172 | } | |
| 173 | } | |
| 174 | ||
| 175 | bool bigint_fits_in_bits(const BigInt *bn, size_t bit_count, bool is_signed) { | |
| 176 | assert(bn->digit_count != 1 || bn->data.digit != 0); | |
| 177 | if (bit_count == 0) { | |
| 178 | return bigint_cmp_zero(bn) == CmpEQ; | |
| 179 | } | |
| 180 | if (bn->digit_count == 0) { | |
| 181 | return true; | |
| 182 | } | |
| 183 | ||
| 184 | if (!is_signed) { | |
| 185 | size_t full_bits = bn->digit_count * 64; | |
| 186 | size_t leading_zero_count = bigint_clz(bn, full_bits); | |
| 187 | return bit_count >= full_bits - leading_zero_count; | |
| 188 | } | |
| 189 | ||
| 190 | BigInt one = {0}; | |
| 191 | bigint_init_unsigned(&one, 1); | |
| 192 | ||
| 193 | BigInt shl_amt = {0}; | |
| 194 | bigint_init_unsigned(&shl_amt, bit_count - 1); | |
| 195 | ||
| 196 | BigInt max_value_plus_one = {0}; | |
| 197 | bigint_shl(&max_value_plus_one, &one, &shl_amt); | |
| 198 | ||
| 199 | BigInt max_value = {0}; | |
| 200 | bigint_sub(&max_value, &max_value_plus_one, &one); | |
| 201 | ||
| 202 | BigInt min_value = {0}; | |
| 203 | bigint_negate(&min_value, &max_value_plus_one); | |
| 204 | ||
| 205 | Cmp min_cmp = bigint_cmp(bn, &min_value); | |
| 206 | Cmp max_cmp = bigint_cmp(bn, &max_value); | |
| 207 | ||
| 208 | return (min_cmp == CmpGT || min_cmp == CmpEQ) && (max_cmp == CmpLT || max_cmp == CmpEQ); | |
| 209 | } | |
| 210 | ||
| 211 | void bigint_write_twos_complement(const BigInt *big_int, uint8_t *buf, size_t bit_count, bool is_big_endian) { | |
| 212 | if (bit_count == 0) | |
| 213 | return; | |
| 214 | ||
| 215 | BigInt twos_comp = {0}; | |
| 216 | to_twos_complement(&twos_comp, big_int, bit_count); | |
| 217 | ||
| 218 | const uint64_t *twos_comp_digits = bigint_ptr(&twos_comp); | |
| 219 | ||
| 220 | size_t bits_in_last_digit = bit_count % 64; | |
| 221 | size_t bytes_in_last_digit = (bits_in_last_digit + 7) / 8; | |
| 222 | size_t unwritten_byte_count = 8 - bytes_in_last_digit; | |
| 223 | ||
| 224 | if (is_big_endian) { | |
| 225 | size_t last_digit_index = (bit_count - 1) / 64; | |
| 226 | size_t digit_index = last_digit_index; | |
| 227 | size_t buf_index = 0; | |
| 228 | for (;;) { | |
| 229 | uint64_t x = (digit_index < twos_comp.digit_count) ? twos_comp_digits[digit_index] : 0; | |
| 230 | ||
| 231 | for (size_t byte_index = 7;;) { | |
| 232 | uint8_t byte = x & 0xff; | |
| 233 | if (digit_index == last_digit_index) { | |
| 234 | buf[buf_index + byte_index - unwritten_byte_count] = byte; | |
| 235 | if (byte_index == unwritten_byte_count) break; | |
| 236 | } else { | |
| 237 | buf[buf_index + byte_index] = byte; | |
| 238 | } | |
| 239 | ||
| 240 | if (byte_index == 0) break; | |
| 241 | byte_index -= 1; | |
| 242 | x >>= 8; | |
| 243 | } | |
| 244 | ||
| 245 | if (digit_index == 0) break; | |
| 246 | digit_index -= 1; | |
| 247 | if (digit_index == last_digit_index) { | |
| 248 | buf_index += bytes_in_last_digit; | |
| 249 | } else { | |
| 250 | buf_index += 8; | |
| 251 | } | |
| 252 | } | |
| 253 | } else { | |
| 254 | size_t digit_count = (bit_count + 63) / 64; | |
| 255 | size_t buf_index = 0; | |
| 256 | for (size_t digit_index = 0; digit_index < digit_count; digit_index += 1) { | |
| 257 | uint64_t x = (digit_index < twos_comp.digit_count) ? twos_comp_digits[digit_index] : 0; | |
| 258 | ||
| 259 | for (size_t byte_index = 0; byte_index < 8; byte_index += 1) { | |
| 260 | uint8_t byte = x & 0xff; | |
| 261 | buf[buf_index] = byte; | |
| 262 | buf_index += 1; | |
| 263 | if (buf_index >= unwritten_byte_count) { | |
| 264 | break; | |
| 265 | } | |
| 266 | x >>= 8; | |
| 267 | } | |
| 268 | } | |
| 269 | } | |
| 270 | } | |
| 271 | ||
| 272 | ||
| 273 | void bigint_read_twos_complement(BigInt *dest, const uint8_t *buf, size_t bit_count, bool is_big_endian, | |
| 274 | bool is_signed) | |
| 275 | { | |
| 276 | if (bit_count == 0) { | |
| 277 | bigint_init_unsigned(dest, 0); | |
| 278 | return; | |
| 279 | } | |
| 280 | ||
| 281 | dest->digit_count = (bit_count + 63) / 64; | |
| 282 | uint64_t *digits; | |
| 283 | if (dest->digit_count == 1) { | |
| 284 | digits = &dest->data.digit; | |
| 285 | } else { | |
| 286 | digits = allocate_nonzero<uint64_t>(dest->digit_count); | |
| 287 | dest->data.digits = digits; | |
| 288 | } | |
| 289 | ||
| 290 | size_t bits_in_last_digit = bit_count % 64; | |
| 291 | if (bits_in_last_digit == 0) { | |
| 292 | bits_in_last_digit = 64; | |
| 293 | } | |
| 294 | size_t bytes_in_last_digit = (bits_in_last_digit + 7) / 8; | |
| 295 | size_t unread_byte_count = 8 - bytes_in_last_digit; | |
| 296 | ||
| 297 | if (is_big_endian) { | |
| 298 | size_t buf_index = 0; | |
| 299 | uint64_t digit = 0; | |
| 300 | for (size_t byte_index = unread_byte_count; byte_index < 8; byte_index += 1) { | |
| 301 | uint8_t byte = buf[buf_index]; | |
| 302 | buf_index += 1; | |
| 303 | digit <<= 8; | |
| 304 | digit |= byte; | |
| 305 | } | |
| 306 | digits[dest->digit_count - 1] = digit; | |
| 307 | for (size_t digit_index = 1; digit_index < dest->digit_count; digit_index += 1) { | |
| 308 | digit = 0; | |
| 309 | for (size_t byte_index = 0; byte_index < 8; byte_index += 1) { | |
| 310 | uint8_t byte = buf[buf_index]; | |
| 311 | buf_index += 1; | |
| 312 | digit <<= 8; | |
| 313 | digit |= byte; | |
| 314 | } | |
| 315 | digits[dest->digit_count - 1 - digit_index] = digit; | |
| 316 | } | |
| 317 | } else { | |
| 318 | size_t buf_index = 0; | |
| 319 | for (size_t digit_index = 0; digit_index < dest->digit_count; digit_index += 1) { | |
| 320 | uint64_t digit = 0; | |
| 321 | size_t end_byte_index = (digit_index == dest->digit_count - 1) ? bytes_in_last_digit : 8; | |
| 322 | for (size_t byte_index = 0; byte_index < end_byte_index; byte_index += 1) { | |
| 323 | uint64_t byte = buf[buf_index]; | |
| 324 | buf_index += 1; | |
| 325 | ||
| 326 | digit |= byte << (8 * byte_index); | |
| 327 | } | |
| 328 | digits[digit_index] = digit; | |
| 329 | } | |
| 330 | } | |
| 331 | ||
| 332 | if (is_signed) { | |
| 333 | bigint_normalize(dest); | |
| 334 | BigInt tmp = {0}; | |
| 335 | bigint_init_bigint(&tmp, dest); | |
| 336 | from_twos_complement(dest, &tmp, bit_count, true); | |
| 337 | } else { | |
| 338 | dest->is_negative = false; | |
| 339 | bigint_normalize(dest); | |
| 340 | } | |
| 341 | } | |
| 342 | ||
| 343 | static bool add_u64_overflow(uint64_t op1, uint64_t op2, uint64_t *result) { | |
| 344 | return __builtin_uaddll_overflow((unsigned long long)op1, (unsigned long long)op2, | |
| 345 | (unsigned long long *)result); | |
| 346 | } | |
| 347 | ||
| 348 | static bool sub_u64_overflow(uint64_t op1, uint64_t op2, uint64_t *result) { | |
| 349 | return __builtin_usubll_overflow((unsigned long long)op1, (unsigned long long)op2, | |
| 350 | (unsigned long long *)result); | |
| 351 | } | |
| 352 | ||
| 353 | static bool mul_u64_overflow(uint64_t op1, uint64_t op2, uint64_t *result) { | |
| 354 | return __builtin_umulll_overflow((unsigned long long)op1, (unsigned long long)op2, | |
| 355 | (unsigned long long *)result); | |
| 356 | } | |
| 357 | ||
| 358 | void bigint_add(BigInt *dest, const BigInt *op1, const BigInt *op2) { | |
| 359 | if (op1->digit_count == 0) { | |
| 360 | return bigint_init_bigint(dest, op2); | |
| 361 | } | |
| 362 | if (op2->digit_count == 0) { | |
| 363 | return bigint_init_bigint(dest, op1); | |
| 364 | } | |
| 365 | if (op1->is_negative == op2->is_negative) { | |
| 366 | dest->is_negative = op1->is_negative; | |
| 367 | ||
| 368 | const uint64_t *op1_digits = bigint_ptr(op1); | |
| 369 | const uint64_t *op2_digits = bigint_ptr(op2); | |
| 370 | uint64_t overflow = add_u64_overflow(op1_digits[0], op2_digits[0], &dest->data.digit); | |
| 371 | if (overflow == 0 && op1->digit_count == 1 && op2->digit_count == 1) { | |
| 372 | dest->digit_count = 1; | |
| 373 | bigint_normalize(dest); | |
| 374 | return; | |
| 375 | } | |
| 376 | // TODO this code path is untested | |
| 377 | size_t i = 1; | |
| 378 | uint64_t first_digit = dest->data.digit; | |
| 379 | dest->data.digits = allocate_nonzero<uint64_t>(max(op1->digit_count, op2->digit_count) + 1); | |
| 380 | dest->data.digits[0] = first_digit; | |
| 381 | ||
| 382 | for (;;) { | |
| 383 | bool found_digit = false; | |
| 384 | uint64_t x = overflow; | |
| 385 | overflow = 0; | |
| 386 | ||
| 387 | if (i < op1->digit_count) { | |
| 388 | found_digit = true; | |
| 389 | uint64_t digit = op1_digits[i]; | |
| 390 | overflow += add_u64_overflow(x, digit, &x); | |
| 391 | } | |
| 392 | ||
| 393 | if (i < op2->digit_count) { | |
| 394 | found_digit = true; | |
| 395 | uint64_t digit = op2_digits[i]; | |
| 396 | overflow += add_u64_overflow(x, digit, &x); | |
| 397 | } | |
| 398 | ||
| 399 | dest->data.digits[i] = x; | |
| 400 | x += 1; | |
| 401 | ||
| 402 | if (!found_digit) { | |
| 403 | break; | |
| 404 | } | |
| 405 | } | |
| 406 | if (overflow > 0) { | |
| 407 | dest->data.digits[i] = overflow; | |
| 408 | } | |
| 409 | bigint_normalize(dest); | |
| 410 | return; | |
| 411 | } | |
| 412 | const BigInt *op_pos; | |
| 413 | const BigInt *op_neg; | |
| 414 | if (op1->is_negative) { | |
| 415 | op_neg = op1; | |
| 416 | op_pos = op2; | |
| 417 | } else { | |
| 418 | op_pos = op1; | |
| 419 | op_neg = op2; | |
| 420 | } | |
| 421 | ||
| 422 | BigInt op_neg_abs = {0}; | |
| 423 | bigint_negate(&op_neg_abs, op_neg); | |
| 424 | const BigInt *bigger_op; | |
| 425 | const BigInt *smaller_op; | |
| 426 | switch (bigint_cmp(op_pos, &op_neg_abs)) { | |
| 427 | case CmpEQ: | |
| 428 | bigint_init_unsigned(dest, 0); | |
| 429 | return; | |
| 430 | case CmpLT: | |
| 431 | bigger_op = &op_neg_abs; | |
| 432 | smaller_op = op_pos; | |
| 433 | dest->is_negative = true; | |
| 434 | break; | |
| 435 | case CmpGT: | |
| 436 | bigger_op = op_pos; | |
| 437 | smaller_op = &op_neg_abs; | |
| 438 | dest->is_negative = false; | |
| 439 | break; | |
| 440 | } | |
| 441 | const uint64_t *bigger_op_digits = bigint_ptr(bigger_op); | |
| 442 | const uint64_t *smaller_op_digits = bigint_ptr(smaller_op); | |
| 443 | uint64_t overflow = sub_u64_overflow(bigger_op_digits[0], smaller_op_digits[0], &dest->data.digit); | |
| 444 | if (overflow == 0 && bigger_op->digit_count == 1 && smaller_op->digit_count == 1) { | |
| 445 | dest->digit_count = 1; | |
| 446 | bigint_normalize(dest); | |
| 447 | return; | |
| 448 | } | |
| 449 | uint64_t first_digit = dest->data.digit; | |
| 450 | dest->data.digits = allocate_nonzero<uint64_t>(bigger_op->digit_count); | |
| 451 | dest->data.digits[0] = first_digit; | |
| 452 | size_t i = 1; | |
| 453 | ||
| 454 | for (;;) { | |
| 455 | bool found_digit = false; | |
| 456 | uint64_t x = bigger_op_digits[i]; | |
| 457 | uint64_t prev_overflow = overflow; | |
| 458 | overflow = 0; | |
| 459 | ||
| 460 | if (i < smaller_op->digit_count) { | |
| 461 | found_digit = true; | |
| 462 | uint64_t digit = smaller_op_digits[i]; | |
| 463 | overflow += sub_u64_overflow(x, digit, &x); | |
| 464 | } | |
| 465 | if (sub_u64_overflow(x, prev_overflow, &x)) { | |
| 466 | found_digit = true; | |
| 467 | overflow += 1; | |
| 468 | } | |
| 469 | dest->data.digits[i] = x; | |
| 470 | i += 1; | |
| 471 | ||
| 472 | if (!found_digit) | |
| 473 | break; | |
| 474 | } | |
| 475 | assert(overflow == 0); | |
| 476 | dest->digit_count = i; | |
| 477 | bigint_normalize(dest); | |
| 478 | } | |
| 479 | ||
| 480 | void bigint_add_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed) { | |
| 481 | BigInt unwrapped = {0}; | |
| 482 | bigint_add(&unwrapped, op1, op2); | |
| 483 | bigint_truncate(dest, &unwrapped, bit_count, is_signed); | |
| 484 | } | |
| 485 | ||
| 486 | void bigint_sub(BigInt *dest, const BigInt *op1, const BigInt *op2) { | |
| 487 | BigInt op2_negated = {0}; | |
| 488 | bigint_negate(&op2_negated, op2); | |
| 489 | return bigint_add(dest, op1, &op2_negated); | |
| 490 | } | |
| 491 | ||
| 492 | void bigint_sub_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed) { | |
| 493 | BigInt op2_negated = {0}; | |
| 494 | bigint_negate(&op2_negated, op2); | |
| 495 | return bigint_add_wrap(dest, op1, &op2_negated, bit_count, is_signed); | |
| 496 | } | |
| 497 | ||
| 498 | static void mul_overflow(uint64_t x, uint64_t y, uint64_t *result, uint64_t *carry) { | |
| 499 | if (!mul_u64_overflow(x, y, result)) { | |
| 500 | *carry = 0; | |
| 501 | return; | |
| 502 | } | |
| 503 | zig_panic("TODO bigint_mul with big numbers"); | |
| 504 | ||
| 505 | //unsigned __int128 big_x = x; | |
| 506 | //unsigned __int128 big_y = y; | |
| 507 | //unsigned __int128 big_result = big_x * big_y; | |
| 508 | //*carry = big_result >> 64; | |
| 509 | } | |
| 510 | ||
| 511 | void bigint_mul(BigInt *dest, const BigInt *op1, const BigInt *op2) { | |
| 512 | if (op1->digit_count == 0 || op2->digit_count == 0) { | |
| 513 | return bigint_init_unsigned(dest, 0); | |
| 514 | } | |
| 515 | const uint64_t *op1_digits = bigint_ptr(op1); | |
| 516 | const uint64_t *op2_digits = bigint_ptr(op2); | |
| 517 | ||
| 518 | uint64_t carry; | |
| 519 | mul_overflow(op1_digits[0], op2_digits[0], &dest->data.digit, &carry); | |
| 520 | if (carry == 0 && op1->digit_count == 1 && op2->digit_count == 1) { | |
| 521 | dest->is_negative = (op1->is_negative != op2->is_negative); | |
| 522 | dest->digit_count = 1; | |
| 523 | bigint_normalize(dest); | |
| 524 | return; | |
| 525 | } | |
| 526 | zig_panic("TODO bigint_mul with big numbers"); | |
| 527 | } | |
| 528 | ||
| 529 | void bigint_mul_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed) { | |
| 530 | BigInt unwrapped = {0}; | |
| 531 | bigint_mul(&unwrapped, op1, op2); | |
| 532 | bigint_truncate(dest, &unwrapped, bit_count, is_signed); | |
| 533 | } | |
| 534 | ||
| 535 | void bigint_div_trunc(BigInt *dest, const BigInt *op1, const BigInt *op2) { | |
| 536 | assert(op2->digit_count != 0); // division by zero | |
| 537 | if (op1->digit_count == 0) { | |
| 538 | bigint_init_unsigned(dest, 0); | |
| 539 | return; | |
| 540 | } | |
| 541 | if (op1->digit_count != 1 || op2->digit_count != 1) { | |
| 542 | zig_panic("TODO bigint div_trunc with >1 digits"); | |
| 543 | } | |
| 544 | const uint64_t *op1_digits = bigint_ptr(op1); | |
| 545 | const uint64_t *op2_digits = bigint_ptr(op2); | |
| 546 | dest->data.digit = op1_digits[0] / op2_digits[0]; | |
| 547 | dest->digit_count = 1; | |
| 548 | dest->is_negative = op1->is_negative != op2->is_negative; | |
| 549 | bigint_normalize(dest); | |
| 550 | } | |
| 551 | ||
| 552 | void bigint_div_floor(BigInt *dest, const BigInt *op1, const BigInt *op2) { | |
| 553 | if (op1->is_negative != op2->is_negative) { | |
| 554 | bigint_div_trunc(dest, op1, op2); | |
| 555 | BigInt mult_again = {0}; | |
| 556 | bigint_mul(&mult_again, dest, op2); | |
| 557 | mult_again.is_negative = op1->is_negative; | |
| 558 | if (bigint_cmp(&mult_again, op1) != CmpEQ) { | |
| 559 | BigInt tmp = {0}; | |
| 560 | bigint_init_bigint(&tmp, dest); | |
| 561 | BigInt neg_one = {0}; | |
| 562 | bigint_init_signed(&neg_one, -1); | |
| 563 | bigint_add(dest, &tmp, &neg_one); | |
| 564 | } | |
| 565 | bigint_normalize(dest); | |
| 566 | } else { | |
| 567 | bigint_div_trunc(dest, op1, op2); | |
| 568 | } | |
| 569 | } | |
| 570 | ||
| 571 | void bigint_rem(BigInt *dest, const BigInt *op1, const BigInt *op2) { | |
| 572 | assert(op2->digit_count != 0); // division by zero | |
| 573 | if (op1->digit_count == 0) { | |
| 574 | bigint_init_unsigned(dest, 0); | |
| 575 | return; | |
| 576 | } | |
| 577 | const uint64_t *op1_digits = bigint_ptr(op1); | |
| 578 | const uint64_t *op2_digits = bigint_ptr(op2); | |
| 579 | if (op2->digit_count == 2 && op2_digits[0] == 0 && op2_digits[1] == 1) { | |
| 580 | // special case this divisor | |
| 581 | bigint_init_unsigned(dest, op1_digits[0]); | |
| 582 | dest->is_negative = op1->is_negative; | |
| 583 | bigint_normalize(dest); | |
| 584 | return; | |
| 585 | } | |
| 586 | if (op1->digit_count != 1 || op2->digit_count != 1) { | |
| 587 | zig_panic("TODO bigint rem with >1 digits"); | |
| 588 | } | |
| 589 | dest->data.digit = op1_digits[0] % op2_digits[0]; | |
| 590 | dest->digit_count = 1; | |
| 591 | dest->is_negative = op1->is_negative; | |
| 592 | bigint_normalize(dest); | |
| 593 | } | |
| 594 | ||
| 595 | void bigint_mod(BigInt *dest, const BigInt *op1, const BigInt *op2) { | |
| 596 | if (op1->is_negative) { | |
| 597 | BigInt first_rem; | |
| 598 | bigint_rem(&first_rem, op1, op2); | |
| 599 | first_rem.is_negative = !op2->is_negative; | |
| 600 | BigInt op2_minus_rem; | |
| 601 | bigint_add(&op2_minus_rem, op2, &first_rem); | |
| 602 | bigint_rem(dest, &op2_minus_rem, op2); | |
| 603 | dest->is_negative = false; | |
| 604 | } else { | |
| 605 | bigint_rem(dest, op1, op2); | |
| 606 | dest->is_negative = false; | |
| 607 | } | |
| 608 | } | |
| 609 | ||
| 610 | void bigint_or(BigInt *dest, const BigInt *op1, const BigInt *op2) { | |
| 611 | if (op1->digit_count == 0) { | |
| 612 | return bigint_init_bigint(dest, op2); | |
| 613 | } | |
| 614 | if (op2->digit_count == 0) { | |
| 615 | return bigint_init_bigint(dest, op1); | |
| 616 | } | |
| 617 | if (op1->is_negative || op2->is_negative) { | |
| 618 | // TODO this code path is untested | |
| 619 | size_t big_bit_count = max(bigint_bits_needed(op1), bigint_bits_needed(op2)); | |
| 620 | ||
| 621 | BigInt twos_comp_op1 = {0}; | |
| 622 | to_twos_complement(&twos_comp_op1, op1, big_bit_count); | |
| 623 | ||
| 624 | BigInt twos_comp_op2 = {0}; | |
| 625 | to_twos_complement(&twos_comp_op2, op2, big_bit_count); | |
| 626 | ||
| 627 | BigInt twos_comp_dest = {0}; | |
| 628 | bigint_or(&twos_comp_dest, &twos_comp_op1, &twos_comp_op2); | |
| 629 | ||
| 630 | from_twos_complement(dest, &twos_comp_dest, big_bit_count, true); | |
| 631 | } else { | |
| 632 | dest->is_negative = false; | |
| 633 | const uint64_t *op1_digits = bigint_ptr(op1); | |
| 634 | const uint64_t *op2_digits = bigint_ptr(op2); | |
| 635 | if (op1->digit_count == 1 && op2->digit_count == 1) { | |
| 636 | dest->digit_count = 1; | |
| 637 | dest->data.digit = op1_digits[0] | op2_digits[0]; | |
| 638 | bigint_normalize(dest); | |
| 639 | return; | |
| 640 | } | |
| 641 | // TODO this code path is untested | |
| 642 | uint64_t first_digit = dest->data.digit; | |
| 643 | dest->digit_count = max(op1->digit_count, op2->digit_count); | |
| 644 | dest->data.digits = allocate_nonzero<uint64_t>(dest->digit_count); | |
| 645 | dest->data.digits[0] = first_digit; | |
| 646 | size_t i = 1; | |
| 647 | for (; i < dest->digit_count; i += 1) { | |
| 648 | uint64_t digit = 0; | |
| 649 | if (i < op1->digit_count) { | |
| 650 | digit |= op1_digits[i]; | |
| 651 | } | |
| 652 | if (i < op2->digit_count) { | |
| 653 | digit |= op2_digits[i]; | |
| 654 | } | |
| 655 | dest->data.digits[i] = digit; | |
| 656 | } | |
| 657 | bigint_normalize(dest); | |
| 658 | } | |
| 659 | } | |
| 660 | ||
| 661 | void bigint_and(BigInt *dest, const BigInt *op1, const BigInt *op2) { | |
| 662 | if (op1->digit_count == 0 || op2->digit_count == 0) { | |
| 663 | return bigint_init_unsigned(dest, 0); | |
| 664 | } | |
| 665 | if (op1->is_negative || op2->is_negative) { | |
| 666 | // TODO this code path is untested | |
| 667 | size_t big_bit_count = max(bigint_bits_needed(op1), bigint_bits_needed(op2)); | |
| 668 | ||
| 669 | BigInt twos_comp_op1 = {0}; | |
| 670 | to_twos_complement(&twos_comp_op1, op1, big_bit_count); | |
| 671 | ||
| 672 | BigInt twos_comp_op2 = {0}; | |
| 673 | to_twos_complement(&twos_comp_op2, op2, big_bit_count); | |
| 674 | ||
| 675 | BigInt twos_comp_dest = {0}; | |
| 676 | bigint_and(&twos_comp_dest, &twos_comp_op1, &twos_comp_op2); | |
| 677 | ||
| 678 | from_twos_complement(dest, &twos_comp_dest, big_bit_count, true); | |
| 679 | } else { | |
| 680 | dest->is_negative = false; | |
| 681 | const uint64_t *op1_digits = bigint_ptr(op1); | |
| 682 | const uint64_t *op2_digits = bigint_ptr(op2); | |
| 683 | if (op1->digit_count == 1 && op2->digit_count == 1) { | |
| 684 | dest->digit_count = 1; | |
| 685 | dest->data.digit = op1_digits[0] & op2_digits[0]; | |
| 686 | bigint_normalize(dest); | |
| 687 | return; | |
| 688 | } | |
| 689 | // TODO this code path is untested | |
| 690 | uint64_t first_digit = dest->data.digit; | |
| 691 | dest->digit_count = max(op1->digit_count, op2->digit_count); | |
| 692 | dest->data.digits = allocate_nonzero<uint64_t>(dest->digit_count); | |
| 693 | dest->data.digits[0] = first_digit; | |
| 694 | size_t i = 1; | |
| 695 | for (; i < op1->digit_count && i < op2->digit_count; i += 1) { | |
| 696 | dest->data.digits[i] = op1_digits[i] & op2_digits[i]; | |
| 697 | } | |
| 698 | for (; i < dest->digit_count; i += 1) { | |
| 699 | dest->data.digits[i] = 0; | |
| 700 | } | |
| 701 | bigint_normalize(dest); | |
| 702 | } | |
| 703 | } | |
| 704 | ||
| 705 | void bigint_xor(BigInt *dest, const BigInt *op1, const BigInt *op2) { | |
| 706 | if (op1->is_negative || op2->is_negative) { | |
| 707 | // TODO this code path is untested | |
| 708 | size_t big_bit_count = max(bigint_bits_needed(op1), bigint_bits_needed(op2)); | |
| 709 | ||
| 710 | BigInt twos_comp_op1 = {0}; | |
| 711 | to_twos_complement(&twos_comp_op1, op1, big_bit_count); | |
| 712 | ||
| 713 | BigInt twos_comp_op2 = {0}; | |
| 714 | to_twos_complement(&twos_comp_op2, op2, big_bit_count); | |
| 715 | ||
| 716 | BigInt twos_comp_dest = {0}; | |
| 717 | bigint_xor(&twos_comp_dest, &twos_comp_op1, &twos_comp_op2); | |
| 718 | ||
| 719 | from_twos_complement(dest, &twos_comp_dest, big_bit_count, true); | |
| 720 | } else { | |
| 721 | dest->is_negative = false; | |
| 722 | const uint64_t *op1_digits = bigint_ptr(op1); | |
| 723 | const uint64_t *op2_digits = bigint_ptr(op2); | |
| 724 | if (op1->digit_count == 1 && op2->digit_count == 1) { | |
| 725 | dest->digit_count = 1; | |
| 726 | dest->data.digit = op1_digits[0] ^ op2_digits[0]; | |
| 727 | bigint_normalize(dest); | |
| 728 | return; | |
| 729 | } | |
| 730 | // TODO this code path is untested | |
| 731 | uint64_t first_digit = dest->data.digit; | |
| 732 | dest->digit_count = max(op1->digit_count, op2->digit_count); | |
| 733 | dest->data.digits = allocate_nonzero<uint64_t>(dest->digit_count); | |
| 734 | dest->data.digits[0] = first_digit; | |
| 735 | size_t i = 1; | |
| 736 | for (; i < op1->digit_count && i < op2->digit_count; i += 1) { | |
| 737 | dest->data.digits[i] = op1_digits[i] ^ op2_digits[i]; | |
| 738 | } | |
| 739 | for (; i < dest->digit_count; i += 1) { | |
| 740 | if (i < op1->digit_count) { | |
| 741 | dest->data.digits[i] = op1_digits[i]; | |
| 742 | } | |
| 743 | if (i < op2->digit_count) { | |
| 744 | dest->data.digits[i] = op2_digits[i]; | |
| 745 | } | |
| 746 | } | |
| 747 | bigint_normalize(dest); | |
| 748 | } | |
| 749 | } | |
| 750 | ||
| 751 | void bigint_shl(BigInt *dest, const BigInt *op1, const BigInt *op2) { | |
| 752 | assert(!op2->is_negative); | |
| 753 | ||
| 754 | if (op2->digit_count == 0) { | |
| 755 | bigint_init_bigint(dest, op1); | |
| 756 | return; | |
| 757 | } | |
| 758 | ||
| 759 | if (op1->digit_count == 0) { | |
| 760 | bigint_init_unsigned(dest, 0); | |
| 761 | return; | |
| 762 | } | |
| 763 | ||
| 764 | if (op2->digit_count != 1) { | |
| 765 | zig_panic("TODO shift left by amount greater than 64 bit integer"); | |
| 766 | } | |
| 767 | ||
| 768 | const uint64_t *op1_digits = bigint_ptr(op1); | |
| 769 | uint64_t shift_amt = bigint_as_unsigned(op2); | |
| 770 | ||
| 771 | if (op1->digit_count == 1) { | |
| 772 | dest->data.digit = op1_digits[0] << shift_amt; | |
| 773 | if (dest->data.digit > op1_digits[0]) { | |
| 774 | dest->digit_count = 1; | |
| 775 | dest->is_negative = op1->is_negative; | |
| 776 | return; | |
| 777 | } | |
| 778 | } | |
| 779 | ||
| 780 | uint64_t digit_shift_count = shift_amt / 64; | |
| 781 | uint64_t leftover_shift_count = shift_amt % 64; | |
| 782 | ||
| 783 | dest->data.digits = allocate<uint64_t>(op1->digit_count + digit_shift_count + 1); | |
| 784 | dest->digit_count = digit_shift_count; | |
| 785 | uint64_t carry = 0; | |
| 786 | for (size_t i = 0; i < op1->digit_count; i += 1) { | |
| 787 | uint64_t digit = op1_digits[i]; | |
| 788 | dest->data.digits[dest->digit_count] = carry | (digit << leftover_shift_count); | |
| 789 | dest->digit_count += 1; | |
| 790 | if (leftover_shift_count > 0) { | |
| 791 | carry = digit >> (64 - leftover_shift_count); | |
| 792 | } else { | |
| 793 | carry = 0; | |
| 794 | } | |
| 795 | } | |
| 796 | dest->data.digits[dest->digit_count] = carry; | |
| 797 | dest->digit_count += 1; | |
| 798 | dest->is_negative = op1->is_negative; | |
| 799 | bigint_normalize(dest); | |
| 800 | } | |
| 801 | ||
| 802 | void bigint_shl_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed) { | |
| 803 | BigInt unwrapped = {0}; | |
| 804 | bigint_shl(&unwrapped, op1, op2); | |
| 805 | bigint_truncate(dest, &unwrapped, bit_count, is_signed); | |
| 806 | } | |
| 807 | ||
| 808 | void bigint_shr(BigInt *dest, const BigInt *op1, const BigInt *op2) { | |
| 809 | assert(!op2->is_negative); | |
| 810 | ||
| 811 | if (op1->digit_count == 0) { | |
| 812 | return bigint_init_unsigned(dest, 0); | |
| 813 | } | |
| 814 | ||
| 815 | if (op2->digit_count == 0) { | |
| 816 | return bigint_init_bigint(dest, op1); | |
| 817 | } | |
| 818 | ||
| 819 | if (op2->digit_count != 1) { | |
| 820 | zig_panic("TODO shift right by amount greater than 64 bit integer"); | |
| 821 | } | |
| 822 | ||
| 823 | const uint64_t *op1_digits = bigint_ptr(op1); | |
| 824 | uint64_t shift_amt = bigint_as_unsigned(op2); | |
| 825 | ||
| 826 | if (op1->digit_count == 1) { | |
| 827 | dest->data.digit = op1_digits[0] >> shift_amt; | |
| 828 | dest->digit_count = 1; | |
| 829 | dest->is_negative = op1->is_negative; | |
| 830 | bigint_normalize(dest); | |
| 831 | return; | |
| 832 | } | |
| 833 | ||
| 834 | // TODO this code path is untested | |
| 835 | size_t digit_shift_count = shift_amt / 64; | |
| 836 | size_t leftover_shift_count = shift_amt % 64; | |
| 837 | ||
| 838 | if (digit_shift_count >= op1->digit_count) { | |
| 839 | return bigint_init_unsigned(dest, 0); | |
| 840 | } | |
| 841 | ||
| 842 | dest->digit_count = op1->digit_count - digit_shift_count; | |
| 843 | dest->data.digits = allocate<uint64_t>(dest->digit_count); | |
| 844 | uint64_t carry = 0; | |
| 845 | for (size_t op_digit_index = op1->digit_count - 1;;) { | |
| 846 | uint64_t digit = op1_digits[op_digit_index]; | |
| 847 | size_t dest_digit_index = op_digit_index - digit_shift_count; | |
| 848 | dest->data.digits[dest_digit_index] = carry | (digit >> leftover_shift_count); | |
| 849 | carry = (0xffffffffffffffffULL << leftover_shift_count) & digit; | |
| 850 | ||
| 851 | if (dest_digit_index == 0) { break; } | |
| 852 | op_digit_index -= 1; | |
| 853 | } | |
| 854 | dest->is_negative = op1->is_negative; | |
| 855 | bigint_normalize(dest); | |
| 856 | } | |
| 857 | ||
| 858 | void bigint_negate(BigInt *dest, const BigInt *op) { | |
| 859 | bigint_init_bigint(dest, op); | |
| 860 | dest->is_negative = !dest->is_negative; | |
| 861 | bigint_normalize(dest); | |
| 862 | } | |
| 863 | ||
| 864 | void bigint_negate_wrap(BigInt *dest, const BigInt *op, size_t bit_count) { | |
| 865 | BigInt zero; | |
| 866 | bigint_init_unsigned(&zero, 0); | |
| 867 | bigint_sub_wrap(dest, &zero, op, bit_count, true); | |
| 868 | } | |
| 869 | ||
| 870 | void bigint_not(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed) { | |
| 871 | if (bit_count == 0) { | |
| 872 | bigint_init_unsigned(dest, 0); | |
| 873 | return; | |
| 874 | } | |
| 875 | ||
| 876 | if (is_signed) { | |
| 877 | BigInt twos_comp = {0}; | |
| 878 | to_twos_complement(&twos_comp, op, bit_count); | |
| 879 | ||
| 880 | BigInt inverted = {0}; | |
| 881 | bigint_not(&inverted, &twos_comp, bit_count, false); | |
| 882 | ||
| 883 | from_twos_complement(dest, &inverted, bit_count, true); | |
| 884 | return; | |
| 885 | } | |
| 886 | ||
| 887 | assert(!op->is_negative); | |
| 888 | ||
| 889 | dest->is_negative = false; | |
| 890 | const uint64_t *op_digits = bigint_ptr(op); | |
| 891 | if (bit_count <= 64) { | |
| 892 | dest->digit_count = 1; | |
| 893 | if (op->digit_count == 0) { | |
| 894 | if (bit_count == 64) { | |
| 895 | dest->data.digit = UINT64_MAX; | |
| 896 | } else { | |
| 897 | dest->data.digit = (1ULL << bit_count) - 1; | |
| 898 | } | |
| 899 | } else if (op->digit_count == 1) { | |
| 900 | dest->data.digit = ~op_digits[0]; | |
| 901 | if (bit_count != 64) { | |
| 902 | uint64_t mask = (1ULL << bit_count) - 1; | |
| 903 | dest->data.digit &= mask; | |
| 904 | } | |
| 905 | } | |
| 906 | bigint_normalize(dest); | |
| 907 | return; | |
| 908 | } | |
| 909 | // TODO this code path is untested | |
| 910 | dest->digit_count = bit_count / 64; | |
| 911 | assert(dest->digit_count >= op->digit_count); | |
| 912 | dest->data.digits = allocate_nonzero<uint64_t>(dest->digit_count); | |
| 913 | size_t i = 0; | |
| 914 | for (; i < op->digit_count; i += 1) { | |
| 915 | dest->data.digits[i] = ~op_digits[i]; | |
| 916 | } | |
| 917 | for (; i < dest->digit_count; i += 1) { | |
| 918 | dest->data.digits[i] = 0xffffffffffffffffULL; | |
| 919 | } | |
| 920 | size_t digit_index = dest->digit_count - (bit_count / 64) - 1; | |
| 921 | size_t digit_bit_index = bit_count % 64; | |
| 922 | if (digit_index < dest->digit_count) { | |
| 923 | uint64_t mask = (1ULL << digit_bit_index) - 1; | |
| 924 | dest->data.digits[digit_index] &= mask; | |
| 925 | } | |
| 926 | bigint_normalize(dest); | |
| 927 | } | |
| 928 | ||
| 929 | void bigint_truncate(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed) { | |
| 930 | BigInt twos_comp; | |
| 931 | to_twos_complement(&twos_comp, op, bit_count); | |
| 932 | from_twos_complement(dest, &twos_comp, bit_count, is_signed); | |
| 933 | } | |
| 934 | ||
| 935 | Cmp bigint_cmp(const BigInt *op1, const BigInt *op2) { | |
| 936 | if (op1->is_negative && !op2->is_negative) { | |
| 937 | return CmpLT; | |
| 938 | } else if (!op1->is_negative && op2->is_negative) { | |
| 939 | return CmpGT; | |
| 940 | } else if (op1->digit_count > op2->digit_count) { | |
| 941 | return op1->is_negative ? CmpLT : CmpGT; | |
| 942 | } else if (op2->digit_count > op1->digit_count) { | |
| 943 | return op1->is_negative ? CmpGT : CmpLT; | |
| 944 | } else if (op1->digit_count == 0) { | |
| 945 | return CmpEQ; | |
| 946 | } | |
| 947 | const uint64_t *op1_digits = bigint_ptr(op1); | |
| 948 | const uint64_t *op2_digits = bigint_ptr(op2); | |
| 949 | for (size_t i = op1->digit_count - 1; ;) { | |
| 950 | uint64_t op1_digit = op1_digits[i]; | |
| 951 | uint64_t op2_digit = op2_digits[i]; | |
| 952 | ||
| 953 | if (op1_digit > op2_digit) { | |
| 954 | return op1->is_negative ? CmpLT : CmpGT; | |
| 955 | } | |
| 956 | if (op1_digit < op2_digit) { | |
| 957 | return op1->is_negative ? CmpGT : CmpLT; | |
| 958 | } | |
| 959 | ||
| 960 | if (i == 0) { | |
| 961 | return CmpEQ; | |
| 962 | } | |
| 963 | i -= 1; | |
| 964 | } | |
| 965 | } | |
| 966 | ||
| 967 | void bigint_write_buf(Buf *buf, const BigInt *op, uint64_t base) { | |
| 968 | if (op->digit_count == 0) { | |
| 969 | buf_append_char(buf, '0'); | |
| 970 | return; | |
| 971 | } | |
| 972 | if (op->is_negative) { | |
| 973 | buf_append_char(buf, '-'); | |
| 974 | } | |
| 975 | if (op->digit_count == 1 && base == 10) { | |
| 976 | buf_appendf(buf, "%" ZIG_PRI_u64, op->data.digit); | |
| 977 | return; | |
| 978 | } | |
| 979 | // TODO this code path is untested | |
| 980 | size_t first_digit_index = buf_len(buf); | |
| 981 | ||
| 982 | BigInt digit_bi = {0}; | |
| 983 | BigInt a1 = {0}; | |
| 984 | BigInt a2 = {0}; | |
| 985 | ||
| 986 | BigInt *a = &a1; | |
| 987 | BigInt *other_a = &a2; | |
| 988 | bigint_init_bigint(a, op); | |
| 989 | ||
| 990 | BigInt base_bi = {0}; | |
| 991 | bigint_init_unsigned(&base_bi, 10); | |
| 992 | ||
| 993 | for (;;) { | |
| 994 | bigint_rem(&digit_bi, a, &base_bi); | |
| 995 | uint8_t digit = bigint_as_unsigned(&digit_bi); | |
| 996 | buf_append_char(buf, digit_to_char(digit, false)); | |
| 997 | bigint_div_trunc(other_a, a, &base_bi); | |
| 998 | { | |
| 999 | BigInt *tmp = a; | |
| 1000 | a = other_a; | |
| 1001 | other_a = tmp; | |
| 1002 | } | |
| 1003 | if (bigint_cmp_zero(a) == CmpEQ) { | |
| 1004 | break; | |
| 1005 | } | |
| 1006 | } | |
| 1007 | ||
| 1008 | // reverse | |
| 1009 | for (size_t i = first_digit_index; i < buf_len(buf); i += 1) { | |
| 1010 | size_t other_i = buf_len(buf) + first_digit_index - i - 1; | |
| 1011 | uint8_t tmp = buf_ptr(buf)[i]; | |
| 1012 | buf_ptr(buf)[i] = buf_ptr(buf)[other_i]; | |
| 1013 | buf_ptr(buf)[other_i] = tmp; | |
| 1014 | } | |
| 1015 | } | |
| 1016 | ||
| 1017 | size_t bigint_ctz(const BigInt *bi, size_t bit_count) { | |
| 1018 | if (bit_count == 0) | |
| 1019 | return 0; | |
| 1020 | if (bi->digit_count == 0) | |
| 1021 | return bit_count; | |
| 1022 | ||
| 1023 | BigInt twos_comp = {0}; | |
| 1024 | to_twos_complement(&twos_comp, bi, bit_count); | |
| 1025 | ||
| 1026 | size_t count = 0; | |
| 1027 | for (size_t i = 0; i < bit_count; i += 1) { | |
| 1028 | if (bit_at_index(&twos_comp, i)) | |
| 1029 | return count; | |
| 1030 | count += 1; | |
| 1031 | } | |
| 1032 | return count; | |
| 1033 | } | |
| 1034 | ||
| 1035 | size_t bigint_clz(const BigInt *bi, size_t bit_count) { | |
| 1036 | if (bi->is_negative || bit_count == 0) | |
| 1037 | return 0; | |
| 1038 | if (bi->digit_count == 0) | |
| 1039 | return bit_count; | |
| 1040 | ||
| 1041 | size_t count = 0; | |
| 1042 | for (size_t i = bit_count - 1;;) { | |
| 1043 | if (bit_at_index(bi, i)) | |
| 1044 | return count; | |
| 1045 | count += 1; | |
| 1046 | ||
| 1047 | if (i == 0) break; | |
| 1048 | i -= 1; | |
| 1049 | } | |
| 1050 | return count; | |
| 1051 | } | |
| 1052 | ||
| 1053 | uint64_t bigint_as_unsigned(const BigInt *bigint) { | |
| 1054 | assert(!bigint->is_negative); | |
| 1055 | if (bigint->digit_count == 0) { | |
| 1056 | return 0; | |
| 1057 | } else if (bigint->digit_count == 1) { | |
| 1058 | return bigint->data.digit; | |
| 1059 | } else { | |
| 1060 | zig_unreachable(); | |
| 1061 | } | |
| 1062 | } | |
| 1063 | ||
| 1064 | int64_t bigint_as_signed(const BigInt *bigint) { | |
| 1065 | if (bigint->digit_count == 0) { | |
| 1066 | return 0; | |
| 1067 | } else if (bigint->digit_count == 1) { | |
| 1068 | if (bigint->is_negative) { | |
| 1069 | // TODO this code path is untested | |
| 1070 | if (bigint->data.digit <= 9223372036854775808ULL) { | |
| 1071 | return (-((int64_t)(bigint->data.digit - 1))) - 1; | |
| 1072 | } else { | |
| 1073 | zig_unreachable(); | |
| 1074 | } | |
| 1075 | } else { | |
| 1076 | return bigint->data.digit; | |
| 1077 | } | |
| 1078 | } else { | |
| 1079 | zig_unreachable(); | |
| 1080 | } | |
| 1081 | } | |
| 1082 | ||
| 1083 | Cmp bigint_cmp_zero(const BigInt *op) { | |
| 1084 | if (op->digit_count == 0) { | |
| 1085 | return CmpEQ; | |
| 1086 | } | |
| 1087 | return op->is_negative ? CmpLT : CmpGT; | |
| 1088 | } |
src/bigint.hpp created+90| ... | ... | @@ -0,0 +1,90 @@ |
| 1 | /* | |
| 2 | * Copyright (c) 2017 Andrew Kelley | |
| 3 | * | |
| 4 | * This file is part of zig, which is MIT licensed. | |
| 5 | * See http://opensource.org/licenses/MIT | |
| 6 | */ | |
| 7 | ||
| 8 | #ifndef ZIG_BIGINT_HPP | |
| 9 | #define ZIG_BIGINT_HPP | |
| 10 | ||
| 11 | #include <stdint.h> | |
| 12 | #include <stddef.h> | |
| 13 | ||
| 14 | struct BigInt { | |
| 15 | size_t digit_count; | |
| 16 | union { | |
| 17 | uint64_t digit; | |
| 18 | uint64_t *digits; // Least significant digit first | |
| 19 | } data; | |
| 20 | bool is_negative; | |
| 21 | }; | |
| 22 | ||
| 23 | struct Buf; | |
| 24 | struct BigFloat; | |
| 25 | ||
| 26 | enum Cmp { | |
| 27 | CmpLT, | |
| 28 | CmpGT, | |
| 29 | CmpEQ, | |
| 30 | }; | |
| 31 | ||
| 32 | void bigint_init_unsigned(BigInt *dest, uint64_t x); | |
| 33 | void bigint_init_signed(BigInt *dest, int64_t x); | |
| 34 | void bigint_init_bigint(BigInt *dest, const BigInt *src); | |
| 35 | void bigint_init_bigfloat(BigInt *dest, const BigFloat *op); | |
| 36 | ||
| 37 | // panics if number won't fit | |
| 38 | uint64_t bigint_as_unsigned(const BigInt *bigint); | |
| 39 | int64_t bigint_as_signed(const BigInt *bigint); | |
| 40 | ||
| 41 | static inline const uint64_t *bigint_ptr(const BigInt *bigint) { | |
| 42 | if (bigint->digit_count == 1) { | |
| 43 | return &bigint->data.digit; | |
| 44 | } else { | |
| 45 | return bigint->data.digits; | |
| 46 | } | |
| 47 | } | |
| 48 | ||
| 49 | bool bigint_fits_in_bits(const BigInt *bn, size_t bit_count, bool is_signed); | |
| 50 | void bigint_write_twos_complement(const BigInt *big_int, uint8_t *buf, size_t bit_count, bool is_big_endian); | |
| 51 | void bigint_read_twos_complement(BigInt *dest, const uint8_t *buf, size_t bit_count, bool is_big_endian, | |
| 52 | bool is_signed); | |
| 53 | void bigint_add(BigInt *dest, const BigInt *op1, const BigInt *op2); | |
| 54 | void bigint_add_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed); | |
| 55 | void bigint_sub(BigInt *dest, const BigInt *op1, const BigInt *op2); | |
| 56 | void bigint_sub_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed); | |
| 57 | void bigint_mul(BigInt *dest, const BigInt *op1, const BigInt *op2); | |
| 58 | void bigint_mul_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed); | |
| 59 | void bigint_div_trunc(BigInt *dest, const BigInt *op1, const BigInt *op2); | |
| 60 | void bigint_div_floor(BigInt *dest, const BigInt *op1, const BigInt *op2); | |
| 61 | void bigint_rem(BigInt *dest, const BigInt *op1, const BigInt *op2); | |
| 62 | void bigint_mod(BigInt *dest, const BigInt *op1, const BigInt *op2); | |
| 63 | ||
| 64 | void bigint_or(BigInt *dest, const BigInt *op1, const BigInt *op2); | |
| 65 | void bigint_and(BigInt *dest, const BigInt *op1, const BigInt *op2); | |
| 66 | void bigint_xor(BigInt *dest, const BigInt *op1, const BigInt *op2); | |
| 67 | ||
| 68 | void bigint_shl(BigInt *dest, const BigInt *op1, const BigInt *op2); | |
| 69 | void bigint_shl_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed); | |
| 70 | void bigint_shr(BigInt *dest, const BigInt *op1, const BigInt *op2); | |
| 71 | ||
| 72 | void bigint_negate(BigInt *dest, const BigInt *op); | |
| 73 | void bigint_negate_wrap(BigInt *dest, const BigInt *op, size_t bit_count); | |
| 74 | void bigint_not(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed); | |
| 75 | void bigint_truncate(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed); | |
| 76 | ||
| 77 | Cmp bigint_cmp(const BigInt *op1, const BigInt *op2); | |
| 78 | ||
| 79 | void bigint_write_buf(Buf *buf, const BigInt *op, uint64_t base); | |
| 80 | ||
| 81 | size_t bigint_ctz(const BigInt *bi, size_t bit_count); | |
| 82 | size_t bigint_clz(const BigInt *bi, size_t bit_count); | |
| 83 | ||
| 84 | size_t bigint_bits_needed(const BigInt *op); | |
| 85 | ||
| 86 | ||
| 87 | // convenience functions | |
| 88 | Cmp bigint_cmp_zero(const BigInt *op); | |
| 89 | ||
| 90 | #endif |
src/bignum.cpp deleted-535| ... | ... | @@ -1,535 +0,0 @@ |
| 1 | /* | |
| 2 | * Copyright (c) 2016 Andrew Kelley | |
| 3 | * | |
| 4 | * This file is part of zig, which is MIT licensed. | |
| 5 | * See http://opensource.org/licenses/MIT | |
| 6 | */ | |
| 7 | ||
| 8 | #include "bignum.hpp" | |
| 9 | #include "buffer.hpp" | |
| 10 | #include "os.hpp" | |
| 11 | ||
| 12 | #include <assert.h> | |
| 13 | #include <math.h> | |
| 14 | #include <inttypes.h> | |
| 15 | ||
| 16 | static void bignum_normalize(BigNum *bn) { | |
| 17 | assert(bn->kind == BigNumKindInt); | |
| 18 | if (bn->data.x_uint == 0) { | |
| 19 | bn->is_negative = false; | |
| 20 | } | |
| 21 | } | |
| 22 | ||
| 23 | void bignum_init_float(BigNum *dest, double x) { | |
| 24 | dest->kind = BigNumKindFloat; | |
| 25 | dest->is_negative = false; | |
| 26 | dest->data.x_float = x; | |
| 27 | } | |
| 28 | ||
| 29 | void bignum_init_unsigned(BigNum *dest, uint64_t x) { | |
| 30 | dest->kind = BigNumKindInt; | |
| 31 | dest->is_negative = false; | |
| 32 | dest->data.x_uint = x; | |
| 33 | } | |
| 34 | ||
| 35 | void bignum_init_signed(BigNum *dest, int64_t x) { | |
| 36 | dest->kind = BigNumKindInt; | |
| 37 | if (x < 0) { | |
| 38 | dest->is_negative = true; | |
| 39 | dest->data.x_uint = ((uint64_t)(-(x + 1))) + 1; | |
| 40 | } else { | |
| 41 | dest->is_negative = false; | |
| 42 | dest->data.x_uint = x; | |
| 43 | } | |
| 44 | } | |
| 45 | ||
| 46 | void bignum_init_bignum(BigNum *dest, BigNum *src) { | |
| 47 | safe_memcpy(dest, src, 1); | |
| 48 | } | |
| 49 | ||
| 50 | static int u64_log2(uint64_t x) { | |
| 51 | int result = 0; | |
| 52 | for (; x != 0; x >>= 1) { | |
| 53 | result += 1; | |
| 54 | } | |
| 55 | return result; | |
| 56 | } | |
| 57 | ||
| 58 | bool bignum_fits_in_bits(BigNum *bn, int bit_count, bool is_signed) { | |
| 59 | assert(bn->kind == BigNumKindInt); | |
| 60 | ||
| 61 | if (is_signed) { | |
| 62 | uint64_t max_neg; | |
| 63 | uint64_t max_pos; | |
| 64 | if (bit_count < 64) { | |
| 65 | max_neg = (1ULL << (bit_count - 1)); | |
| 66 | max_pos = max_neg - 1; | |
| 67 | } else { | |
| 68 | max_pos = ((uint64_t)INT64_MAX); | |
| 69 | max_neg = max_pos + 1; | |
| 70 | } | |
| 71 | uint64_t max_val = bn->is_negative ? max_neg : max_pos; | |
| 72 | return bn->data.x_uint <= max_val; | |
| 73 | } else { | |
| 74 | if (bn->is_negative) { | |
| 75 | return bn->data.x_uint == 0; | |
| 76 | } else { | |
| 77 | int required_bit_count = u64_log2(bn->data.x_uint); | |
| 78 | return bit_count >= required_bit_count; | |
| 79 | } | |
| 80 | } | |
| 81 | } | |
| 82 | ||
| 83 | void bignum_truncate(BigNum *bn, int bit_count) { | |
| 84 | assert(bn->kind == BigNumKindInt); | |
| 85 | // TODO handle case when negative = true | |
| 86 | if (bit_count < 64) { | |
| 87 | bn->data.x_uint &= (1LL << bit_count) - 1; | |
| 88 | } | |
| 89 | } | |
| 90 | ||
| 91 | uint64_t bignum_to_twos_complement(BigNum *bn) { | |
| 92 | assert(bn->kind == BigNumKindInt); | |
| 93 | ||
| 94 | if (bn->is_negative) { | |
| 95 | int64_t x = bn->data.x_uint; | |
| 96 | return -x; | |
| 97 | } else { | |
| 98 | return bn->data.x_uint; | |
| 99 | } | |
| 100 | } | |
| 101 | ||
| 102 | // returns true if overflow happened | |
| 103 | bool bignum_add(BigNum *dest, BigNum *op1, BigNum *op2) { | |
| 104 | assert(op1->kind == op2->kind); | |
| 105 | dest->kind = op1->kind; | |
| 106 | ||
| 107 | if (dest->kind == BigNumKindFloat) { | |
| 108 | dest->data.x_float = op1->data.x_float + op2->data.x_float; | |
| 109 | return false; | |
| 110 | } | |
| 111 | ||
| 112 | if (op1->is_negative == op2->is_negative) { | |
| 113 | dest->is_negative = op1->is_negative; | |
| 114 | return __builtin_uaddll_overflow(op1->data.x_uint, op2->data.x_uint, &dest->data.x_uint); | |
| 115 | } else if (!op1->is_negative && op2->is_negative) { | |
| 116 | if (__builtin_usubll_overflow(op1->data.x_uint, op2->data.x_uint, &dest->data.x_uint)) { | |
| 117 | dest->data.x_uint = (UINT64_MAX - dest->data.x_uint) + 1; | |
| 118 | dest->is_negative = true; | |
| 119 | bignum_normalize(dest); | |
| 120 | return false; | |
| 121 | } else { | |
| 122 | bignum_normalize(dest); | |
| 123 | return false; | |
| 124 | } | |
| 125 | } else { | |
| 126 | return bignum_add(dest, op2, op1); | |
| 127 | } | |
| 128 | } | |
| 129 | ||
| 130 | void bignum_negate(BigNum *dest, BigNum *op) { | |
| 131 | dest->kind = op->kind; | |
| 132 | ||
| 133 | if (dest->kind == BigNumKindFloat) { | |
| 134 | dest->data.x_float = -op->data.x_float; | |
| 135 | } else { | |
| 136 | dest->data.x_uint = op->data.x_uint; | |
| 137 | dest->is_negative = !op->is_negative; | |
| 138 | bignum_normalize(dest); | |
| 139 | } | |
| 140 | } | |
| 141 | ||
| 142 | void bignum_not(BigNum *dest, BigNum *op, int bit_count, bool is_signed) { | |
| 143 | assert(op->kind == BigNumKindInt); | |
| 144 | uint64_t bits = ~bignum_to_twos_complement(op); | |
| 145 | if (bit_count < 64) { | |
| 146 | bits &= (1LL << bit_count) - 1; | |
| 147 | } | |
| 148 | if (is_signed) | |
| 149 | bignum_init_signed(dest, bits); | |
| 150 | else | |
| 151 | bignum_init_unsigned(dest, bits); | |
| 152 | } | |
| 153 | ||
| 154 | void bignum_cast_to_float(BigNum *dest, BigNum *op) { | |
| 155 | assert(op->kind == BigNumKindInt); | |
| 156 | dest->kind = BigNumKindFloat; | |
| 157 | ||
| 158 | dest->data.x_float = (double)op->data.x_uint; | |
| 159 | ||
| 160 | if (op->is_negative) { | |
| 161 | dest->data.x_float = -dest->data.x_float; | |
| 162 | } | |
| 163 | } | |
| 164 | ||
| 165 | void bignum_cast_to_int(BigNum *dest, BigNum *op) { | |
| 166 | assert(op->kind == BigNumKindFloat); | |
| 167 | dest->kind = BigNumKindInt; | |
| 168 | ||
| 169 | if (op->data.x_float >= 0) { | |
| 170 | dest->data.x_uint = (unsigned long long)op->data.x_float; | |
| 171 | dest->is_negative = false; | |
| 172 | } else { | |
| 173 | dest->data.x_uint = (unsigned long long)-op->data.x_float; | |
| 174 | dest->is_negative = true; | |
| 175 | } | |
| 176 | } | |
| 177 | ||
| 178 | bool bignum_sub(BigNum *dest, BigNum *op1, BigNum *op2) { | |
| 179 | BigNum op2_negated; | |
| 180 | bignum_negate(&op2_negated, op2); | |
| 181 | return bignum_add(dest, op1, &op2_negated); | |
| 182 | } | |
| 183 | ||
| 184 | bool bignum_mul(BigNum *dest, BigNum *op1, BigNum *op2) { | |
| 185 | assert(op1->kind == op2->kind); | |
| 186 | dest->kind = op1->kind; | |
| 187 | ||
| 188 | if (dest->kind == BigNumKindFloat) { | |
| 189 | dest->data.x_float = op1->data.x_float * op2->data.x_float; | |
| 190 | return false; | |
| 191 | } | |
| 192 | ||
| 193 | if (__builtin_umulll_overflow(op1->data.x_uint, op2->data.x_uint, &dest->data.x_uint)) { | |
| 194 | return true; | |
| 195 | } | |
| 196 | ||
| 197 | dest->is_negative = op1->is_negative != op2->is_negative; | |
| 198 | bignum_normalize(dest); | |
| 199 | return false; | |
| 200 | } | |
| 201 | ||
| 202 | bool bignum_div(BigNum *dest, BigNum *op1, BigNum *op2) { | |
| 203 | assert(op1->kind == op2->kind); | |
| 204 | dest->kind = op1->kind; | |
| 205 | ||
| 206 | if (dest->kind == BigNumKindFloat) { | |
| 207 | dest->data.x_float = op1->data.x_float / op2->data.x_float; | |
| 208 | } else { | |
| 209 | return bignum_div_trunc(dest, op1, op2); | |
| 210 | } | |
| 211 | return false; | |
| 212 | } | |
| 213 | ||
| 214 | bool bignum_div_trunc(BigNum *dest, BigNum *op1, BigNum *op2) { | |
| 215 | assert(op1->kind == op2->kind); | |
| 216 | dest->kind = op1->kind; | |
| 217 | ||
| 218 | if (dest->kind == BigNumKindFloat) { | |
| 219 | double result = op1->data.x_float / op2->data.x_float; | |
| 220 | if (result >= 0) { | |
| 221 | dest->data.x_float = floor(result); | |
| 222 | } else { | |
| 223 | dest->data.x_float = ceil(result); | |
| 224 | } | |
| 225 | } else { | |
| 226 | dest->data.x_uint = op1->data.x_uint / op2->data.x_uint; | |
| 227 | dest->is_negative = op1->is_negative != op2->is_negative; | |
| 228 | bignum_normalize(dest); | |
| 229 | } | |
| 230 | return false; | |
| 231 | } | |
| 232 | ||
| 233 | bool bignum_div_floor(BigNum *dest, BigNum *op1, BigNum *op2) { | |
| 234 | assert(op1->kind == op2->kind); | |
| 235 | dest->kind = op1->kind; | |
| 236 | ||
| 237 | if (dest->kind == BigNumKindFloat) { | |
| 238 | dest->data.x_float = floor(op1->data.x_float / op2->data.x_float); | |
| 239 | } else { | |
| 240 | if (op1->is_negative != op2->is_negative) { | |
| 241 | uint64_t result = op1->data.x_uint / op2->data.x_uint; | |
| 242 | if (result * op2->data.x_uint == op1->data.x_uint) { | |
| 243 | dest->data.x_uint = result; | |
| 244 | } else { | |
| 245 | dest->data.x_uint = result + 1; | |
| 246 | } | |
| 247 | dest->is_negative = true; | |
| 248 | } else { | |
| 249 | dest->data.x_uint = op1->data.x_uint / op2->data.x_uint; | |
| 250 | dest->is_negative = false; | |
| 251 | } | |
| 252 | } | |
| 253 | return false; | |
| 254 | } | |
| 255 | ||
| 256 | bool bignum_rem(BigNum *dest, BigNum *op1, BigNum *op2) { | |
| 257 | assert(op1->kind == op2->kind); | |
| 258 | dest->kind = op1->kind; | |
| 259 | ||
| 260 | if (dest->kind == BigNumKindFloat) { | |
| 261 | dest->data.x_float = fmod(op1->data.x_float, op2->data.x_float); | |
| 262 | } else { | |
| 263 | dest->data.x_uint = op1->data.x_uint % op2->data.x_uint; | |
| 264 | dest->is_negative = op1->is_negative; | |
| 265 | bignum_normalize(dest); | |
| 266 | } | |
| 267 | return false; | |
| 268 | } | |
| 269 | ||
| 270 | bool bignum_mod(BigNum *dest, BigNum *op1, BigNum *op2) { | |
| 271 | assert(op1->kind == op2->kind); | |
| 272 | dest->kind = op1->kind; | |
| 273 | ||
| 274 | if (dest->kind == BigNumKindFloat) { | |
| 275 | dest->data.x_float = fmod(fmod(op1->data.x_float, op2->data.x_float) + op2->data.x_float, op2->data.x_float); | |
| 276 | } else { | |
| 277 | if (op1->is_negative) { | |
| 278 | dest->data.x_uint = (op2->data.x_uint - op1->data.x_uint % op2->data.x_uint) % op2->data.x_uint; | |
| 279 | } else { | |
| 280 | dest->data.x_uint = op1->data.x_uint % op2->data.x_uint; | |
| 281 | } | |
| 282 | dest->is_negative = false; | |
| 283 | bignum_normalize(dest); | |
| 284 | } | |
| 285 | return false; | |
| 286 | } | |
| 287 | ||
| 288 | bool bignum_or(BigNum *dest, BigNum *op1, BigNum *op2) { | |
| 289 | assert(op1->kind == BigNumKindInt); | |
| 290 | assert(op2->kind == BigNumKindInt); | |
| 291 | ||
| 292 | assert(!op1->is_negative); | |
| 293 | assert(!op2->is_negative); | |
| 294 | ||
| 295 | dest->kind = BigNumKindInt; | |
| 296 | dest->data.x_uint = op1->data.x_uint | op2->data.x_uint; | |
| 297 | return false; | |
| 298 | } | |
| 299 | ||
| 300 | bool bignum_and(BigNum *dest, BigNum *op1, BigNum *op2) { | |
| 301 | assert(op1->kind == BigNumKindInt); | |
| 302 | assert(op2->kind == BigNumKindInt); | |
| 303 | ||
| 304 | assert(!op1->is_negative); | |
| 305 | assert(!op2->is_negative); | |
| 306 | ||
| 307 | dest->kind = BigNumKindInt; | |
| 308 | dest->data.x_uint = op1->data.x_uint & op2->data.x_uint; | |
| 309 | return false; | |
| 310 | } | |
| 311 | ||
| 312 | bool bignum_xor(BigNum *dest, BigNum *op1, BigNum *op2) { | |
| 313 | assert(op1->kind == BigNumKindInt); | |
| 314 | assert(op2->kind == BigNumKindInt); | |
| 315 | ||
| 316 | assert(!op1->is_negative); | |
| 317 | assert(!op2->is_negative); | |
| 318 | ||
| 319 | dest->kind = BigNumKindInt; | |
| 320 | dest->data.x_uint = op1->data.x_uint ^ op2->data.x_uint; | |
| 321 | return false; | |
| 322 | } | |
| 323 | ||
| 324 | bool bignum_shl(BigNum *dest, BigNum *op1, BigNum *op2) { | |
| 325 | assert(op1->kind == BigNumKindInt); | |
| 326 | assert(op2->kind == BigNumKindInt); | |
| 327 | ||
| 328 | assert(!op1->is_negative); | |
| 329 | assert(!op2->is_negative); | |
| 330 | ||
| 331 | dest->kind = BigNumKindInt; | |
| 332 | dest->data.x_uint = op1->data.x_uint << op2->data.x_uint; | |
| 333 | return false; | |
| 334 | } | |
| 335 | ||
| 336 | bool bignum_shr(BigNum *dest, BigNum *op1, BigNum *op2) { | |
| 337 | assert(op1->kind == BigNumKindInt); | |
| 338 | assert(op2->kind == BigNumKindInt); | |
| 339 | ||
| 340 | assert(!op1->is_negative); | |
| 341 | assert(!op2->is_negative); | |
| 342 | ||
| 343 | dest->kind = BigNumKindInt; | |
| 344 | dest->data.x_uint = op1->data.x_uint >> op2->data.x_uint; | |
| 345 | return false; | |
| 346 | } | |
| 347 | ||
| 348 | ||
| 349 | Buf *bignum_to_buf(BigNum *bn) { | |
| 350 | if (bn->kind == BigNumKindFloat) { | |
| 351 | return buf_sprintf("%f", bn->data.x_float); | |
| 352 | } else { | |
| 353 | const char *neg = bn->is_negative ? "-" : ""; | |
| 354 | return buf_sprintf("%s%" ZIG_PRI_llu "", neg, bn->data.x_uint); | |
| 355 | } | |
| 356 | } | |
| 357 | ||
| 358 | bool bignum_cmp_eq(BigNum *op1, BigNum *op2) { | |
| 359 | assert(op1->kind == op2->kind); | |
| 360 | if (op1->kind == BigNumKindFloat) { | |
| 361 | return op1->data.x_float == op2->data.x_float; | |
| 362 | } else { | |
| 363 | return op1->data.x_uint == op2->data.x_uint && | |
| 364 | (op1->is_negative == op2->is_negative || op1->data.x_uint == 0); | |
| 365 | } | |
| 366 | } | |
| 367 | ||
| 368 | bool bignum_cmp_neq(BigNum *op1, BigNum *op2) { | |
| 369 | return !bignum_cmp_eq(op1, op2); | |
| 370 | } | |
| 371 | ||
| 372 | bool bignum_cmp_lt(BigNum *op1, BigNum *op2) { | |
| 373 | return !bignum_cmp_gte(op1, op2); | |
| 374 | } | |
| 375 | ||
| 376 | bool bignum_cmp_gt(BigNum *op1, BigNum *op2) { | |
| 377 | return !bignum_cmp_lte(op1, op2); | |
| 378 | } | |
| 379 | ||
| 380 | bool bignum_cmp_lte(BigNum *op1, BigNum *op2) { | |
| 381 | assert(op1->kind == op2->kind); | |
| 382 | if (op1->kind == BigNumKindFloat) { | |
| 383 | return (op1->data.x_float <= op2->data.x_float); | |
| 384 | } | |
| 385 | ||
| 386 | // assume normalized is_negative | |
| 387 | if (!op1->is_negative && !op2->is_negative) { | |
| 388 | return op1->data.x_uint <= op2->data.x_uint; | |
| 389 | } else if (op1->is_negative && op2->is_negative) { | |
| 390 | return op1->data.x_uint >= op2->data.x_uint; | |
| 391 | } else if (op1->is_negative && !op2->is_negative) { | |
| 392 | return true; | |
| 393 | } else { | |
| 394 | return false; | |
| 395 | } | |
| 396 | } | |
| 397 | ||
| 398 | bool bignum_cmp_gte(BigNum *op1, BigNum *op2) { | |
| 399 | assert(op1->kind == op2->kind); | |
| 400 | ||
| 401 | if (op1->kind == BigNumKindFloat) { | |
| 402 | return (op1->data.x_float >= op2->data.x_float); | |
| 403 | } | |
| 404 | ||
| 405 | // assume normalized is_negative | |
| 406 | if (!op1->is_negative && !op2->is_negative) { | |
| 407 | return op1->data.x_uint >= op2->data.x_uint; | |
| 408 | } else if (op1->is_negative && op2->is_negative) { | |
| 409 | return op1->data.x_uint <= op2->data.x_uint; | |
| 410 | } else if (op1->is_negative && !op2->is_negative) { | |
| 411 | return false; | |
| 412 | } else { | |
| 413 | return true; | |
| 414 | } | |
| 415 | } | |
| 416 | ||
| 417 | bool bignum_increment_by_scalar(BigNum *bignum, uint64_t scalar) { | |
| 418 | assert(bignum->kind == BigNumKindInt); | |
| 419 | assert(!bignum->is_negative); | |
| 420 | return __builtin_uaddll_overflow(bignum->data.x_uint, scalar, &bignum->data.x_uint); | |
| 421 | } | |
| 422 | ||
| 423 | bool bignum_multiply_by_scalar(BigNum *bignum, uint64_t scalar) { | |
| 424 | assert(bignum->kind == BigNumKindInt); | |
| 425 | assert(!bignum->is_negative); | |
| 426 | return __builtin_umulll_overflow(bignum->data.x_uint, scalar, &bignum->data.x_uint); | |
| 427 | } | |
| 428 | ||
| 429 | uint32_t bignum_ctz(BigNum *bignum, uint32_t bit_count) { | |
| 430 | assert(bignum->kind == BigNumKindInt); | |
| 431 | ||
| 432 | uint64_t x = bignum_to_twos_complement(bignum); | |
| 433 | uint32_t result = 0; | |
| 434 | for (uint32_t i = 0; i < bit_count; i += 1) { | |
| 435 | if ((x & 0x1) != 0) | |
| 436 | break; | |
| 437 | ||
| 438 | result += 1; | |
| 439 | x = x >> 1; | |
| 440 | } | |
| 441 | return result; | |
| 442 | } | |
| 443 | ||
| 444 | uint32_t bignum_clz(BigNum *bignum, uint32_t bit_count) { | |
| 445 | assert(bignum->kind == BigNumKindInt); | |
| 446 | ||
| 447 | if (bit_count == 0) | |
| 448 | return 0; | |
| 449 | ||
| 450 | uint64_t x = bignum_to_twos_complement(bignum); | |
| 451 | uint64_t mask = ((uint64_t)1) << ((uint64_t)bit_count - 1); | |
| 452 | uint32_t result = 0; | |
| 453 | for (uint32_t i = 0; i < bit_count; i += 1) { | |
| 454 | if ((x & mask) != 0) | |
| 455 | break; | |
| 456 | ||
| 457 | result += 1; | |
| 458 | x = x << 1; | |
| 459 | } | |
| 460 | return result; | |
| 461 | } | |
| 462 | ||
| 463 | void bignum_write_twos_complement(BigNum *bn, uint8_t *buf, int bit_count, bool is_big_endian) { | |
| 464 | assert(bn->kind == BigNumKindInt); | |
| 465 | uint64_t x = bignum_to_twos_complement(bn); | |
| 466 | ||
| 467 | int byte_count = (bit_count + 7) / 8; | |
| 468 | for (int i = 0; i < byte_count; i += 1) { | |
| 469 | uint8_t le_byte = (x >> (i * 8)) & 0xff; | |
| 470 | if (is_big_endian) { | |
| 471 | buf[byte_count - i - 1] = le_byte; | |
| 472 | } else { | |
| 473 | buf[i] = le_byte; | |
| 474 | } | |
| 475 | } | |
| 476 | } | |
| 477 | ||
| 478 | void bignum_read_twos_complement(BigNum *bn, uint8_t *buf, int bit_count, bool is_big_endian, bool is_signed) { | |
| 479 | int byte_count = (bit_count + 7) / 8; | |
| 480 | ||
| 481 | uint64_t twos_comp = 0; | |
| 482 | for (int i = 0; i < byte_count; i += 1) { | |
| 483 | uint8_t be_byte; | |
| 484 | if (is_big_endian) { | |
| 485 | be_byte = buf[i]; | |
| 486 | } else { | |
| 487 | be_byte = buf[byte_count - i - 1]; | |
| 488 | } | |
| 489 | ||
| 490 | twos_comp <<= 8; | |
| 491 | twos_comp |= be_byte; | |
| 492 | } | |
| 493 | ||
| 494 | uint8_t be_byte = buf[is_big_endian ? 0 : byte_count - 1]; | |
| 495 | if (is_signed && ((be_byte >> 7) & 0x1) != 0) { | |
| 496 | bn->is_negative = true; | |
| 497 | uint64_t mask = 0; | |
| 498 | for (int i = 0; i < bit_count; i += 1) { | |
| 499 | mask <<= 1; | |
| 500 | mask |= 1; | |
| 501 | } | |
| 502 | bn->data.x_uint = ((~twos_comp) & mask) + 1; | |
| 503 | } else { | |
| 504 | bn->data.x_uint = twos_comp; | |
| 505 | } | |
| 506 | bn->kind = BigNumKindInt; | |
| 507 | } | |
| 508 | ||
| 509 | void bignum_write_ieee597(BigNum *bn, uint8_t *buf, int bit_count, bool is_big_endian) { | |
| 510 | assert(bn->kind == BigNumKindFloat); | |
| 511 | if (bit_count == 32) { | |
| 512 | float f32 = bn->data.x_float; | |
| 513 | memcpy(buf, &f32, 4); | |
| 514 | } else if (bit_count == 64) { | |
| 515 | double f64 = bn->data.x_float; | |
| 516 | memcpy(buf, &f64, 8); | |
| 517 | } else { | |
| 518 | zig_unreachable(); | |
| 519 | } | |
| 520 | } | |
| 521 | ||
| 522 | void bignum_read_ieee597(BigNum *bn, uint8_t *buf, int bit_count, bool is_big_endian) { | |
| 523 | bn->kind = BigNumKindFloat; | |
| 524 | if (bit_count == 32) { | |
| 525 | float f32; | |
| 526 | memcpy(&f32, buf, 4); | |
| 527 | bn->data.x_float = f32; | |
| 528 | } else if (bit_count == 64) { | |
| 529 | double f64; | |
| 530 | memcpy(&f64, buf, 8); | |
| 531 | bn->data.x_float = f64; | |
| 532 | } else { | |
| 533 | zig_unreachable(); | |
| 534 | } | |
| 535 | } |
src/bignum.hpp deleted-81| ... | ... | @@ -1,81 +0,0 @@ |
| 1 | /* | |
| 2 | * Copyright (c) 2016 Andrew Kelley | |
| 3 | * | |
| 4 | * This file is part of zig, which is MIT licensed. | |
| 5 | * See http://opensource.org/licenses/MIT | |
| 6 | */ | |
| 7 | ||
| 8 | #ifndef ZIG_BIGNUM_HPP | |
| 9 | #define ZIG_BIGNUM_HPP | |
| 10 | ||
| 11 | #include <stdint.h> | |
| 12 | ||
| 13 | enum BigNumKind { | |
| 14 | BigNumKindInt, | |
| 15 | BigNumKindFloat, | |
| 16 | }; | |
| 17 | ||
| 18 | struct BigNum { | |
| 19 | BigNumKind kind; | |
| 20 | bool is_negative; | |
| 21 | union { | |
| 22 | unsigned long long x_uint; | |
| 23 | double x_float; | |
| 24 | } data; | |
| 25 | }; | |
| 26 | ||
| 27 | void bignum_init_float(BigNum *dest, double x); | |
| 28 | void bignum_init_unsigned(BigNum *dest, uint64_t x); | |
| 29 | void bignum_init_signed(BigNum *dest, int64_t x); | |
| 30 | void bignum_init_bignum(BigNum *dest, BigNum *src); | |
| 31 | ||
| 32 | bool bignum_fits_in_bits(BigNum *bn, int bit_count, bool is_signed); | |
| 33 | uint64_t bignum_to_twos_complement(BigNum *bn); | |
| 34 | ||
| 35 | void bignum_write_twos_complement(BigNum *bn, uint8_t *buf, int bit_count, bool is_big_endian); | |
| 36 | void bignum_write_ieee597(BigNum *bn, uint8_t *buf, int bit_count, bool is_big_endian); | |
| 37 | void bignum_read_twos_complement(BigNum *bn, uint8_t *buf, int bit_count, bool is_big_endian, bool is_signed); | |
| 38 | void bignum_read_ieee597(BigNum *bn, uint8_t *buf, int bit_count, bool is_big_endian); | |
| 39 | ||
| 40 | // returns true if overflow happened | |
| 41 | bool bignum_add(BigNum *dest, BigNum *op1, BigNum *op2); | |
| 42 | bool bignum_sub(BigNum *dest, BigNum *op1, BigNum *op2); | |
| 43 | bool bignum_mul(BigNum *dest, BigNum *op1, BigNum *op2); | |
| 44 | bool bignum_div(BigNum *dest, BigNum *op1, BigNum *op2); | |
| 45 | bool bignum_div_trunc(BigNum *dest, BigNum *op1, BigNum *op2); | |
| 46 | bool bignum_div_floor(BigNum *dest, BigNum *op1, BigNum *op2); | |
| 47 | bool bignum_rem(BigNum *dest, BigNum *op1, BigNum *op2); | |
| 48 | bool bignum_mod(BigNum *dest, BigNum *op1, BigNum *op2); | |
| 49 | ||
| 50 | bool bignum_or(BigNum *dest, BigNum *op1, BigNum *op2); | |
| 51 | bool bignum_and(BigNum *dest, BigNum *op1, BigNum *op2); | |
| 52 | bool bignum_xor(BigNum *dest, BigNum *op1, BigNum *op2); | |
| 53 | bool bignum_shl(BigNum *dest, BigNum *op1, BigNum *op2); | |
| 54 | bool bignum_shr(BigNum *dest, BigNum *op1, BigNum *op2); | |
| 55 | ||
| 56 | void bignum_negate(BigNum *dest, BigNum *op); | |
| 57 | void bignum_cast_to_float(BigNum *dest, BigNum *op); | |
| 58 | void bignum_cast_to_int(BigNum *dest, BigNum *op); | |
| 59 | void bignum_not(BigNum *dest, BigNum *op, int bit_count, bool is_signed); | |
| 60 | ||
| 61 | void bignum_truncate(BigNum *dest, int bit_count); | |
| 62 | ||
| 63 | // returns the result of the comparison | |
| 64 | bool bignum_cmp_eq(BigNum *op1, BigNum *op2); | |
| 65 | bool bignum_cmp_neq(BigNum *op1, BigNum *op2); | |
| 66 | bool bignum_cmp_lt(BigNum *op1, BigNum *op2); | |
| 67 | bool bignum_cmp_gt(BigNum *op1, BigNum *op2); | |
| 68 | bool bignum_cmp_lte(BigNum *op1, BigNum *op2); | |
| 69 | bool bignum_cmp_gte(BigNum *op1, BigNum *op2); | |
| 70 | ||
| 71 | // helper functions | |
| 72 | bool bignum_increment_by_scalar(BigNum *bignum, uint64_t scalar); | |
| 73 | bool bignum_multiply_by_scalar(BigNum *bignum, uint64_t scalar); | |
| 74 | ||
| 75 | struct Buf; | |
| 76 | Buf *bignum_to_buf(BigNum *bn); | |
| 77 | ||
| 78 | uint32_t bignum_ctz(BigNum *bignum, uint32_t bit_count); | |
| 79 | uint32_t bignum_clz(BigNum *bignum, uint32_t bit_count); | |
| 80 | ||
| 81 | #endif |
src/codegen.cpp+33-19| ... | ... | @@ -1203,6 +1203,23 @@ enum DivKind { |
| 1203 | 1203 | DivKindExact, |
| 1204 | 1204 | }; |
| 1205 | 1205 | |
| 1206 | static LLVMValueRef bigint_to_llvm_const(LLVMTypeRef type_ref, BigInt *bigint) { | |
| 1207 | if (bigint->digit_count == 0) { | |
| 1208 | return LLVMConstNull(type_ref); | |
| 1209 | } | |
| 1210 | LLVMValueRef unsigned_val = LLVMConstIntOfArbitraryPrecision(type_ref, | |
| 1211 | bigint->digit_count, bigint_ptr(bigint)); | |
| 1212 | if (bigint->is_negative) { | |
| 1213 | return LLVMConstNeg(unsigned_val); | |
| 1214 | } else { | |
| 1215 | return unsigned_val; | |
| 1216 | } | |
| 1217 | } | |
| 1218 | ||
| 1219 | static LLVMValueRef bigfloat_to_llvm_const(LLVMTypeRef type_ref, BigFloat *bigfloat) { | |
| 1220 | return LLVMConstReal(type_ref, bigfloat_to_double(bigfloat)); | |
| 1221 | } | |
| 1222 | ||
| 1206 | 1223 | static LLVMValueRef gen_div(CodeGen *g, bool want_debug_safety, bool want_fast_math, |
| 1207 | 1224 | LLVMValueRef val1, LLVMValueRef val2, |
| 1208 | 1225 | TypeTableEntry *type_entry, DivKind div_kind) |
| ... | ... | @@ -1230,7 +1247,9 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_debug_safety, bool want_fast_m |
| 1230 | 1247 | |
| 1231 | 1248 | if (type_entry->id == TypeTableEntryIdInt && type_entry->data.integral.is_signed) { |
| 1232 | 1249 | LLVMValueRef neg_1_value = LLVMConstInt(type_entry->type_ref, -1, true); |
| 1233 | LLVMValueRef int_min_value = LLVMConstInt(type_entry->type_ref, min_signed_val(type_entry), true); | |
| 1250 | BigInt int_min_bi = {0}; | |
| 1251 | eval_min_max_value_int(g, type_entry, &int_min_bi, false); | |
| 1252 | LLVMValueRef int_min_value = bigint_to_llvm_const(type_entry->type_ref, &int_min_bi); | |
| 1234 | 1253 | LLVMBasicBlockRef overflow_ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivOverflowOk"); |
| 1235 | 1254 | LLVMBasicBlockRef overflow_fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivOverflowFail"); |
| 1236 | 1255 | LLVMValueRef num_is_int_min = LLVMBuildICmp(g->builder, LLVMIntEQ, val1, int_min_value, ""); |
| ... | ... | @@ -1765,8 +1784,13 @@ static LLVMValueRef ir_render_int_to_err(CodeGen *g, IrExecutable *executable, I |
| 1765 | 1784 | LLVMValueRef zero = LLVMConstNull(actual_type->type_ref); |
| 1766 | 1785 | LLVMValueRef neq_zero_bit = LLVMBuildICmp(g->builder, LLVMIntNE, target_val, zero, ""); |
| 1767 | 1786 | LLVMValueRef ok_bit; |
| 1768 | uint64_t biggest_possible_err_val = max_unsigned_val(actual_type); | |
| 1769 | if (biggest_possible_err_val < g->error_decls.length) { | |
| 1787 | ||
| 1788 | BigInt biggest_possible_err_val = {0}; | |
| 1789 | eval_min_max_value_int(g, actual_type, &biggest_possible_err_val, true); | |
| 1790 | ||
| 1791 | if (bigint_fits_in_bits(&biggest_possible_err_val, 64, false) && | |
| 1792 | bigint_as_unsigned(&biggest_possible_err_val) < g->error_decls.length) | |
| 1793 | { | |
| 1770 | 1794 | ok_bit = neq_zero_bit; |
| 1771 | 1795 | } else { |
| 1772 | 1796 | LLVMValueRef error_value_count = LLVMConstInt(actual_type->type_ref, g->error_decls.length, false); |
| ... | ... | @@ -3317,7 +3341,6 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con |
| 3317 | 3341 | LLVMValueRef int_val = gen_const_val(g, const_val); |
| 3318 | 3342 | return LLVMConstZExt(int_val, big_int_type_ref); |
| 3319 | 3343 | } |
| 3320 | return LLVMConstInt(big_int_type_ref, bignum_to_twos_complement(&const_val->data.x_bignum), false); | |
| 3321 | 3344 | case TypeTableEntryIdFloat: |
| 3322 | 3345 | { |
| 3323 | 3346 | LLVMValueRef float_val = gen_const_val(g, const_val); |
| ... | ... | @@ -3374,21 +3397,13 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { |
| 3374 | 3397 | switch (type_entry->id) { |
| 3375 | 3398 | case TypeTableEntryIdInt: |
| 3376 | 3399 | case TypeTableEntryIdEnumTag: |
| 3377 | return LLVMConstInt(type_entry->type_ref, bignum_to_twos_complement(&const_val->data.x_bignum), false); | |
| 3400 | return bigint_to_llvm_const(type_entry->type_ref, &const_val->data.x_bigint); | |
| 3378 | 3401 | case TypeTableEntryIdPureError: |
| 3379 | 3402 | assert(const_val->data.x_pure_err); |
| 3380 | 3403 | return LLVMConstInt(g->builtin_types.entry_pure_error->type_ref, |
| 3381 | 3404 | const_val->data.x_pure_err->value, false); |
| 3382 | 3405 | case TypeTableEntryIdFloat: |
| 3383 | if (const_val->data.x_bignum.kind == BigNumKindFloat) { | |
| 3384 | return LLVMConstReal(type_entry->type_ref, const_val->data.x_bignum.data.x_float); | |
| 3385 | } else { | |
| 3386 | double x = (double)const_val->data.x_bignum.data.x_uint; | |
| 3387 | if (const_val->data.x_bignum.is_negative) { | |
| 3388 | x = -x; | |
| 3389 | } | |
| 3390 | return LLVMConstReal(type_entry->type_ref, x); | |
| 3391 | } | |
| 3406 | return bigfloat_to_llvm_const(type_entry->type_ref, &const_val->data.x_bigfloat); | |
| 3392 | 3407 | case TypeTableEntryIdBool: |
| 3393 | 3408 | if (const_val->data.x_bool) { |
| 3394 | 3409 | return LLVMConstAllOnes(LLVMInt1Type()); |
| ... | ... | @@ -3866,7 +3881,7 @@ static void do_code_gen(CodeGen *g) { |
| 3866 | 3881 | ConstExprValue *const_val = var->value; |
| 3867 | 3882 | assert(const_val->special != ConstValSpecialRuntime); |
| 3868 | 3883 | TypeTableEntry *var_type = g->builtin_types.entry_f64; |
| 3869 | LLVMValueRef init_val = LLVMConstReal(var_type->type_ref, const_val->data.x_bignum.data.x_float); | |
| 3884 | LLVMValueRef init_val = bigfloat_to_llvm_const(var_type->type_ref, &const_val->data.x_bigfloat); | |
| 3870 | 3885 | gen_global_var(g, var, init_val, var_type); |
| 3871 | 3886 | continue; |
| 3872 | 3887 | } |
| ... | ... | @@ -3875,10 +3890,9 @@ static void do_code_gen(CodeGen *g) { |
| 3875 | 3890 | // Generate debug info for it but that's it. |
| 3876 | 3891 | ConstExprValue *const_val = var->value; |
| 3877 | 3892 | assert(const_val->special != ConstValSpecialRuntime); |
| 3878 | TypeTableEntry *var_type = const_val->data.x_bignum.is_negative ? | |
| 3879 | g->builtin_types.entry_isize : g->builtin_types.entry_usize; | |
| 3880 | LLVMValueRef init_val = LLVMConstInt(var_type->type_ref, | |
| 3881 | bignum_to_twos_complement(&const_val->data.x_bignum), false); | |
| 3893 | size_t bits_needed = bigint_bits_needed(&const_val->data.x_bigint); | |
| 3894 | TypeTableEntry *var_type = get_int_type(g, const_val->data.x_bigint.is_negative, bits_needed); | |
| 3895 | LLVMValueRef init_val = bigint_to_llvm_const(var_type->type_ref, &const_val->data.x_bigint); | |
| 3882 | 3896 | gen_global_var(g, var, init_val, var_type); |
| 3883 | 3897 | continue; |
| 3884 | 3898 | } |
src/ir.cpp+405-300| ... | ... | @@ -656,16 +656,23 @@ static IrInstruction *ir_build_const_uint(IrBuilder *irb, Scope *scope, AstNode |
| 656 | 656 | IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, source_node); |
| 657 | 657 | const_instruction->base.value.type = irb->codegen->builtin_types.entry_num_lit_int; |
| 658 | 658 | const_instruction->base.value.special = ConstValSpecialStatic; |
| 659 | bignum_init_unsigned(&const_instruction->base.value.data.x_bignum, value); | |
| 659 | bigint_init_unsigned(&const_instruction->base.value.data.x_bigint, value); | |
| 660 | 660 | return &const_instruction->base; |
| 661 | 661 | } |
| 662 | 662 | |
| 663 | static IrInstruction *ir_build_const_bignum(IrBuilder *irb, Scope *scope, AstNode *source_node, BigNum *bignum) { | |
| 663 | static IrInstruction *ir_build_const_bigint(IrBuilder *irb, Scope *scope, AstNode *source_node, BigInt *bigint) { | |
| 664 | 664 | IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, source_node); |
| 665 | const_instruction->base.value.type = (bignum->kind == BigNumKindInt) ? | |
| 666 | irb->codegen->builtin_types.entry_num_lit_int : irb->codegen->builtin_types.entry_num_lit_float; | |
| 665 | const_instruction->base.value.type = irb->codegen->builtin_types.entry_num_lit_int; | |
| 666 | const_instruction->base.value.special = ConstValSpecialStatic; | |
| 667 | bigint_init_bigint(&const_instruction->base.value.data.x_bigint, bigint); | |
| 668 | return &const_instruction->base; | |
| 669 | } | |
| 670 | ||
| 671 | static IrInstruction *ir_build_const_bigfloat(IrBuilder *irb, Scope *scope, AstNode *source_node, BigFloat *bigfloat) { | |
| 672 | IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, source_node); | |
| 673 | const_instruction->base.value.type = irb->codegen->builtin_types.entry_num_lit_float; | |
| 667 | 674 | const_instruction->base.value.special = ConstValSpecialStatic; |
| 668 | const_instruction->base.value.data.x_bignum = *bignum; | |
| 675 | bigfloat_init_bigfloat(&const_instruction->base.value.data.x_bigfloat, bigfloat); | |
| 669 | 676 | return &const_instruction->base; |
| 670 | 677 | } |
| 671 | 678 | |
| ... | ... | @@ -680,7 +687,7 @@ static IrInstruction *ir_build_const_usize(IrBuilder *irb, Scope *scope, AstNode |
| 680 | 687 | IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, source_node); |
| 681 | 688 | const_instruction->base.value.type = irb->codegen->builtin_types.entry_usize; |
| 682 | 689 | const_instruction->base.value.special = ConstValSpecialStatic; |
| 683 | bignum_init_unsigned(&const_instruction->base.value.data.x_bignum, value); | |
| 690 | bigint_init_unsigned(&const_instruction->base.value.data.x_bigint, value); | |
| 684 | 691 | return &const_instruction->base; |
| 685 | 692 | } |
| 686 | 693 | |
| ... | ... | @@ -3687,15 +3694,21 @@ static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node) |
| 3687 | 3694 | zig_unreachable(); |
| 3688 | 3695 | } |
| 3689 | 3696 | |
| 3690 | static IrInstruction *ir_gen_num_lit(IrBuilder *irb, Scope *scope, AstNode *node) { | |
| 3691 | assert(node->type == NodeTypeNumberLiteral); | |
| 3697 | static IrInstruction *ir_gen_int_lit(IrBuilder *irb, Scope *scope, AstNode *node) { | |
| 3698 | assert(node->type == NodeTypeIntLiteral); | |
| 3699 | ||
| 3700 | return ir_build_const_bigint(irb, scope, node, node->data.int_literal.bigint); | |
| 3701 | } | |
| 3692 | 3702 | |
| 3693 | if (node->data.number_literal.overflow) { | |
| 3694 | add_node_error(irb->codegen, node, buf_sprintf("number literal too large to be represented in any type")); | |
| 3703 | static IrInstruction *ir_gen_float_lit(IrBuilder *irb, Scope *scope, AstNode *node) { | |
| 3704 | assert(node->type == NodeTypeFloatLiteral); | |
| 3705 | ||
| 3706 | if (node->data.float_literal.overflow) { | |
| 3707 | add_node_error(irb->codegen, node, buf_sprintf("float literal too large to be represented in any type")); | |
| 3695 | 3708 | return irb->codegen->invalid_instruction; |
| 3696 | 3709 | } |
| 3697 | 3710 | |
| 3698 | return ir_build_const_bignum(irb, scope, node, node->data.number_literal.bignum); | |
| 3711 | return ir_build_const_bigfloat(irb, scope, node, node->data.float_literal.bigfloat); | |
| 3699 | 3712 | } |
| 3700 | 3713 | |
| 3701 | 3714 | static IrInstruction *ir_gen_char_lit(IrBuilder *irb, Scope *scope, AstNode *node) { |
| ... | ... | @@ -5933,8 +5946,10 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop |
| 5933 | 5946 | return ir_gen_node_raw(irb, node->data.grouped_expr, scope, lval); |
| 5934 | 5947 | case NodeTypeBinOpExpr: |
| 5935 | 5948 | return ir_lval_wrap(irb, scope, ir_gen_bin_op(irb, scope, node), lval); |
| 5936 | case NodeTypeNumberLiteral: | |
| 5937 | return ir_lval_wrap(irb, scope, ir_gen_num_lit(irb, scope, node), lval); | |
| 5949 | case NodeTypeIntLiteral: | |
| 5950 | return ir_lval_wrap(irb, scope, ir_gen_int_lit(irb, scope, node), lval); | |
| 5951 | case NodeTypeFloatLiteral: | |
| 5952 | return ir_lval_wrap(irb, scope, ir_gen_float_lit(irb, scope, node), lval); | |
| 5938 | 5953 | case NodeTypeCharLiteral: |
| 5939 | 5954 | return ir_lval_wrap(irb, scope, ir_gen_char_lit(irb, scope, node), lval); |
| 5940 | 5955 | case NodeTypeSymbol: |
| ... | ... | @@ -6184,6 +6199,13 @@ static bool ir_emit_global_runtime_side_effect(IrAnalyze *ira, IrInstruction *so |
| 6184 | 6199 | return true; |
| 6185 | 6200 | } |
| 6186 | 6201 | |
| 6202 | static bool const_val_fits_in_num_lit(ConstExprValue *const_val, TypeTableEntry *num_lit_type) { | |
| 6203 | return ((num_lit_type->id == TypeTableEntryIdNumLitFloat && | |
| 6204 | (const_val->type->id == TypeTableEntryIdFloat || const_val->type->id == TypeTableEntryIdNumLitFloat)) || | |
| 6205 | (num_lit_type->id == TypeTableEntryIdNumLitInt && | |
| 6206 | (const_val->type->id == TypeTableEntryIdInt || const_val->type->id == TypeTableEntryIdNumLitInt))); | |
| 6207 | } | |
| 6208 | ||
| 6187 | 6209 | static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruction, TypeTableEntry *other_type) { |
| 6188 | 6210 | if (type_is_invalid(other_type)) { |
| 6189 | 6211 | return false; |
| ... | ... | @@ -6191,44 +6213,51 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruc |
| 6191 | 6213 | |
| 6192 | 6214 | ConstExprValue *const_val = &instruction->value; |
| 6193 | 6215 | assert(const_val->special != ConstValSpecialRuntime); |
| 6216 | ||
| 6217 | bool const_val_is_int = (const_val->type->id == TypeTableEntryIdInt || | |
| 6218 | const_val->type->id == TypeTableEntryIdNumLitInt); | |
| 6219 | bool const_val_is_float = (const_val->type->id == TypeTableEntryIdFloat || | |
| 6220 | const_val->type->id == TypeTableEntryIdNumLitFloat); | |
| 6194 | 6221 | if (other_type->id == TypeTableEntryIdFloat) { |
| 6195 | 6222 | return true; |
| 6196 | } else if (other_type->id == TypeTableEntryIdInt && | |
| 6197 | const_val->data.x_bignum.kind == BigNumKindInt) | |
| 6198 | { | |
| 6199 | if (bignum_fits_in_bits(&const_val->data.x_bignum, other_type->data.integral.bit_count, | |
| 6223 | } else if (other_type->id == TypeTableEntryIdInt && const_val_is_int) { | |
| 6224 | if (bigint_fits_in_bits(&const_val->data.x_bigint, other_type->data.integral.bit_count, | |
| 6200 | 6225 | other_type->data.integral.is_signed)) |
| 6201 | 6226 | { |
| 6202 | 6227 | return true; |
| 6203 | 6228 | } |
| 6204 | } else if ((other_type->id == TypeTableEntryIdNumLitFloat && const_val->data.x_bignum.kind == BigNumKindFloat) || | |
| 6205 | (other_type->id == TypeTableEntryIdNumLitInt && const_val->data.x_bignum.kind == BigNumKindInt )) | |
| 6206 | { | |
| 6229 | } else if (const_val_fits_in_num_lit(const_val, other_type)) { | |
| 6207 | 6230 | return true; |
| 6208 | 6231 | } else if (other_type->id == TypeTableEntryIdMaybe) { |
| 6209 | 6232 | TypeTableEntry *child_type = other_type->data.maybe.child_type; |
| 6210 | if ((child_type->id == TypeTableEntryIdNumLitFloat && const_val->data.x_bignum.kind == BigNumKindFloat) || | |
| 6211 | (child_type->id == TypeTableEntryIdNumLitInt && const_val->data.x_bignum.kind == BigNumKindInt )) | |
| 6212 | { | |
| 6233 | if (const_val_fits_in_num_lit(const_val, child_type)) { | |
| 6213 | 6234 | return true; |
| 6214 | } else if (child_type->id == TypeTableEntryIdInt && const_val->data.x_bignum.kind == BigNumKindInt) { | |
| 6215 | if (bignum_fits_in_bits(&const_val->data.x_bignum, | |
| 6235 | } else if (child_type->id == TypeTableEntryIdInt && const_val_is_int) { | |
| 6236 | if (bigint_fits_in_bits(&const_val->data.x_bigint, | |
| 6216 | 6237 | child_type->data.integral.bit_count, |
| 6217 | 6238 | child_type->data.integral.is_signed)) |
| 6218 | 6239 | { |
| 6219 | 6240 | return true; |
| 6220 | 6241 | } |
| 6221 | } else if (child_type->id == TypeTableEntryIdFloat && const_val->data.x_bignum.kind == BigNumKindFloat) { | |
| 6242 | } else if (child_type->id == TypeTableEntryIdFloat && const_val_is_float) { | |
| 6222 | 6243 | return true; |
| 6223 | 6244 | } |
| 6224 | 6245 | } |
| 6225 | 6246 | |
| 6226 | const char *num_lit_str = (const_val->data.x_bignum.kind == BigNumKindFloat) ? "float" : "integer"; | |
| 6247 | const char *num_lit_str; | |
| 6248 | Buf *val_buf = buf_alloc(); | |
| 6249 | if (const_val_is_float) { | |
| 6250 | num_lit_str = "float"; | |
| 6251 | bigfloat_write_buf(val_buf, &const_val->data.x_bigfloat); | |
| 6252 | } else { | |
| 6253 | num_lit_str = "integer"; | |
| 6254 | bigint_write_buf(val_buf, &const_val->data.x_bigint, 10); | |
| 6255 | } | |
| 6227 | 6256 | |
| 6228 | 6257 | ir_add_error(ira, instruction, |
| 6229 | 6258 | buf_sprintf("%s value %s cannot be implicitly casted to type '%s'", |
| 6230 | 6259 | num_lit_str, |
| 6231 | buf_ptr(bignum_to_buf(&const_val->data.x_bignum)), | |
| 6260 | buf_ptr(val_buf), | |
| 6232 | 6261 | buf_ptr(&other_type->name))); |
| 6233 | 6262 | return false; |
| 6234 | 6263 | } |
| ... | ... | @@ -6643,7 +6672,13 @@ static void eval_const_expr_implicit_cast(CastOp cast_op, |
| 6643 | 6672 | break; |
| 6644 | 6673 | } |
| 6645 | 6674 | case CastOpNumLitToConcrete: |
| 6646 | const_val->data.x_bignum = other_val->data.x_bignum; | |
| 6675 | if (other_val->type->id == TypeTableEntryIdNumLitFloat) { | |
| 6676 | bigfloat_init_bigfloat(&const_val->data.x_bigfloat, &other_val->data.x_bigfloat); | |
| 6677 | } else if (other_val->type->id == TypeTableEntryIdNumLitInt) { | |
| 6678 | bigint_init_bigint(&const_val->data.x_bigint, &other_val->data.x_bigint); | |
| 6679 | } else { | |
| 6680 | zig_unreachable(); | |
| 6681 | } | |
| 6647 | 6682 | const_val->type = new_type; |
| 6648 | 6683 | break; |
| 6649 | 6684 | case CastOpResizeSlice: |
| ... | ... | @@ -6651,15 +6686,15 @@ static void eval_const_expr_implicit_cast(CastOp cast_op, |
| 6651 | 6686 | // can't do it |
| 6652 | 6687 | break; |
| 6653 | 6688 | case CastOpIntToFloat: |
| 6654 | bignum_cast_to_float(&const_val->data.x_bignum, &other_val->data.x_bignum); | |
| 6689 | bigfloat_init_bigint(&const_val->data.x_bigfloat, &other_val->data.x_bigint); | |
| 6655 | 6690 | const_val->special = ConstValSpecialStatic; |
| 6656 | 6691 | break; |
| 6657 | 6692 | case CastOpFloatToInt: |
| 6658 | bignum_cast_to_int(&const_val->data.x_bignum, &other_val->data.x_bignum); | |
| 6693 | bigint_init_bigfloat(&const_val->data.x_bigint, &other_val->data.x_bigfloat); | |
| 6659 | 6694 | const_val->special = ConstValSpecialStatic; |
| 6660 | 6695 | break; |
| 6661 | 6696 | case CastOpBoolToInt: |
| 6662 | bignum_init_unsigned(&const_val->data.x_bignum, other_val->data.x_bool ? 1 : 0); | |
| 6697 | bigint_init_unsigned(&const_val->data.x_bigint, other_val->data.x_bool ? 1 : 0); | |
| 6663 | 6698 | const_val->special = ConstValSpecialStatic; |
| 6664 | 6699 | break; |
| 6665 | 6700 | } |
| ... | ... | @@ -6878,7 +6913,7 @@ static TypeTableEntry *ir_analyze_const_ptr(IrAnalyze *ira, IrInstruction *instr |
| 6878 | 6913 | |
| 6879 | 6914 | static TypeTableEntry *ir_analyze_const_usize(IrAnalyze *ira, IrInstruction *instruction, uint64_t value) { |
| 6880 | 6915 | ConstExprValue *const_val = ir_build_const_from(ira, instruction); |
| 6881 | bignum_init_unsigned(&const_val->data.x_bignum, value); | |
| 6916 | bigint_init_unsigned(&const_val->data.x_bigint, value); | |
| 6882 | 6917 | return ira->codegen->builtin_types.entry_usize; |
| 6883 | 6918 | } |
| 6884 | 6919 | |
| ... | ... | @@ -7239,12 +7274,12 @@ static IrInstruction *ir_analyze_widen_or_shorten(IrAnalyze *ira, IrInstruction |
| 7239 | 7274 | if (!val) |
| 7240 | 7275 | return ira->codegen->invalid_instruction; |
| 7241 | 7276 | if (wanted_type->id == TypeTableEntryIdInt) { |
| 7242 | if (val->data.x_bignum.is_negative && !wanted_type->data.integral.is_signed) { | |
| 7277 | if (bigint_cmp_zero(&val->data.x_bigint) == CmpLT && !wanted_type->data.integral.is_signed) { | |
| 7243 | 7278 | ir_add_error(ira, source_instr, |
| 7244 | 7279 | buf_sprintf("attempt to cast negative value to unsigned integer")); |
| 7245 | 7280 | return ira->codegen->invalid_instruction; |
| 7246 | 7281 | } |
| 7247 | if (!bignum_fits_in_bits(&val->data.x_bignum, wanted_type->data.integral.bit_count, | |
| 7282 | if (!bigint_fits_in_bits(&val->data.x_bigint, wanted_type->data.integral.bit_count, | |
| 7248 | 7283 | wanted_type->data.integral.is_signed)) |
| 7249 | 7284 | { |
| 7250 | 7285 | ir_add_error(ira, source_instr, |
| ... | ... | @@ -7255,7 +7290,11 @@ static IrInstruction *ir_analyze_widen_or_shorten(IrAnalyze *ira, IrInstruction |
| 7255 | 7290 | } |
| 7256 | 7291 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, |
| 7257 | 7292 | source_instr->source_node, wanted_type); |
| 7258 | result->value.data.x_bignum = val->data.x_bignum; | |
| 7293 | if (wanted_type->id == TypeTableEntryIdInt) { | |
| 7294 | bigint_init_bigint(&result->value.data.x_bigint, &val->data.x_bigint); | |
| 7295 | } else { | |
| 7296 | bigfloat_init_bigfloat(&result->value.data.x_bigfloat, &val->data.x_bigfloat); | |
| 7297 | } | |
| 7259 | 7298 | result->value.type = wanted_type; |
| 7260 | 7299 | return result; |
| 7261 | 7300 | } |
| ... | ... | @@ -7278,7 +7317,7 @@ static IrInstruction *ir_analyze_ptr_to_int(IrAnalyze *ira, IrInstruction *sourc |
| 7278 | 7317 | if (val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) { |
| 7279 | 7318 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, |
| 7280 | 7319 | source_instr->source_node, wanted_type); |
| 7281 | bignum_init_unsigned(&result->value.data.x_bignum, val->data.x_ptr.data.hard_coded_addr.addr); | |
| 7320 | bigint_init_unsigned(&result->value.data.x_bigint, val->data.x_ptr.data.hard_coded_addr.addr); | |
| 7282 | 7321 | return result; |
| 7283 | 7322 | } |
| 7284 | 7323 | } |
| ... | ... | @@ -7299,9 +7338,20 @@ static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *sour |
| 7299 | 7338 | ConstExprValue *val = ir_resolve_const(ira, target, UndefBad); |
| 7300 | 7339 | if (!val) |
| 7301 | 7340 | return ira->codegen->invalid_instruction; |
| 7341 | BigInt enum_member_count; | |
| 7342 | bigint_init_unsigned(&enum_member_count, wanted_type->data.enumeration.src_field_count); | |
| 7343 | if (bigint_cmp(&val->data.x_bigint, &enum_member_count) != CmpLT) { | |
| 7344 | Buf *val_buf = buf_alloc(); | |
| 7345 | bigint_write_buf(val_buf, &val->data.x_bigint, 10); | |
| 7346 | ir_add_error(ira, source_instr, | |
| 7347 | buf_sprintf("integer value %s too big for enum '%s' which has %" PRIu32 " fields", | |
| 7348 | buf_ptr(val_buf), buf_ptr(&wanted_type->name), wanted_type->data.enumeration.src_field_count)); | |
| 7349 | return ira->codegen->invalid_instruction; | |
| 7350 | } | |
| 7351 | ||
| 7302 | 7352 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, |
| 7303 | 7353 | source_instr->source_node, wanted_type); |
| 7304 | result->value.data.x_enum.tag = val->data.x_bignum.data.x_uint; | |
| 7354 | result->value.data.x_enum.tag = bigint_as_unsigned(&val->data.x_bigint); | |
| 7305 | 7355 | return result; |
| 7306 | 7356 | } |
| 7307 | 7357 | |
| ... | ... | @@ -7320,7 +7370,13 @@ static IrInstruction *ir_analyze_number_to_literal(IrAnalyze *ira, IrInstruction |
| 7320 | 7370 | |
| 7321 | 7371 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, |
| 7322 | 7372 | source_instr->source_node, wanted_type); |
| 7323 | bignum_init_bignum(&result->value.data.x_bignum, &val->data.x_bignum); | |
| 7373 | if (wanted_type->id == TypeTableEntryIdNumLitFloat) { | |
| 7374 | bigfloat_init_bigfloat(&result->value.data.x_bigfloat, &val->data.x_bigfloat); | |
| 7375 | } else if (wanted_type->id == TypeTableEntryIdNumLitInt) { | |
| 7376 | bigint_init_bigint(&result->value.data.x_bigint, &val->data.x_bigint); | |
| 7377 | } else { | |
| 7378 | zig_unreachable(); | |
| 7379 | } | |
| 7324 | 7380 | return result; |
| 7325 | 7381 | } |
| 7326 | 7382 | |
| ... | ... | @@ -7336,13 +7392,17 @@ static IrInstruction *ir_analyze_int_to_err(IrAnalyze *ira, IrInstruction *sourc |
| 7336 | 7392 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, |
| 7337 | 7393 | source_instr->source_node, ira->codegen->builtin_types.entry_pure_error); |
| 7338 | 7394 | |
| 7339 | uint64_t index = val->data.x_bignum.data.x_uint; | |
| 7340 | if (index == 0 || index >= ira->codegen->error_decls.length) { | |
| 7395 | BigInt err_count; | |
| 7396 | bigint_init_unsigned(&err_count, ira->codegen->error_decls.length); | |
| 7397 | if (bigint_cmp_zero(&val->data.x_bigint) == CmpEQ || bigint_cmp(&val->data.x_bigint, &err_count) != CmpLT) { | |
| 7398 | Buf *val_buf = buf_alloc(); | |
| 7399 | bigint_write_buf(val_buf, &val->data.x_bigint, 10); | |
| 7341 | 7400 | ir_add_error(ira, source_instr, |
| 7342 | buf_sprintf("integer value %" ZIG_PRI_u64 " represents no error", index)); | |
| 7401 | buf_sprintf("integer value %s represents no error", buf_ptr(val_buf))); | |
| 7343 | 7402 | return ira->codegen->invalid_instruction; |
| 7344 | 7403 | } |
| 7345 | 7404 | |
| 7405 | size_t index = bigint_as_unsigned(&val->data.x_bigint); | |
| 7346 | 7406 | AstNode *error_decl_node = ira->codegen->error_decls.at(index); |
| 7347 | 7407 | result->value.data.x_pure_err = error_decl_node->data.error_value_decl.err; |
| 7348 | 7408 | return result; |
| ... | ... | @@ -7378,9 +7438,9 @@ static IrInstruction *ir_analyze_err_to_int(IrAnalyze *ira, IrInstruction *sourc |
| 7378 | 7438 | } |
| 7379 | 7439 | result->value.type = wanted_type; |
| 7380 | 7440 | uint64_t err_value = err ? err->value : 0; |
| 7381 | bignum_init_unsigned(&result->value.data.x_bignum, err_value); | |
| 7441 | bigint_init_unsigned(&result->value.data.x_bigint, err_value); | |
| 7382 | 7442 | |
| 7383 | if (!bignum_fits_in_bits(&result->value.data.x_bignum, | |
| 7443 | if (!bigint_fits_in_bits(&result->value.data.x_bigint, | |
| 7384 | 7444 | wanted_type->data.integral.bit_count, wanted_type->data.integral.is_signed)) |
| 7385 | 7445 | { |
| 7386 | 7446 | ir_add_error_node(ira, source_instr->source_node, |
| ... | ... | @@ -7392,9 +7452,9 @@ static IrInstruction *ir_analyze_err_to_int(IrAnalyze *ira, IrInstruction *sourc |
| 7392 | 7452 | return result; |
| 7393 | 7453 | } |
| 7394 | 7454 | |
| 7395 | BigNum bn; | |
| 7396 | bignum_init_unsigned(&bn, ira->codegen->error_decls.length); | |
| 7397 | if (!bignum_fits_in_bits(&bn, wanted_type->data.integral.bit_count, wanted_type->data.integral.is_signed)) { | |
| 7455 | BigInt bn; | |
| 7456 | bigint_init_unsigned(&bn, ira->codegen->error_decls.length); | |
| 7457 | if (!bigint_fits_in_bits(&bn, wanted_type->data.integral.bit_count, wanted_type->data.integral.is_signed)) { | |
| 7398 | 7458 | ir_add_error_node(ira, source_instr->source_node, |
| 7399 | 7459 | buf_sprintf("too many error values to fit in '%s'", buf_ptr(&wanted_type->name))); |
| 7400 | 7460 | return ira->codegen->invalid_instruction; |
| ... | ... | @@ -7861,7 +7921,7 @@ static bool ir_resolve_usize(IrAnalyze *ira, IrInstruction *value, uint64_t *out |
| 7861 | 7921 | if (!const_val) |
| 7862 | 7922 | return false; |
| 7863 | 7923 | |
| 7864 | *out = const_val->data.x_bignum.data.x_uint; | |
| 7924 | *out = bigint_as_unsigned(&const_val->data.x_bigint); | |
| 7865 | 7925 | return true; |
| 7866 | 7926 | } |
| 7867 | 7927 | |
| ... | ... | @@ -7941,7 +8001,7 @@ static Buf *ir_resolve_str(IrAnalyze *ira, IrInstruction *value) { |
| 7941 | 8001 | assert(ptr_field->data.x_ptr.special == ConstPtrSpecialBaseArray); |
| 7942 | 8002 | ConstExprValue *array_val = ptr_field->data.x_ptr.data.base_array.array_val; |
| 7943 | 8003 | expand_undef_array(ira->codegen, array_val); |
| 7944 | size_t len = len_field->data.x_bignum.data.x_uint; | |
| 8004 | size_t len = bigint_as_unsigned(&len_field->data.x_bigint); | |
| 7945 | 8005 | Buf *result = buf_alloc(); |
| 7946 | 8006 | buf_resize(result, len); |
| 7947 | 8007 | for (size_t i = 0; i < len; i += 1) { |
| ... | ... | @@ -7951,7 +8011,7 @@ static Buf *ir_resolve_str(IrAnalyze *ira, IrInstruction *value) { |
| 7951 | 8011 | ir_add_error(ira, casted_value, buf_sprintf("use of undefined value")); |
| 7952 | 8012 | return nullptr; |
| 7953 | 8013 | } |
| 7954 | uint64_t big_c = char_val->data.x_bignum.data.x_uint; | |
| 8014 | uint64_t big_c = bigint_as_unsigned(&char_val->data.x_bigint); | |
| 7955 | 8015 | assert(big_c <= UINT8_MAX); |
| 7956 | 8016 | uint8_t c = (uint8_t)big_c; |
| 7957 | 8017 | buf_ptr(result)[i] = c; |
| ... | ... | @@ -8039,6 +8099,24 @@ static TypeTableEntry *ir_analyze_bin_op_bool(IrAnalyze *ira, IrInstructionBinOp |
| 8039 | 8099 | return bool_type; |
| 8040 | 8100 | } |
| 8041 | 8101 | |
| 8102 | static bool resolve_cmp_op_id(IrBinOp op_id, Cmp cmp) { | |
| 8103 | if (op_id == IrBinOpCmpEq) { | |
| 8104 | return cmp == CmpEQ; | |
| 8105 | } else if (op_id == IrBinOpCmpNotEq) { | |
| 8106 | return cmp != CmpEQ; | |
| 8107 | } else if (op_id == IrBinOpCmpLessThan) { | |
| 8108 | return cmp == CmpLT; | |
| 8109 | } else if (op_id == IrBinOpCmpGreaterThan) { | |
| 8110 | return cmp == CmpGT; | |
| 8111 | } else if (op_id == IrBinOpCmpLessOrEq) { | |
| 8112 | return cmp != CmpGT; | |
| 8113 | } else if (op_id == IrBinOpCmpGreaterOrEq) { | |
| 8114 | return cmp != CmpLT; | |
| 8115 | } else { | |
| 8116 | zig_unreachable(); | |
| 8117 | } | |
| 8118 | } | |
| 8119 | ||
| 8042 | 8120 | static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) { |
| 8043 | 8121 | IrInstruction *op1 = bin_op_instruction->op1->other; |
| 8044 | 8122 | IrInstruction *op2 = bin_op_instruction->op2->other; |
| ... | ... | @@ -8157,30 +8235,13 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp |
| 8157 | 8235 | ConstExprValue *op1_val = &casted_op1->value; |
| 8158 | 8236 | ConstExprValue *op2_val = &casted_op2->value; |
| 8159 | 8237 | if ((value_is_comptime(op1_val) && value_is_comptime(op2_val)) || resolved_type->id == TypeTableEntryIdVoid) { |
| 8160 | bool type_can_gt_lt_cmp = (resolved_type->id == TypeTableEntryIdNumLitFloat || | |
| 8161 | resolved_type->id == TypeTableEntryIdNumLitInt || | |
| 8162 | resolved_type->id == TypeTableEntryIdFloat || | |
| 8163 | resolved_type->id == TypeTableEntryIdInt); | |
| 8164 | 8238 | bool answer; |
| 8165 | if (type_can_gt_lt_cmp) { | |
| 8166 | bool (*bignum_cmp)(BigNum *, BigNum *); | |
| 8167 | if (op_id == IrBinOpCmpEq) { | |
| 8168 | bignum_cmp = bignum_cmp_eq; | |
| 8169 | } else if (op_id == IrBinOpCmpNotEq) { | |
| 8170 | bignum_cmp = bignum_cmp_neq; | |
| 8171 | } else if (op_id == IrBinOpCmpLessThan) { | |
| 8172 | bignum_cmp = bignum_cmp_lt; | |
| 8173 | } else if (op_id == IrBinOpCmpGreaterThan) { | |
| 8174 | bignum_cmp = bignum_cmp_gt; | |
| 8175 | } else if (op_id == IrBinOpCmpLessOrEq) { | |
| 8176 | bignum_cmp = bignum_cmp_lte; | |
| 8177 | } else if (op_id == IrBinOpCmpGreaterOrEq) { | |
| 8178 | bignum_cmp = bignum_cmp_gte; | |
| 8179 | } else { | |
| 8180 | zig_unreachable(); | |
| 8181 | } | |
| 8182 | ||
| 8183 | answer = bignum_cmp(&op1_val->data.x_bignum, &op2_val->data.x_bignum); | |
| 8239 | if (resolved_type->id == TypeTableEntryIdNumLitFloat || resolved_type->id == TypeTableEntryIdFloat) { | |
| 8240 | Cmp cmp_result = bigfloat_cmp(&op1_val->data.x_bigfloat, &op2_val->data.x_bigfloat); | |
| 8241 | answer = resolve_cmp_op_id(op_id, cmp_result); | |
| 8242 | } else if (resolved_type->id == TypeTableEntryIdNumLitInt || resolved_type->id == TypeTableEntryIdInt) { | |
| 8243 | Cmp cmp_result = bigint_cmp(&op1_val->data.x_bigint, &op2_val->data.x_bigint); | |
| 8244 | answer = resolve_cmp_op_id(op_id, cmp_result); | |
| 8184 | 8245 | } else { |
| 8185 | 8246 | bool are_equal = resolved_type->id == TypeTableEntryIdVoid || const_values_equal(op1_val, op2_val); |
| 8186 | 8247 | if (op_id == IrBinOpCmpEq) { |
| ... | ... | @@ -8220,7 +8281,7 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp |
| 8220 | 8281 | } else { |
| 8221 | 8282 | known_left_val = nullptr; |
| 8222 | 8283 | } |
| 8223 | if (known_left_val != nullptr && known_left_val->data.x_bignum.data.x_uint == 0 && | |
| 8284 | if (known_left_val != nullptr && bigint_cmp_zero(&known_left_val->data.x_bigint) == CmpEQ && | |
| 8224 | 8285 | (flipped_op_id == IrBinOpCmpLessOrEq || flipped_op_id == IrBinOpCmpGreaterThan)) |
| 8225 | 8286 | { |
| 8226 | 8287 | bool answer = (flipped_op_id == IrBinOpCmpLessOrEq); |
| ... | ... | @@ -8236,101 +8297,35 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp |
| 8236 | 8297 | return ira->codegen->builtin_types.entry_bool; |
| 8237 | 8298 | } |
| 8238 | 8299 | |
| 8239 | enum EvalBigNumSpecial { | |
| 8240 | EvalBigNumSpecialNone, | |
| 8241 | EvalBigNumSpecialWrapping, | |
| 8242 | EvalBigNumSpecialExact, | |
| 8243 | }; | |
| 8244 | ||
| 8245 | static int ir_eval_bignum(ConstExprValue *op1_val, ConstExprValue *op2_val, | |
| 8246 | ConstExprValue *out_val, bool (*bignum_fn)(BigNum *, BigNum *, BigNum *), | |
| 8247 | TypeTableEntry *type, EvalBigNumSpecial special) | |
| 8300 | static int ir_eval_math_op(TypeTableEntry *type_entry, ConstExprValue *op1_val, | |
| 8301 | IrBinOp op_id, ConstExprValue *op2_val, ConstExprValue *out_val) | |
| 8248 | 8302 | { |
| 8249 | bool is_int = false; | |
| 8250 | bool is_float = false; | |
| 8251 | if (type->id == TypeTableEntryIdInt || | |
| 8252 | type->id == TypeTableEntryIdNumLitInt) | |
| 8253 | { | |
| 8303 | bool is_int; | |
| 8304 | bool is_float; | |
| 8305 | Cmp op2_zcmp; | |
| 8306 | if (type_entry->id == TypeTableEntryIdInt || type_entry->id == TypeTableEntryIdNumLitInt) { | |
| 8254 | 8307 | is_int = true; |
| 8255 | } else if (type->id == TypeTableEntryIdFloat || | |
| 8256 | type->id == TypeTableEntryIdNumLitFloat) | |
| 8308 | is_float = false; | |
| 8309 | op2_zcmp = bigint_cmp_zero(&op2_val->data.x_bigint); | |
| 8310 | } else if (type_entry->id == TypeTableEntryIdFloat || | |
| 8311 | type_entry->id == TypeTableEntryIdNumLitFloat) | |
| 8257 | 8312 | { |
| 8313 | is_int = false; | |
| 8258 | 8314 | is_float = true; |
| 8315 | op2_zcmp = bigfloat_cmp_zero(&op2_val->data.x_bigfloat); | |
| 8259 | 8316 | } else { |
| 8260 | 8317 | zig_unreachable(); |
| 8261 | 8318 | } |
| 8262 | if (bignum_fn == bignum_div || bignum_fn == bignum_rem || bignum_fn == bignum_mod || | |
| 8263 | bignum_fn == bignum_div_trunc || bignum_fn == bignum_div_floor) | |
| 8264 | { | |
| 8265 | if ((is_int && op2_val->data.x_bignum.data.x_uint == 0) || | |
| 8266 | (is_float && op2_val->data.x_bignum.data.x_float == 0.0)) | |
| 8267 | { | |
| 8268 | return ErrorDivByZero; | |
| 8269 | } | |
| 8270 | } | |
| 8271 | if (bignum_fn == bignum_rem || bignum_fn == bignum_mod) { | |
| 8272 | BigNum zero; | |
| 8273 | if (is_float) { | |
| 8274 | bignum_init_float(&zero, 0.0); | |
| 8275 | } else { | |
| 8276 | bignum_init_unsigned(&zero, 0); | |
| 8277 | } | |
| 8278 | if (bignum_cmp_lt(&op2_val->data.x_bignum, &zero)) { | |
| 8279 | return ErrorNegativeDenominator; | |
| 8280 | } | |
| 8281 | } | |
| 8282 | ||
| 8283 | if (special == EvalBigNumSpecialExact) { | |
| 8284 | assert(bignum_fn == bignum_div); | |
| 8285 | BigNum remainder; | |
| 8286 | if (bignum_rem(&remainder, &op1_val->data.x_bignum, &op2_val->data.x_bignum)) { | |
| 8287 | return ErrorOverflow; | |
| 8288 | } | |
| 8289 | BigNum zero; | |
| 8290 | if (is_float) { | |
| 8291 | bignum_init_float(&zero, 0.0); | |
| 8292 | } else { | |
| 8293 | bignum_init_unsigned(&zero, 0); | |
| 8294 | } | |
| 8295 | if (bignum_cmp_neq(&remainder, &zero)) { | |
| 8296 | return ErrorExactDivRemainder; | |
| 8297 | } | |
| 8298 | } | |
| 8299 | ||
| 8300 | bool overflow = bignum_fn(&out_val->data.x_bignum, &op1_val->data.x_bignum, &op2_val->data.x_bignum); | |
| 8301 | if (overflow) { | |
| 8302 | if (special == EvalBigNumSpecialWrapping) { | |
| 8303 | zig_panic("TODO compiler bug, implement compile-time wrapping arithmetic for >= 64 bit ints"); | |
| 8304 | } else { | |
| 8305 | return ErrorOverflow; | |
| 8306 | } | |
| 8307 | } | |
| 8308 | 8319 | |
| 8309 | if (type->id == TypeTableEntryIdInt && !bignum_fits_in_bits(&out_val->data.x_bignum, | |
| 8310 | type->data.integral.bit_count, type->data.integral.is_signed)) | |
| 8320 | if ((op_id == IrBinOpDivUnspecified || op_id == IrBinOpRemRem || op_id == IrBinOpRemMod || | |
| 8321 | op_id == IrBinOpDivTrunc || op_id == IrBinOpDivFloor) && op2_zcmp == CmpEQ) | |
| 8311 | 8322 | { |
| 8312 | if (special == EvalBigNumSpecialWrapping) { | |
| 8313 | if (type->data.integral.is_signed) { | |
| 8314 | out_val->data.x_bignum.data.x_uint = max_unsigned_val(type) - out_val->data.x_bignum.data.x_uint + 1; | |
| 8315 | out_val->data.x_bignum.is_negative = !out_val->data.x_bignum.is_negative; | |
| 8316 | } else if (out_val->data.x_bignum.is_negative) { | |
| 8317 | out_val->data.x_bignum.data.x_uint = max_unsigned_val(type) - out_val->data.x_bignum.data.x_uint + 1; | |
| 8318 | out_val->data.x_bignum.is_negative = false; | |
| 8319 | } else { | |
| 8320 | bignum_truncate(&out_val->data.x_bignum, type->data.integral.bit_count); | |
| 8321 | } | |
| 8322 | } else { | |
| 8323 | return ErrorOverflow; | |
| 8324 | } | |
| 8323 | return ErrorDivByZero; | |
| 8324 | } | |
| 8325 | if ((op_id == IrBinOpRemRem || op_id == IrBinOpRemMod) && op2_zcmp == CmpLT) { | |
| 8326 | return ErrorNegativeDenominator; | |
| 8325 | 8327 | } |
| 8326 | 8328 | |
| 8327 | out_val->special = ConstValSpecialStatic; | |
| 8328 | return 0; | |
| 8329 | } | |
| 8330 | ||
| 8331 | static int ir_eval_math_op(TypeTableEntry *canon_type, ConstExprValue *op1_val, | |
| 8332 | IrBinOp op_id, ConstExprValue *op2_val, ConstExprValue *out_val) | |
| 8333 | { | |
| 8334 | 8329 | switch (op_id) { |
| 8335 | 8330 | case IrBinOpInvalid: |
| 8336 | 8331 | case IrBinOpBoolOr: |
| ... | ... | @@ -8346,43 +8341,128 @@ static int ir_eval_math_op(TypeTableEntry *canon_type, ConstExprValue *op1_val, |
| 8346 | 8341 | case IrBinOpRemUnspecified: |
| 8347 | 8342 | zig_unreachable(); |
| 8348 | 8343 | case IrBinOpBinOr: |
| 8349 | return ir_eval_bignum(op1_val, op2_val, out_val, bignum_or, canon_type, EvalBigNumSpecialNone); | |
| 8344 | assert(is_int); | |
| 8345 | bigint_or(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); | |
| 8346 | break; | |
| 8350 | 8347 | case IrBinOpBinXor: |
| 8351 | return ir_eval_bignum(op1_val, op2_val, out_val, bignum_xor, canon_type, EvalBigNumSpecialNone); | |
| 8348 | assert(is_int); | |
| 8349 | bigint_xor(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); | |
| 8350 | break; | |
| 8352 | 8351 | case IrBinOpBinAnd: |
| 8353 | return ir_eval_bignum(op1_val, op2_val, out_val, bignum_and, canon_type, EvalBigNumSpecialNone); | |
| 8352 | assert(is_int); | |
| 8353 | bigint_and(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); | |
| 8354 | break; | |
| 8354 | 8355 | case IrBinOpBitShiftLeft: |
| 8355 | return ir_eval_bignum(op1_val, op2_val, out_val, bignum_shl, canon_type, EvalBigNumSpecialNone); | |
| 8356 | assert(is_int); | |
| 8357 | bigint_shl(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); | |
| 8358 | break; | |
| 8356 | 8359 | case IrBinOpBitShiftLeftWrap: |
| 8357 | return ir_eval_bignum(op1_val, op2_val, out_val, bignum_shl, canon_type, EvalBigNumSpecialWrapping); | |
| 8360 | assert(type_entry->id == TypeTableEntryIdInt); | |
| 8361 | bigint_shl_wrap(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint, | |
| 8362 | type_entry->data.integral.bit_count, type_entry->data.integral.is_signed); | |
| 8363 | break; | |
| 8358 | 8364 | case IrBinOpBitShiftRight: |
| 8359 | return ir_eval_bignum(op1_val, op2_val, out_val, bignum_shr, canon_type, EvalBigNumSpecialNone); | |
| 8365 | assert(is_int); | |
| 8366 | bigint_shr(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); | |
| 8367 | break; | |
| 8360 | 8368 | case IrBinOpAdd: |
| 8361 | return ir_eval_bignum(op1_val, op2_val, out_val, bignum_add, canon_type, EvalBigNumSpecialNone); | |
| 8369 | if (is_int) { | |
| 8370 | bigint_add(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); | |
| 8371 | } else { | |
| 8372 | bigfloat_add(&out_val->data.x_bigfloat, &op1_val->data.x_bigfloat, &op2_val->data.x_bigfloat); | |
| 8373 | } | |
| 8374 | break; | |
| 8362 | 8375 | case IrBinOpAddWrap: |
| 8363 | return ir_eval_bignum(op1_val, op2_val, out_val, bignum_add, canon_type, EvalBigNumSpecialWrapping); | |
| 8376 | assert(type_entry->id == TypeTableEntryIdInt); | |
| 8377 | bigint_add_wrap(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint, | |
| 8378 | type_entry->data.integral.bit_count, type_entry->data.integral.is_signed); | |
| 8379 | break; | |
| 8364 | 8380 | case IrBinOpSub: |
| 8365 | return ir_eval_bignum(op1_val, op2_val, out_val, bignum_sub, canon_type, EvalBigNumSpecialNone); | |
| 8381 | if (is_int) { | |
| 8382 | bigint_sub(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); | |
| 8383 | } else { | |
| 8384 | bigfloat_sub(&out_val->data.x_bigfloat, &op1_val->data.x_bigfloat, &op2_val->data.x_bigfloat); | |
| 8385 | } | |
| 8386 | break; | |
| 8366 | 8387 | case IrBinOpSubWrap: |
| 8367 | return ir_eval_bignum(op1_val, op2_val, out_val, bignum_sub, canon_type, EvalBigNumSpecialWrapping); | |
| 8388 | assert(type_entry->id == TypeTableEntryIdInt); | |
| 8389 | bigint_sub_wrap(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint, | |
| 8390 | type_entry->data.integral.bit_count, type_entry->data.integral.is_signed); | |
| 8391 | break; | |
| 8368 | 8392 | case IrBinOpMult: |
| 8369 | return ir_eval_bignum(op1_val, op2_val, out_val, bignum_mul, canon_type, EvalBigNumSpecialNone); | |
| 8393 | if (is_int) { | |
| 8394 | bigint_mul(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); | |
| 8395 | } else { | |
| 8396 | bigfloat_mul(&out_val->data.x_bigfloat, &op1_val->data.x_bigfloat, &op2_val->data.x_bigfloat); | |
| 8397 | } | |
| 8398 | break; | |
| 8370 | 8399 | case IrBinOpMultWrap: |
| 8371 | return ir_eval_bignum(op1_val, op2_val, out_val, bignum_mul, canon_type, EvalBigNumSpecialWrapping); | |
| 8400 | assert(type_entry->id == TypeTableEntryIdInt); | |
| 8401 | bigint_mul_wrap(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint, | |
| 8402 | type_entry->data.integral.bit_count, type_entry->data.integral.is_signed); | |
| 8403 | break; | |
| 8372 | 8404 | case IrBinOpDivUnspecified: |
| 8373 | return ir_eval_bignum(op1_val, op2_val, out_val, bignum_div, canon_type, EvalBigNumSpecialNone); | |
| 8405 | assert(is_float); | |
| 8406 | bigfloat_div(&out_val->data.x_bigfloat, &op1_val->data.x_bigfloat, &op2_val->data.x_bigfloat); | |
| 8407 | break; | |
| 8374 | 8408 | case IrBinOpDivTrunc: |
| 8375 | return ir_eval_bignum(op1_val, op2_val, out_val, bignum_div_trunc, canon_type, EvalBigNumSpecialNone); | |
| 8409 | if (is_int) { | |
| 8410 | bigint_div_trunc(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); | |
| 8411 | } else { | |
| 8412 | bigfloat_div_trunc(&out_val->data.x_bigfloat, &op1_val->data.x_bigfloat, &op2_val->data.x_bigfloat); | |
| 8413 | } | |
| 8414 | break; | |
| 8376 | 8415 | case IrBinOpDivFloor: |
| 8377 | return ir_eval_bignum(op1_val, op2_val, out_val, bignum_div_floor, canon_type, EvalBigNumSpecialNone); | |
| 8416 | if (is_int) { | |
| 8417 | bigint_div_floor(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); | |
| 8418 | } else { | |
| 8419 | bigfloat_div_floor(&out_val->data.x_bigfloat, &op1_val->data.x_bigfloat, &op2_val->data.x_bigfloat); | |
| 8420 | } | |
| 8421 | break; | |
| 8378 | 8422 | case IrBinOpDivExact: |
| 8379 | return ir_eval_bignum(op1_val, op2_val, out_val, bignum_div, canon_type, EvalBigNumSpecialExact); | |
| 8423 | if (is_int) { | |
| 8424 | bigint_div_trunc(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); | |
| 8425 | BigInt remainder; | |
| 8426 | bigint_rem(&remainder, &op1_val->data.x_bigint, &op2_val->data.x_bigint); | |
| 8427 | if (bigint_cmp_zero(&remainder) != CmpEQ) { | |
| 8428 | return ErrorExactDivRemainder; | |
| 8429 | } | |
| 8430 | } else { | |
| 8431 | bigfloat_div_trunc(&out_val->data.x_bigfloat, &op1_val->data.x_bigfloat, &op2_val->data.x_bigfloat); | |
| 8432 | BigFloat remainder; | |
| 8433 | bigfloat_rem(&remainder, &op1_val->data.x_bigfloat, &op2_val->data.x_bigfloat); | |
| 8434 | if (bigfloat_cmp_zero(&remainder) != CmpEQ) { | |
| 8435 | return ErrorExactDivRemainder; | |
| 8436 | } | |
| 8437 | } | |
| 8438 | break; | |
| 8380 | 8439 | case IrBinOpRemRem: |
| 8381 | return ir_eval_bignum(op1_val, op2_val, out_val, bignum_rem, canon_type, EvalBigNumSpecialNone); | |
| 8440 | if (is_int) { | |
| 8441 | bigint_rem(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); | |
| 8442 | } else { | |
| 8443 | bigfloat_rem(&out_val->data.x_bigfloat, &op1_val->data.x_bigfloat, &op2_val->data.x_bigfloat); | |
| 8444 | } | |
| 8445 | break; | |
| 8382 | 8446 | case IrBinOpRemMod: |
| 8383 | return ir_eval_bignum(op1_val, op2_val, out_val, bignum_mod, canon_type, EvalBigNumSpecialNone); | |
| 8447 | if (is_int) { | |
| 8448 | bigint_mod(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); | |
| 8449 | } else { | |
| 8450 | bigfloat_mod(&out_val->data.x_bigfloat, &op1_val->data.x_bigfloat, &op2_val->data.x_bigfloat); | |
| 8451 | } | |
| 8452 | break; | |
| 8384 | 8453 | } |
| 8385 | zig_unreachable(); | |
| 8454 | ||
| 8455 | if (type_entry->id == TypeTableEntryIdInt) { | |
| 8456 | if (!bigint_fits_in_bits(&out_val->data.x_bigint, type_entry->data.integral.bit_count, | |
| 8457 | type_entry->data.integral.is_signed)) | |
| 8458 | { | |
| 8459 | return ErrorOverflow; | |
| 8460 | } | |
| 8461 | } | |
| 8462 | ||
| 8463 | out_val->type = type_entry; | |
| 8464 | out_val->special = ConstValSpecialStatic; | |
| 8465 | return 0; | |
| 8386 | 8466 | } |
| 8387 | 8467 | |
| 8388 | 8468 | static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) { |
| ... | ... | @@ -8395,31 +8475,32 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp |
| 8395 | 8475 | IrBinOp op_id = bin_op_instruction->op_id; |
| 8396 | 8476 | |
| 8397 | 8477 | bool is_int = resolved_type->id == TypeTableEntryIdInt || resolved_type->id == TypeTableEntryIdNumLitInt; |
| 8398 | bool is_signed = ((resolved_type->id == TypeTableEntryIdInt && resolved_type->data.integral.is_signed) || | |
| 8399 | resolved_type->id == TypeTableEntryIdFloat || | |
| 8400 | (resolved_type->id == TypeTableEntryIdNumLitFloat && | |
| 8401 | (op1->value.data.x_bignum.data.x_float < 0.0 || op2->value.data.x_bignum.data.x_float < 0.0)) || | |
| 8402 | (resolved_type->id == TypeTableEntryIdNumLitInt && | |
| 8403 | (op1->value.data.x_bignum.is_negative || op2->value.data.x_bignum.is_negative))); | |
| 8404 | if (op_id == IrBinOpDivUnspecified) { | |
| 8405 | if (is_int && is_signed) { | |
| 8478 | bool is_float = resolved_type->id == TypeTableEntryIdFloat || resolved_type->id == TypeTableEntryIdNumLitFloat; | |
| 8479 | bool is_signed_div = ( | |
| 8480 | (resolved_type->id == TypeTableEntryIdInt && resolved_type->data.integral.is_signed) || | |
| 8481 | resolved_type->id == TypeTableEntryIdFloat || | |
| 8482 | (resolved_type->id == TypeTableEntryIdNumLitFloat && | |
| 8483 | ((bigfloat_cmp_zero(&op1->value.data.x_bigfloat) != CmpGT) != | |
| 8484 | (bigfloat_cmp_zero(&op2->value.data.x_bigfloat) != CmpGT))) || | |
| 8485 | (resolved_type->id == TypeTableEntryIdNumLitInt && | |
| 8486 | ((bigint_cmp_zero(&op1->value.data.x_bigint) != CmpGT) != | |
| 8487 | (bigint_cmp_zero(&op2->value.data.x_bigint) != CmpGT))) | |
| 8488 | ); | |
| 8489 | if (op_id == IrBinOpDivUnspecified && is_int) { | |
| 8490 | if (is_signed_div) { | |
| 8406 | 8491 | bool ok = false; |
| 8407 | 8492 | if (instr_is_comptime(op1) && instr_is_comptime(op2)) { |
| 8408 | 				if (op2->value.data.x_bignum.data.x_uint == 0) { | |
| 8493 | 				if (bigint_cmp_zero(&op2->value.data.x_bigint) == CmpEQ) { | |
| 8409 | 8494 | // the division by zero error will be caught later, but we don't have a |
| 8410 | 8495 | // division function ambiguity problem. |
| 8411 | 8496 | op_id = IrBinOpDivTrunc; |
| 8412 | 8497 | 					ok = true; |
| 8413 | 8498 | 				} else { |
| 8414 | 					BigNum trunc_result; | |
| 8415 | 					BigNum floor_result; | |
| 8416 | 					if (bignum_div_trunc(&trunc_result, &op1->value.data.x_bignum, &op2->value.data.x_bignum)) { | |
| 8417 | 						zig_unreachable(); | |
| 8418 | 					} | |
| 8419 | 					if (bignum_div_floor(&floor_result, &op1->value.data.x_bignum, &op2->value.data.x_bignum)) { | |
| 8420 | 						zig_unreachable(); | |
| 8421 | 					} | |
| 8422 | 					if (bignum_cmp_eq(&trunc_result, &floor_result)) { | |
| 8499 | 					BigInt trunc_result; | |
| 8500 | 					BigInt floor_result; | |
| 8501 | 					bigint_div_trunc(&trunc_result, &op1->value.data.x_bigint, &op2->value.data.x_bigint); | |
| 8502 | 					bigint_div_floor(&floor_result, &op1->value.data.x_bigint, &op2->value.data.x_bigint); | |
| 8503 | 					if (bigint_cmp(&trunc_result, &floor_result) == CmpEQ) { | |
| 8423 | 8504 | 						ok = true; |
| 8424 | 8505 | 						op_id = IrBinOpDivTrunc; |
| 8425 | 8506 | 					} |
| ... | ... | @@ -8432,29 +8513,37 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp |
| 8432 | 8513 | buf_ptr(&op2->value.type->name))); |
| 8433 | 8514 | return ira->codegen->builtin_types.entry_invalid; |
| 8434 | 8515 | } |
| 8435 | } else if (is_int) { | |
| 8516 | } else { | |
| 8436 | 8517 | op_id = IrBinOpDivTrunc; |
| 8437 | 8518 | } |
| 8438 | 8519 | } else if (op_id == IrBinOpRemUnspecified) { |
| 8439 | if (is_signed) { | |
| 8520 | if (is_signed_div && (is_int || is_float)) { | |
| 8440 | 8521 | bool ok = false; |
| 8441 | 8522 | if (instr_is_comptime(op1) && instr_is_comptime(op2)) { |
| 8442 | if ((is_int && op2->value.data.x_bignum.data.x_uint == 0) || | |
| 8443 | (!is_int && op2->value.data.x_bignum.data.x_float == 0.0)) | |
| 8444 | { | |
| 8445 | // the division by zero error will be caught later, but we don't | |
| 8446 | // have a remainder function ambiguity problem | |
| 8447 | ok = true; | |
| 8448 | } else { | |
| 8449 | BigNum rem_result; | |
| 8450 | BigNum mod_result; | |
| 8451 | if (bignum_rem(&rem_result, &op1->value.data.x_bignum, &op2->value.data.x_bignum)) { | |
| 8452 | zig_unreachable(); | |
| 8523 | if (is_int) { | |
| 8524 | if (bigint_cmp_zero(&op2->value.data.x_bigint) == CmpEQ) { | |
| 8525 | // the division by zero error will be caught later, but we don't | |
| 8526 | // have a remainder function ambiguity problem | |
| 8527 | ok = true; | |
| 8528 | } else { | |
| 8529 | BigInt rem_result; | |
| 8530 | BigInt mod_result; | |
| 8531 | bigint_rem(&rem_result, &op1->value.data.x_bigint, &op2->value.data.x_bigint); | |
| 8532 | bigint_mod(&mod_result, &op1->value.data.x_bigint, &op2->value.data.x_bigint); | |
| 8533 | ok = bigint_cmp(&rem_result, &mod_result) == CmpEQ; | |
| 8453 | 8534 | } |
| 8454 | if (bignum_mod(&mod_result, &op1->value.data.x_bignum, &op2->value.data.x_bignum)) { | |
| 8455 | zig_unreachable(); | |
| 8535 | } else { | |
| 8536 | if (bigfloat_cmp_zero(&op2->value.data.x_bigfloat) == CmpEQ) { | |
| 8537 | // the division by zero error will be caught later, but we don't | |
| 8538 | // have a remainder function ambiguity problem | |
| 8539 | ok = true; | |
| 8540 | } else { | |
| 8541 | BigFloat rem_result; | |
| 8542 | BigFloat mod_result; | |
| 8543 | bigfloat_rem(&rem_result, &op1->value.data.x_bigfloat, &op2->value.data.x_bigfloat); | |
| 8544 | bigfloat_mod(&mod_result, &op1->value.data.x_bigfloat, &op2->value.data.x_bigfloat); | |
| 8545 | ok = bigfloat_cmp(&rem_result, &mod_result) == CmpEQ; | |
| 8456 | 8546 | } |
| 8457 | ok = bignum_cmp_eq(&rem_result, &mod_result); | |
| 8458 | 8547 | } |
| 8459 | 8548 | } |
| 8460 | 8549 | if (!ok) { |
| ... | ... | @@ -8468,21 +8557,18 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp |
| 8468 | 8557 | op_id = IrBinOpRemRem; |
| 8469 | 8558 | } |
| 8470 | 8559 | |
| 8471 | if (resolved_type->id == TypeTableEntryIdInt || | |
| 8472 | resolved_type->id == TypeTableEntryIdNumLitInt) | |
| 8473 | { | |
| 8560 | if (is_int) { | |
| 8474 | 8561 | // int |
| 8475 | } else if ((resolved_type->id == TypeTableEntryIdFloat || | |
| 8476 | resolved_type->id == TypeTableEntryIdNumLitFloat) && | |
| 8562 | } else if (is_float && | |
| 8477 | 8563 | (op_id == IrBinOpAdd || |
| 8478 | op_id == IrBinOpSub || | |
| 8479 | op_id == IrBinOpMult || | |
| 8480 | op_id == IrBinOpDivUnspecified || | |
| 8481 | op_id == IrBinOpDivTrunc || | |
| 8482 | op_id == IrBinOpDivFloor || | |
| 8483 | op_id == IrBinOpDivExact || | |
| 8484 | op_id == IrBinOpRemRem || | |
| 8485 | op_id == IrBinOpRemMod)) | |
| 8564 | op_id == IrBinOpSub || | |
| 8565 | op_id == IrBinOpMult || | |
| 8566 | op_id == IrBinOpDivUnspecified || | |
| 8567 | op_id == IrBinOpDivTrunc || | |
| 8568 | op_id == IrBinOpDivFloor || | |
| 8569 | op_id == IrBinOpDivExact || | |
| 8570 | op_id == IrBinOpRemRem || | |
| 8571 | op_id == IrBinOpRemMod)) | |
| 8486 | 8572 | { |
| 8487 | 8573 | // float |
| 8488 | 8574 | } else { |
| ... | ... | @@ -8494,6 +8580,18 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp |
| 8494 | 8580 | return ira->codegen->builtin_types.entry_invalid; |
| 8495 | 8581 | } |
| 8496 | 8582 | |
| 8583 | if (resolved_type->id == TypeTableEntryIdNumLitInt) { | |
| 8584 | if (op_id == IrBinOpBitShiftLeftWrap) { | |
| 8585 | op_id = IrBinOpBitShiftLeft; | |
| 8586 | } else if (op_id == IrBinOpAddWrap) { | |
| 8587 | op_id = IrBinOpAdd; | |
| 8588 | } else if (op_id == IrBinOpSubWrap) { | |
| 8589 | op_id = IrBinOpSub; | |
| 8590 | } else if (op_id == IrBinOpMultWrap) { | |
| 8591 | op_id = IrBinOpMult; | |
| 8592 | } | |
| 8593 | } | |
| 8594 | ||
| 8497 | 8595 | IrInstruction *casted_op1 = ir_implicit_cast(ira, op1, resolved_type); |
| 8498 | 8596 | if (casted_op1 == ira->codegen->invalid_instruction) |
| 8499 | 8597 | return ira->codegen->builtin_types.entry_invalid; |
| ... | ... | @@ -8502,8 +8600,7 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp |
| 8502 | 8600 | if (casted_op2 == ira->codegen->invalid_instruction) |
| 8503 | 8601 | return ira->codegen->builtin_types.entry_invalid; |
| 8504 | 8602 | |
| 8505 | ||
| 8506 | if (casted_op1->value.special != ConstValSpecialRuntime && casted_op2->value.special != ConstValSpecialRuntime) { | |
| 8603 | if (instr_is_comptime(casted_op1) && instr_is_comptime(casted_op2)) { | |
| 8507 | 8604 | ConstExprValue *op1_val = &casted_op1->value; |
| 8508 | 8605 | ConstExprValue *op2_val = &casted_op2->value; |
| 8509 | 8606 | ConstExprValue *out_val = &bin_op_instruction->base.value; |
| ... | ... | @@ -8704,17 +8801,17 @@ static TypeTableEntry *ir_analyze_array_mult(IrAnalyze *ira, IrInstructionBinOp |
| 8704 | 8801 | } |
| 8705 | 8802 | |
| 8706 | 8803 | uint64_t old_array_len = array_type->data.array.len; |
| 8804 | uint64_t new_array_len; | |
| 8707 | 8805 | |
| 8708 | BigNum array_len; | |
| 8709 | bignum_init_unsigned(&array_len, old_array_len); | |
| 8710 | if (bignum_multiply_by_scalar(&array_len, mult_amt)) { | |
| 8806 | if (__builtin_umulll_overflow((unsigned long long)old_array_len, (unsigned long long)mult_amt, | |
| 8807 | (unsigned long long*)&new_array_len)) | |
| 8808 | { | |
| 8711 | 8809 | ir_add_error(ira, &instruction->base, buf_sprintf("operation results in overflow")); |
| 8712 | 8810 | return ira->codegen->builtin_types.entry_invalid; |
| 8713 | 8811 | } |
| 8714 | 8812 | |
| 8715 | 8813 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); |
| 8716 | 8814 | |
| 8717 | uint64_t new_array_len = array_len.data.x_uint; | |
| 8718 | 8815 | out_val->data.x_array.s_none.elements = create_const_vals(new_array_len); |
| 8719 | 8816 | |
| 8720 | 8817 | expand_undef_array(ira->codegen, array_val); |
| ... | ... | @@ -9581,9 +9678,10 @@ static TypeTableEntry *ir_analyze_negation(IrAnalyze *ira, IrInstructionUnOp *un |
| 9581 | 9678 | |
| 9582 | 9679 | bool is_wrap_op = (un_op_instruction->op_id == IrUnOpNegationWrap); |
| 9583 | 9680 | |
| 9681 | bool is_float = (expr_type->id == TypeTableEntryIdFloat || expr_type->id == TypeTableEntryIdNumLitFloat); | |
| 9682 | ||
| 9584 | 9683 | if ((expr_type->id == TypeTableEntryIdInt && expr_type->data.integral.is_signed) || |
| 9585 | expr_type->id == TypeTableEntryIdNumLitInt || | |
| 9586 | ((expr_type->id == TypeTableEntryIdFloat || expr_type->id == TypeTableEntryIdNumLitFloat) && !is_wrap_op)) | |
| 9684 | expr_type->id == TypeTableEntryIdNumLitInt || (is_float && !is_wrap_op)) | |
| 9587 | 9685 | { |
| 9588 | 9686 | if (instr_is_comptime(value)) { |
| 9589 | 9687 | ConstExprValue *target_const_val = ir_resolve_const(ira, value, UndefBad); |
| ... | ... | @@ -9591,19 +9689,19 @@ static TypeTableEntry *ir_analyze_negation(IrAnalyze *ira, IrInstructionUnOp *un |
| 9591 | 9689 | return ira->codegen->builtin_types.entry_invalid; |
| 9592 | 9690 | |
| 9593 | 9691 | ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base); |
| 9594 | bignum_negate(&out_val->data.x_bignum, &target_const_val->data.x_bignum); | |
| 9595 | if (expr_type->id == TypeTableEntryIdFloat || | |
| 9596 | expr_type->id == TypeTableEntryIdNumLitFloat || | |
| 9597 | expr_type->id == TypeTableEntryIdNumLitInt) | |
| 9598 | { | |
| 9692 | if (is_float) { | |
| 9693 | bigfloat_negate(&out_val->data.x_bigfloat, &target_const_val->data.x_bigfloat); | |
| 9694 | } else if (is_wrap_op) { | |
| 9695 | bigint_negate_wrap(&out_val->data.x_bigint, &target_const_val->data.x_bigint, | |
| 9696 | expr_type->data.integral.bit_count); | |
| 9697 | } else { | |
| 9698 | bigint_negate(&out_val->data.x_bigint, &target_const_val->data.x_bigint); | |
| 9699 | } | |
| 9700 | if (is_wrap_op || is_float || expr_type->id == TypeTableEntryIdNumLitInt) { | |
| 9599 | 9701 | return expr_type; |
| 9600 | 9702 | } |
| 9601 | 9703 | |
| 9602 | bool overflow = !bignum_fits_in_bits(&out_val->data.x_bignum, expr_type->data.integral.bit_count, true); | |
| 9603 | if (is_wrap_op) { | |
| 9604 | if (overflow) | |
| 9605 | out_val->data.x_bignum.is_negative = true; | |
| 9606 | } else if (overflow) { | |
| 9704 | if (!bigint_fits_in_bits(&out_val->data.x_bigint, expr_type->data.integral.bit_count, true)) { | |
| 9607 | 9705 | ir_add_error(ira, &un_op_instruction->base, buf_sprintf("negation caused overflow")); |
| 9608 | 9706 | return ira->codegen->builtin_types.entry_invalid; |
| 9609 | 9707 | } |
| ... | ... | @@ -9632,7 +9730,7 @@ static TypeTableEntry *ir_analyze_bin_not(IrAnalyze *ira, IrInstructionUnOp *ins |
| 9632 | 9730 | return ira->codegen->builtin_types.entry_invalid; |
| 9633 | 9731 | |
| 9634 | 9732 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); |
| 9635 | bignum_not(&out_val->data.x_bignum, &target_const_val->data.x_bignum, | |
| 9733 | bigint_not(&out_val->data.x_bigint, &target_const_val->data.x_bigint, | |
| 9636 | 9734 | expr_type->data.integral.bit_count, expr_type->data.integral.is_signed); |
| 9637 | 9735 | return expr_type; |
| 9638 | 9736 | } |
| ... | ... | @@ -9887,12 +9985,12 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc |
| 9887 | 9985 | return_type = get_pointer_to_type_extra(ira->codegen, child_type, |
| 9888 | 9986 | ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, 0, 0); |
| 9889 | 9987 | } else { |
| 9890 | ConstExprValue *elem_val = ir_resolve_const(ira, elem_index, UndefBad); | |
| 9891 | if (!elem_val) | |
| 9988 | uint64_t elem_val_scalar; | |
| 9989 | if (!ir_resolve_usize(ira, elem_index, &elem_val_scalar)) | |
| 9892 | 9990 | return ira->codegen->builtin_types.entry_invalid; |
| 9893 | 9991 | |
| 9894 | 9992 | size_t bit_width = type_size_bits(ira->codegen, child_type); |
| 9895 | size_t bit_offset = bit_width * elem_val->data.x_bignum.data.x_uint; | |
| 9993 | size_t bit_offset = bit_width * elem_val_scalar; | |
| 9896 | 9994 | |
| 9897 | 9995 | return_type = get_pointer_to_type_extra(ira->codegen, child_type, |
| 9898 | 9996 | ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, |
| ... | ... | @@ -9909,10 +10007,10 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc |
| 9909 | 10007 | ConstExprValue *args_val = const_ptr_pointee(ira->codegen, ptr_val); |
| 9910 | 10008 | size_t start = args_val->data.x_arg_tuple.start_index; |
| 9911 | 10009 | size_t end = args_val->data.x_arg_tuple.end_index; |
| 9912 | ConstExprValue *elem_index_val = ir_resolve_const(ira, elem_index, UndefBad); | |
| 9913 | if (!elem_index_val) | |
| 10010 | uint64_t elem_index_val; | |
| 10011 | if (!ir_resolve_usize(ira, elem_index, &elem_index_val)) | |
| 9914 | 10012 | return ira->codegen->builtin_types.entry_invalid; |
| 9915 | size_t index = bignum_to_twos_complement(&elem_index_val->data.x_bignum); | |
| 10013 | size_t index = elem_index_val; | |
| 9916 | 10014 | size_t len = end - start; |
| 9917 | 10015 | if (index >= len) { |
| 9918 | 10016 | ir_add_error(ira, &elem_ptr_instruction->base, |
| ... | ... | @@ -9945,7 +10043,7 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc |
| 9945 | 10043 | |
| 9946 | 10044 | bool safety_check_on = elem_ptr_instruction->safety_check_on; |
| 9947 | 10045 | if (instr_is_comptime(casted_elem_index)) { |
| 9948 | uint64_t index = casted_elem_index->value.data.x_bignum.data.x_uint; | |
| 10046 | uint64_t index = bigint_as_unsigned(&casted_elem_index->value.data.x_bigint); | |
| 9949 | 10047 | if (array_type->id == TypeTableEntryIdArray) { |
| 9950 | 10048 | uint64_t array_len = array_type->data.array.len; |
| 9951 | 10049 | if (index >= array_len) { |
| ... | ... | @@ -10021,7 +10119,7 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc |
| 10021 | 10119 | } |
| 10022 | 10120 | ConstExprValue *len_field = &array_ptr_val->data.x_struct.fields[slice_len_index]; |
| 10023 | 10121 | ConstExprValue *out_val = ir_build_const_from(ira, &elem_ptr_instruction->base); |
| 10024 | uint64_t slice_len = len_field->data.x_bignum.data.x_uint; | |
| 10122 | uint64_t slice_len = bigint_as_unsigned(&len_field->data.x_bigint); | |
| 10025 | 10123 | if (index >= slice_len) { |
| 10026 | 10124 | ir_add_error_node(ira, elem_ptr_instruction->base.source_node, |
| 10027 | 10125 | buf_sprintf("index %" ZIG_PRI_u64 " outside slice of size %" ZIG_PRI_u64, |
| ... | ... | @@ -11107,7 +11205,7 @@ static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira, |
| 11107 | 11205 | { |
| 11108 | 11206 | uint64_t size_in_bytes = type_size(ira->codegen, type_entry); |
| 11109 | 11207 | ConstExprValue *out_val = ir_build_const_from(ira, &size_of_instruction->base); |
| 11110 | bignum_init_unsigned(&out_val->data.x_bignum, size_in_bytes); | |
| 11208 | bigint_init_unsigned(&out_val->data.x_bigint, size_in_bytes); | |
| 11111 | 11209 | return ira->codegen->builtin_types.entry_num_lit_int; |
| 11112 | 11210 | } |
| 11113 | 11211 | } |
| ... | ... | @@ -11213,10 +11311,10 @@ static TypeTableEntry *ir_analyze_instruction_ctz(IrAnalyze *ira, IrInstructionC |
| 11213 | 11311 | return ira->codegen->builtin_types.entry_invalid; |
| 11214 | 11312 | } else if (value->value.type->id == TypeTableEntryIdInt) { |
| 11215 | 11313 | if (value->value.special != ConstValSpecialRuntime) { |
| 11216 | uint32_t result = bignum_ctz(&value->value.data.x_bignum, | |
| 11314 | size_t result = bigint_ctz(&value->value.data.x_bigint, | |
| 11217 | 11315 | value->value.type->data.integral.bit_count); |
| 11218 | 11316 | ConstExprValue *out_val = ir_build_const_from(ira, &ctz_instruction->base); |
| 11219 | bignum_init_unsigned(&out_val->data.x_bignum, result); | |
| 11317 | bigint_init_unsigned(&out_val->data.x_bigint, result); | |
| 11220 | 11318 | return value->value.type; |
| 11221 | 11319 | } |
| 11222 | 11320 | |
| ... | ... | @@ -11235,10 +11333,10 @@ static TypeTableEntry *ir_analyze_instruction_clz(IrAnalyze *ira, IrInstructionC |
| 11235 | 11333 | return ira->codegen->builtin_types.entry_invalid; |
| 11236 | 11334 | } else if (value->value.type->id == TypeTableEntryIdInt) { |
| 11237 | 11335 | if (value->value.special != ConstValSpecialRuntime) { |
| 11238 | uint32_t result = bignum_clz(&value->value.data.x_bignum, | |
| 11336 | size_t result = bigint_clz(&value->value.data.x_bigint, | |
| 11239 | 11337 | value->value.type->data.integral.bit_count); |
| 11240 | 11338 | ConstExprValue *out_val = ir_build_const_from(ira, &clz_instruction->base); |
| 11241 | bignum_init_unsigned(&out_val->data.x_bignum, result); | |
| 11339 | bigint_init_unsigned(&out_val->data.x_bigint, result); | |
| 11242 | 11340 | return value->value.type; |
| 11243 | 11341 | } |
| 11244 | 11342 | |
| ... | ... | @@ -11272,7 +11370,7 @@ static IrInstruction *ir_analyze_enum_tag(IrAnalyze *ira, IrInstruction *source_ |
| 11272 | 11370 | source_instr->scope, source_instr->source_node); |
| 11273 | 11371 | const_instruction->base.value.type = tag_type; |
| 11274 | 11372 | const_instruction->base.value.special = ConstValSpecialStatic; |
| 11275 | bignum_init_unsigned(&const_instruction->base.value.data.x_bignum, val->data.x_enum.tag); | |
| 11373 | bigint_init_unsigned(&const_instruction->base.value.data.x_bigint, val->data.x_enum.tag); | |
| 11276 | 11374 | return &const_instruction->base; |
| 11277 | 11375 | } |
| 11278 | 11376 | |
| ... | ... | @@ -11441,7 +11539,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira, |
| 11441 | 11539 | TypeTableEntry *tag_type = target_type->data.enumeration.tag_type; |
| 11442 | 11540 | if (pointee_val) { |
| 11443 | 11541 | ConstExprValue *out_val = ir_build_const_from(ira, &switch_target_instruction->base); |
| 11444 | bignum_init_unsigned(&out_val->data.x_bignum, pointee_val->data.x_enum.tag); | |
| 11542 | bigint_init_unsigned(&out_val->data.x_bigint, pointee_val->data.x_enum.tag); | |
| 11445 | 11543 | return tag_type; |
| 11446 | 11544 | } |
| 11447 | 11545 | |
| ... | ... | @@ -11490,9 +11588,9 @@ static TypeTableEntry *ir_analyze_instruction_switch_var(IrAnalyze *ira, IrInstr |
| 11490 | 11588 | if (!prong_val) |
| 11491 | 11589 | return ira->codegen->builtin_types.entry_invalid; |
| 11492 | 11590 | |
| 11493 | TypeEnumField *field = &target_type->data.enumeration.fields[prong_val->data.x_bignum.data.x_uint]; | |
| 11591 | TypeEnumField *field; | |
| 11494 | 11592 | if (prong_value->value.type->id == TypeTableEntryIdEnumTag) { |
| 11495 | field = &target_type->data.enumeration.fields[prong_val->data.x_bignum.data.x_uint]; | |
| 11593 | field = &target_type->data.enumeration.fields[bigint_as_unsigned(&prong_val->data.x_bigint)]; | |
| 11496 | 11594 | } else if (prong_value->value.type->id == TypeTableEntryIdEnum) { |
| 11497 | 11595 | field = &target_type->data.enumeration.fields[prong_val->data.x_enum.tag]; |
| 11498 | 11596 | } else { |
| ... | ... | @@ -11619,7 +11717,7 @@ static TypeTableEntry *ir_analyze_instruction_array_len(IrAnalyze *ira, |
| 11619 | 11717 | ConstExprValue *len_val = &array_value->value.data.x_struct.fields[slice_len_index]; |
| 11620 | 11718 | if (len_val->special != ConstValSpecialRuntime) { |
| 11621 | 11719 | return ir_analyze_const_usize(ira, &array_len_instruction->base, |
| 11622 | len_val->data.x_bignum.data.x_uint); | |
| 11720 | bigint_as_unsigned(&len_val->data.x_bigint)); | |
| 11623 | 11721 | } |
| 11624 | 11722 | } |
| 11625 | 11723 | TypeStructField *field = &type_entry->data.structure.fields[slice_len_index]; |
| ... | ... | @@ -11866,7 +11964,7 @@ static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira |
| 11866 | 11964 | |
| 11867 | 11965 | TypeTableEntry *enum_type = container_type_value->value.type->data.enum_tag.enum_type; |
| 11868 | 11966 | |
| 11869 | uint64_t tag_uint = tag_value->data.x_bignum.data.x_uint; | |
| 11967 | uint64_t tag_uint = bigint_as_unsigned(&tag_value->data.x_bigint); | |
| 11870 | 11968 | TypeEnumField *field = &enum_type->data.enumeration.fields[tag_uint]; |
| 11871 | 11969 | TypeTableEntry *this_field_type = field->type_entry; |
| 11872 | 11970 | |
| ... | ... | @@ -12063,7 +12161,7 @@ static TypeTableEntry *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrIn |
| 12063 | 12161 | |
| 12064 | 12162 | if (instr_is_comptime(target)) { |
| 12065 | 12163 | TypeTableEntry *enum_type = target->value.type->data.enum_tag.enum_type; |
| 12066 | uint64_t tag_value = target->value.data.x_bignum.data.x_uint; | |
| 12164 | uint64_t tag_value = bigint_as_unsigned(&target->value.data.x_bigint); | |
| 12067 | 12165 | TypeEnumField *field = &enum_type->data.enumeration.fields[tag_value]; |
| 12068 | 12166 | ConstExprValue *array_val = create_const_str_lit(ira->codegen, field->name); |
| 12069 | 12167 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); |
| ... | ... | @@ -12197,7 +12295,7 @@ static TypeTableEntry *ir_analyze_instruction_offset_of(IrAnalyze *ira, |
| 12197 | 12295 | |
| 12198 | 12296 | size_t byte_offset = LLVMOffsetOfElement(ira->codegen->target_data_ref, container_type->type_ref, field->gen_index); |
| 12199 | 12297 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); |
| 12200 | bignum_init_unsigned(&out_val->data.x_bignum, byte_offset); | |
| 12298 | bigint_init_unsigned(&out_val->data.x_bigint, byte_offset); | |
| 12201 | 12299 | return ira->codegen->builtin_types.entry_num_lit_int; |
| 12202 | 12300 | } |
| 12203 | 12301 | |
| ... | ... | @@ -12506,8 +12604,8 @@ static TypeTableEntry *ir_analyze_instruction_truncate(IrAnalyze *ira, IrInstruc |
| 12506 | 12604 | |
| 12507 | 12605 | if (target->value.special == ConstValSpecialStatic) { |
| 12508 | 12606 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); |
| 12509 | bignum_init_bignum(&out_val->data.x_bignum, &target->value.data.x_bignum); | |
| 12510 | bignum_truncate(&out_val->data.x_bignum, dest_type->data.integral.bit_count); | |
| 12607 | bigint_truncate(&out_val->data.x_bigint, &target->value.data.x_bigint, dest_type->data.integral.bit_count, | |
| 12608 | dest_type->data.integral.is_signed); | |
| 12511 | 12609 | return dest_type; |
| 12512 | 12610 | } |
| 12513 | 12611 | |
| ... | ... | @@ -12619,7 +12717,7 @@ static TypeTableEntry *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstructi |
| 12619 | 12717 | zig_unreachable(); |
| 12620 | 12718 | } |
| 12621 | 12719 | |
| 12622 | size_t count = casted_count->value.data.x_bignum.data.x_uint; | |
| 12720 | size_t count = bigint_as_unsigned(&casted_count->value.data.x_bigint); | |
| 12623 | 12721 | size_t end = start + count; |
| 12624 | 12722 | if (end > bound_end) { |
| 12625 | 12723 | ir_add_error(ira, count_value, buf_sprintf("out of bounds pointer access")); |
| ... | ... | @@ -12681,7 +12779,7 @@ static TypeTableEntry *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructi |
| 12681 | 12779 | casted_count->value.special == ConstValSpecialStatic && |
| 12682 | 12780 | casted_dest_ptr->value.data.x_ptr.special != ConstPtrSpecialHardCodedAddr) |
| 12683 | 12781 | { |
| 12684 | size_t count = casted_count->value.data.x_bignum.data.x_uint; | |
| 12782 | size_t count = bigint_as_unsigned(&casted_count->value.data.x_bigint); | |
| 12685 | 12783 | |
| 12686 | 12784 | ConstExprValue *dest_ptr_val = &casted_dest_ptr->value; |
| 12687 | 12785 | ConstExprValue *dest_elements; |
| ... | ... | @@ -12868,21 +12966,21 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio |
| 12868 | 12966 | case ConstPtrSpecialBaseArray: |
| 12869 | 12967 | array_val = parent_ptr->data.x_ptr.data.base_array.array_val; |
| 12870 | 12968 | abs_offset = parent_ptr->data.x_ptr.data.base_array.elem_index; |
| 12871 | rel_end = len_val->data.x_bignum.data.x_uint; | |
| 12969 | rel_end = bigint_as_unsigned(&len_val->data.x_bigint); | |
| 12872 | 12970 | break; |
| 12873 | 12971 | case ConstPtrSpecialBaseStruct: |
| 12874 | 12972 | zig_panic("TODO slice const inner struct"); |
| 12875 | 12973 | case ConstPtrSpecialHardCodedAddr: |
| 12876 | 12974 | array_val = nullptr; |
| 12877 | 12975 | abs_offset = 0; |
| 12878 | rel_end = len_val->data.x_bignum.data.x_uint; | |
| 12976 | rel_end = bigint_as_unsigned(&len_val->data.x_bigint); | |
| 12879 | 12977 | break; |
| 12880 | 12978 | } |
| 12881 | 12979 | } else { |
| 12882 | 12980 | zig_unreachable(); |
| 12883 | 12981 | } |
| 12884 | 12982 | |
| 12885 | uint64_t start_scalar = casted_start->value.data.x_bignum.data.x_uint; | |
| 12983 | uint64_t start_scalar = bigint_as_unsigned(&casted_start->value.data.x_bigint); | |
| 12886 | 12984 | if (start_scalar > rel_end) { |
| 12887 | 12985 | ir_add_error(ira, &instruction->base, buf_sprintf("out of bounds slice")); |
| 12888 | 12986 | return ira->codegen->builtin_types.entry_invalid; |
| ... | ... | @@ -12890,7 +12988,7 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio |
| 12890 | 12988 | |
| 12891 | 12989 | uint64_t end_scalar; |
| 12892 | 12990 | if (end) { |
| 12893 | end_scalar = end->value.data.x_bignum.data.x_uint; | |
| 12991 | end_scalar = bigint_as_unsigned(&end->value.data.x_bigint); | |
| 12894 | 12992 | } else { |
| 12895 | 12993 | end_scalar = rel_end; |
| 12896 | 12994 | } |
| ... | ... | @@ -12970,7 +13068,7 @@ static TypeTableEntry *ir_analyze_instruction_member_count(IrAnalyze *ira, IrIns |
| 12970 | 13068 | } |
| 12971 | 13069 | |
| 12972 | 13070 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); |
| 12973 | bignum_init_unsigned(&out_val->data.x_bignum, result); | |
| 13071 | bigint_init_unsigned(&out_val->data.x_bigint, result); | |
| 12974 | 13072 | return ira->codegen->builtin_types.entry_num_lit_int; |
| 12975 | 13073 | } |
| 12976 | 13074 | |
| ... | ... | @@ -13011,7 +13109,7 @@ static TypeTableEntry *ir_analyze_instruction_alignof(IrAnalyze *ira, IrInstruct |
| 13011 | 13109 | } else { |
| 13012 | 13110 | uint64_t align_in_bytes = LLVMABIAlignmentOfType(ira->codegen->target_data_ref, type_entry->type_ref); |
| 13013 | 13111 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); |
| 13014 | bignum_init_unsigned(&out_val->data.x_bignum, align_in_bytes); | |
| 13112 | bigint_init_unsigned(&out_val->data.x_bigint, align_in_bytes); | |
| 13015 | 13113 | return ira->codegen->builtin_types.entry_num_lit_int; |
| 13016 | 13114 | } |
| 13017 | 13115 | } |
| ... | ... | @@ -13060,29 +13158,32 @@ static TypeTableEntry *ir_analyze_instruction_overflow_op(IrAnalyze *ira, IrInst |
| 13060 | 13158 | casted_result_ptr->value.special == ConstValSpecialStatic) |
| 13061 | 13159 | { |
| 13062 | 13160 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); |
| 13063 | BigNum *op1_bignum = &casted_op1->value.data.x_bignum; | |
| 13064 | BigNum *op2_bignum = &casted_op2->value.data.x_bignum; | |
| 13161 | BigInt *op1_bigint = &casted_op1->value.data.x_bigint; | |
| 13162 | BigInt *op2_bigint = &casted_op2->value.data.x_bigint; | |
| 13065 | 13163 | ConstExprValue *pointee_val = const_ptr_pointee(ira->codegen, &casted_result_ptr->value); |
| 13066 | BigNum *dest_bignum = &pointee_val->data.x_bignum; | |
| 13164 | BigInt *dest_bigint = &pointee_val->data.x_bigint; | |
| 13067 | 13165 | switch (instruction->op) { |
| 13068 | 13166 | case IrOverflowOpAdd: |
| 13069 | out_val->data.x_bool = bignum_add(dest_bignum, op1_bignum, op2_bignum); | |
| 13167 | bigint_add(dest_bigint, op1_bigint, op2_bigint); | |
| 13070 | 13168 | break; |
| 13071 | 13169 | case IrOverflowOpSub: |
| 13072 | out_val->data.x_bool = bignum_sub(dest_bignum, op1_bignum, op2_bignum); | |
| 13170 | bigint_sub(dest_bigint, op1_bigint, op2_bigint); | |
| 13073 | 13171 | break; |
| 13074 | 13172 | case IrOverflowOpMul: |
| 13075 | out_val->data.x_bool = bignum_mul(dest_bignum, op1_bignum, op2_bignum); | |
| 13173 | bigint_mul(dest_bigint, op1_bigint, op2_bigint); | |
| 13076 | 13174 | break; |
| 13077 | 13175 | case IrOverflowOpShl: |
| 13078 | out_val->data.x_bool = bignum_shl(dest_bignum, op1_bignum, op2_bignum); | |
| 13176 | bigint_shl(dest_bigint, op1_bigint, op2_bigint); | |
| 13079 | 13177 | break; |
| 13080 | 13178 | } |
| 13081 | if (!bignum_fits_in_bits(dest_bignum, dest_type->data.integral.bit_count, | |
| 13179 | if (!bigint_fits_in_bits(dest_bigint, dest_type->data.integral.bit_count, | |
| 13082 | 13180 | dest_type->data.integral.is_signed)) |
| 13083 | 13181 | { |
| 13084 | 13182 | out_val->data.x_bool = true; |
| 13085 | bignum_truncate(dest_bignum, dest_type->data.integral.bit_count); | |
| 13183 | BigInt tmp_bigint; | |
| 13184 | bigint_init_bigint(&tmp_bigint, dest_bigint); | |
| 13185 | bigint_truncate(dest_bigint, &tmp_bigint, dest_type->data.integral.bit_count, | |
| 13186 | dest_type->data.integral.is_signed); | |
| 13086 | 13187 | } |
| 13087 | 13188 | pointee_val->special = ConstValSpecialStatic; |
| 13088 | 13189 | return ira->codegen->builtin_types.entry_bool; |
| ... | ... | @@ -13301,14 +13402,14 @@ static TypeTableEntry *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira |
| 13301 | 13402 | size_t start_index; |
| 13302 | 13403 | size_t end_index; |
| 13303 | 13404 | if (start_value->value.type->id == TypeTableEntryIdEnumTag) { |
| 13304 | start_index = start_value->value.data.x_bignum.data.x_uint; | |
| 13405 | start_index = bigint_as_unsigned(&start_value->value.data.x_bigint); | |
| 13305 | 13406 | } else if (start_value->value.type->id == TypeTableEntryIdEnum) { |
| 13306 | 13407 | start_index = start_value->value.data.x_enum.tag; |
| 13307 | 13408 | } else { |
| 13308 | 13409 | zig_unreachable(); |
| 13309 | 13410 | } |
| 13310 | 13411 | if (end_value->value.type->id == TypeTableEntryIdEnumTag) { |
| 13311 | end_index = end_value->value.data.x_bignum.data.x_uint; | |
| 13412 | end_index = bigint_as_unsigned(&end_value->value.data.x_bigint); | |
| 13312 | 13413 | } else if (end_value->value.type->id == TypeTableEntryIdEnum) { |
| 13313 | 13414 | end_index = end_value->value.data.x_enum.tag; |
| 13314 | 13415 | } else { |
| ... | ... | @@ -13357,7 +13458,7 @@ static TypeTableEntry *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira |
| 13357 | 13458 | if (!end_val) |
| 13358 | 13459 | return ira->codegen->builtin_types.entry_invalid; |
| 13359 | 13460 | |
| 13360 | AstNode *prev_node = rangeset_add_range(&rs, &start_val->data.x_bignum, &end_val->data.x_bignum, | |
| 13461 | AstNode *prev_node = rangeset_add_range(&rs, &start_val->data.x_bigint, &end_val->data.x_bigint, | |
| 13361 | 13462 | start_value->source_node); |
| 13362 | 13463 | if (prev_node != nullptr) { |
| 13363 | 13464 | ErrorMsg *msg = ir_add_error(ira, start_value, buf_sprintf("duplicate switch value")); |
| ... | ... | @@ -13366,9 +13467,9 @@ static TypeTableEntry *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira |
| 13366 | 13467 | } |
| 13367 | 13468 | } |
| 13368 | 13469 | if (!instruction->have_else_prong) { |
| 13369 | BigNum min_val; | |
| 13470 | BigInt min_val; | |
| 13370 | 13471 | eval_min_max_value_int(ira->codegen, switch_type, &min_val, false); |
| 13371 | BigNum max_val; | |
| 13472 | BigInt max_val; | |
| 13372 | 13473 | eval_min_max_value_int(ira->codegen, switch_type, &max_val, true); |
| 13373 | 13474 | if (!rangeset_spans(&rs, &min_val, &max_val)) { |
| 13374 | 13475 | ir_add_error(ira, &instruction->base, buf_sprintf("switch must handle all possibilities")); |
| ... | ... | @@ -13503,16 +13604,18 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue |
| 13503 | 13604 | buf[0] = val->data.x_bool ? 1 : 0; |
| 13504 | 13605 | return; |
| 13505 | 13606 | case TypeTableEntryIdInt: |
| 13506 | bignum_write_twos_complement(&val->data.x_bignum, buf, val->type->data.integral.bit_count, codegen->is_big_endian); | |
| 13607 | bigint_write_twos_complement(&val->data.x_bigint, buf, val->type->data.integral.bit_count, | |
| 13608 | codegen->is_big_endian); | |
| 13507 | 13609 | return; |
| 13508 | 13610 | case TypeTableEntryIdFloat: |
| 13509 | bignum_write_ieee597(&val->data.x_bignum, buf, val->type->data.floating.bit_count, codegen->is_big_endian); | |
| 13611 | bigfloat_write_ieee597(&val->data.x_bigfloat, buf, val->type->data.floating.bit_count, | |
| 13612 | codegen->is_big_endian); | |
| 13510 | 13613 | return; |
| 13511 | 13614 | case TypeTableEntryIdPointer: |
| 13512 | 13615 | if (val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) { |
| 13513 | BigNum bn; | |
| 13514 | bignum_init_unsigned(&bn, val->data.x_ptr.data.hard_coded_addr.addr); | |
| 13515 | bignum_write_twos_complement(&bn, buf, codegen->builtin_types.entry_usize->data.integral.bit_count, codegen->is_big_endian); | |
| 13616 | BigInt bn; | |
| 13617 | bigint_init_unsigned(&bn, val->data.x_ptr.data.hard_coded_addr.addr); | |
| 13618 | bigint_write_twos_complement(&bn, buf, codegen->builtin_types.entry_usize->data.integral.bit_count, codegen->is_big_endian); | |
| 13516 | 13619 | return; |
| 13517 | 13620 | } else { |
| 13518 | 13621 | zig_unreachable(); |
| ... | ... | @@ -13562,18 +13665,20 @@ static void buf_read_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue |
| 13562 | 13665 | val->data.x_bool = (buf[0] != 0); |
| 13563 | 13666 | return; |
| 13564 | 13667 | case TypeTableEntryIdInt: |
| 13565 | bignum_read_twos_complement(&val->data.x_bignum, buf, val->type->data.integral.bit_count, codegen->is_big_endian, | |
| 13566 | val->type->data.integral.is_signed); | |
| 13668 | bigint_read_twos_complement(&val->data.x_bigint, buf, val->type->data.integral.bit_count, | |
| 13669 | codegen->is_big_endian, val->type->data.integral.is_signed); | |
| 13567 | 13670 | return; |
| 13568 | 13671 | case TypeTableEntryIdFloat: |
| 13569 | bignum_read_ieee597(&val->data.x_bignum, buf, val->type->data.floating.bit_count, codegen->is_big_endian); | |
| 13672 | bigfloat_read_ieee597(&val->data.x_bigfloat, buf, val->type->data.floating.bit_count, | |
| 13673 | codegen->is_big_endian); | |
| 13570 | 13674 | return; |
| 13571 | 13675 | case TypeTableEntryIdPointer: |
| 13572 | 13676 | { |
| 13573 | 13677 | val->data.x_ptr.special = ConstPtrSpecialHardCodedAddr; |
| 13574 | BigNum bn; | |
| 13575 | bignum_read_twos_complement(&bn, buf, codegen->builtin_types.entry_usize->data.integral.bit_count, codegen->is_big_endian, false); | |
| 13576 | val->data.x_ptr.data.hard_coded_addr.addr = bignum_to_twos_complement(&bn); | |
| 13678 | BigInt bn; | |
| 13679 | bigint_read_twos_complement(&bn, buf, codegen->builtin_types.entry_usize->data.integral.bit_count, | |
| 13680 | codegen->is_big_endian, false); | |
| 13681 | val->data.x_ptr.data.hard_coded_addr.addr = bigint_as_unsigned(&bn); | |
| 13577 | 13682 | return; |
| 13578 | 13683 | } |
| 13579 | 13684 | case TypeTableEntryIdArray: |
| ... | ... | @@ -13729,7 +13834,7 @@ static TypeTableEntry *ir_analyze_instruction_int_to_ptr(IrAnalyze *ira, IrInstr |
| 13729 | 13834 | |
| 13730 | 13835 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); |
| 13731 | 13836 | out_val->data.x_ptr.special = ConstPtrSpecialHardCodedAddr; |
| 13732 | out_val->data.x_ptr.data.hard_coded_addr.addr = bignum_to_twos_complement(&val->data.x_bignum); | |
| 13837 | out_val->data.x_ptr.data.hard_coded_addr.addr = bigint_as_unsigned(&val->data.x_bigint); | |
| 13733 | 13838 | return dest_type; |
| 13734 | 13839 | } |
| 13735 | 13840 |
src/os.hpp+1| ... | ... | @@ -13,6 +13,7 @@ |
| 13 | 13 | #include "error.hpp" |
| 14 | 14 | |
| 15 | 15 | #include <stdio.h> |
| 16 | #include <inttypes.h> | |
| 16 | 17 | |
| 17 | 18 | enum TerminationId { |
| 18 | 19 | TerminationIdClean, |
src/parser.cpp+22-9| ... | ... | @@ -186,9 +186,14 @@ static Buf *token_buf(Token *token) { |
| 186 | 186 | return &token->data.str_lit.str; |
| 187 | 187 | } |
| 188 | 188 | |
| 189 | static BigNum *token_bignum(Token *token) { | |
| 190 | assert(token->id == TokenIdNumberLiteral); | |
| 191 | return &token->data.num_lit.bignum; | |
| 189 | static BigInt *token_bigint(Token *token) { | |
| 190 | assert(token->id == TokenIdIntLiteral); | |
| 191 | return &token->data.int_lit.bigint; | |
| 192 | } | |
| 193 | ||
| 194 | static BigFloat *token_bigfloat(Token *token) { | |
| 195 | assert(token->id == TokenIdFloatLiteral); | |
| 196 | return &token->data.float_lit.bigfloat; | |
| 192 | 197 | } |
| 193 | 198 | |
| 194 | 199 | static uint8_t token_char_lit(Token *token) { |
| ... | ... | @@ -660,16 +665,21 @@ static AstNode *ast_parse_comptime_expr(ParseContext *pc, size_t *token_index, b |
| 660 | 665 | } |
| 661 | 666 | |
| 662 | 667 | /* |
| 663 | PrimaryExpression = Number | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) | ContainerDecl | |
| 668 | PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) | ContainerDecl | |
| 664 | 669 | KeywordLiteral = "true" | "false" | "null" | "continue" | "undefined" | "error" | "this" | "unreachable" |
| 665 | 670 | */ |
| 666 | 671 | static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bool mandatory) { |
| 667 | 672 | Token *token = &pc->tokens->at(*token_index); |
| 668 | 673 | |
| 669 | if (token->id == TokenIdNumberLiteral) { | |
| 670 | AstNode *node = ast_create_node(pc, NodeTypeNumberLiteral, token); | |
| 671 | node->data.number_literal.bignum = token_bignum(token); | |
| 672 | node->data.number_literal.overflow = token->data.num_lit.overflow; | |
| 674 | if (token->id == TokenIdIntLiteral) { | |
| 675 | AstNode *node = ast_create_node(pc, NodeTypeIntLiteral, token); | |
| 676 | node->data.int_literal.bigint = token_bigint(token); | |
| 677 | *token_index += 1; | |
| 678 | return node; | |
| 679 | } else if (token->id == TokenIdFloatLiteral) { | |
| 680 | AstNode *node = ast_create_node(pc, NodeTypeFloatLiteral, token); | |
| 681 | node->data.float_literal.bigfloat = token_bigfloat(token); | |
| 682 | node->data.float_literal.overflow = token->data.float_lit.overflow; | |
| 673 | 683 | *token_index += 1; |
| 674 | 684 | return node; |
| 675 | 685 | } else if (token->id == TokenIdStringLiteral) { |
| ... | ... | @@ -2629,7 +2639,10 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont |
| 2629 | 2639 | visit_field(&node->data.unwrap_err_expr.symbol, visit, context); |
| 2630 | 2640 | visit_field(&node->data.unwrap_err_expr.op2, visit, context); |
| 2631 | 2641 | break; |
| 2632 | case NodeTypeNumberLiteral: | |
| 2642 | case NodeTypeIntLiteral: | |
| 2643 | // none | |
| 2644 | break; | |
| 2645 | case NodeTypeFloatLiteral: | |
| 2633 | 2646 | // none |
| 2634 | 2647 | break; |
| 2635 | 2648 | case NodeTypeStringLiteral: |
src/range_set.cpp+15-17| ... | ... | @@ -1,11 +1,11 @@ |
| 1 | 1 | #include "range_set.hpp" |
| 2 | 2 | |
| 3 | AstNode *rangeset_add_range(RangeSet *rs, BigNum *first, BigNum *last, AstNode *source_node) { | |
| 3 | AstNode *rangeset_add_range(RangeSet *rs, BigInt *first, BigInt *last, AstNode *source_node) { | |
| 4 | 4 | for (size_t i = 0; i < rs->src_range_list.length; i += 1) { |
| 5 | 5 | RangeWithSrc *range_with_src = &rs->src_range_list.at(i); |
| 6 | 6 | Range *range = &range_with_src->range; |
| 7 | if ((bignum_cmp_gte(first, &range->first) && bignum_cmp_lte(first, &range->last)) || | |
| 8 | (bignum_cmp_gte(last, &range->first) && bignum_cmp_lte(last, &range->last))) | |
| 7 | if ((bigint_cmp(first, &range->first) != CmpLT && bigint_cmp(first, &range->last) != CmpGT) || | |
| 8 | (bigint_cmp(last, &range->first) != CmpLT && bigint_cmp(last, &range->last) != CmpGT)) | |
| 9 | 9 | { |
| 10 | 10 | return range_with_src->source_node; |
| 11 | 11 | } |
| ... | ... | @@ -16,24 +16,22 @@ AstNode *rangeset_add_range(RangeSet *rs, BigNum *first, BigNum *last, AstNode * |
| 16 | 16 | |
| 17 | 17 | } |
| 18 | 18 | |
| 19 | static bool add_range(ZigList<Range> *list, Range *new_range, BigNum *one) { | |
| 19 | static bool add_range(ZigList<Range> *list, Range *new_range, BigInt *one) { | |
| 20 | 20 | for (size_t i = 0; i < list->length; i += 1) { |
| 21 | 21 | Range *range = &list->at(i); |
| 22 | 22 | |
| 23 | BigNum first_minus_one; | |
| 24 | if (bignum_sub(&first_minus_one, &range->first, one)) | |
| 25 | zig_unreachable(); | |
| 23 | BigInt first_minus_one; | |
| 24 | bigint_sub(&first_minus_one, &range->first, one); | |
| 26 | 25 | |
| 27 | if (bignum_cmp_eq(&new_range->last, &first_minus_one)) { | |
| 26 | if (bigint_cmp(&new_range->last, &first_minus_one) == CmpEQ) { | |
| 28 | 27 | range->first = new_range->first; |
| 29 | 28 | return true; |
| 30 | 29 | } |
| 31 | 30 | |
| 32 | BigNum last_plus_one; | |
| 33 | if (bignum_add(&last_plus_one, &range->last, one)) | |
| 34 | zig_unreachable(); | |
| 31 | BigInt last_plus_one; | |
| 32 | bigint_add(&last_plus_one, &range->last, one); | |
| 35 | 33 | |
| 36 | if (bignum_cmp_eq(&new_range->first, &last_plus_one)) { | |
| 34 | if (bigint_cmp(&new_range->first, &last_plus_one) == CmpEQ) { | |
| 37 | 35 | range->last = new_range->last; |
| 38 | 36 | return true; |
| 39 | 37 | } |
| ... | ... | @@ -42,7 +40,7 @@ static bool add_range(ZigList<Range> *list, Range *new_range, BigNum *one) { |
| 42 | 40 | return false; |
| 43 | 41 | } |
| 44 | 42 | |
| 45 | bool rangeset_spans(RangeSet *rs, BigNum *first, BigNum *last) { | |
| 43 | bool rangeset_spans(RangeSet *rs, BigInt *first, BigInt *last) { | |
| 46 | 44 | ZigList<Range> cur_list_value = {0}; |
| 47 | 45 | ZigList<Range> other_list_value = {0}; |
| 48 | 46 | ZigList<Range> *cur_list = &cur_list_value; |
| ... | ... | @@ -54,8 +52,8 @@ bool rangeset_spans(RangeSet *rs, BigNum *first, BigNum *last) { |
| 54 | 52 | cur_list->append({range->first, range->last}); |
| 55 | 53 | } |
| 56 | 54 | |
| 57 | BigNum one; | |
| 58 | bignum_init_unsigned(&one, 1); | |
| 55 | BigInt one; | |
| 56 | bigint_init_unsigned(&one, 1); | |
| 59 | 57 | |
| 60 | 58 | bool changes_made = true; |
| 61 | 59 | while (changes_made) { |
| ... | ... | @@ -73,9 +71,9 @@ bool rangeset_spans(RangeSet *rs, BigNum *first, BigNum *last) { |
| 73 | 71 | if (cur_list->length != 1) |
| 74 | 72 | return false; |
| 75 | 73 | Range *range = &cur_list->at(0); |
| 76 | if (bignum_cmp_neq(&range->first, first)) | |
| 74 | if (bigint_cmp(&range->first, first) != CmpEQ) | |
| 77 | 75 | return false; |
| 78 | if (bignum_cmp_neq(&range->last, last)) | |
| 76 | if (bigint_cmp(&range->last, last) != CmpEQ) | |
| 79 | 77 | return false; |
| 80 | 78 | return true; |
| 81 | 79 | } |
src/range_set.hpp+4-4| ... | ... | @@ -11,8 +11,8 @@ |
| 11 | 11 | #include "all_types.hpp" |
| 12 | 12 | |
| 13 | 13 | struct Range { |
| 14 | BigNum first; | |
| 15 | BigNum last; | |
| 14 | BigInt first; | |
| 15 | BigInt last; | |
| 16 | 16 | }; |
| 17 | 17 | |
| 18 | 18 | struct RangeWithSrc { |
| ... | ... | @@ -24,7 +24,7 @@ struct RangeSet { |
| 24 | 24 | ZigList<RangeWithSrc> src_range_list; |
| 25 | 25 | }; |
| 26 | 26 | |
| 27 | AstNode *rangeset_add_range(RangeSet *rs, BigNum *first, BigNum *last, AstNode *source_node); | |
| 28 | bool rangeset_spans(RangeSet *rs, BigNum *first, BigNum *last); | |
| 27 | AstNode *rangeset_add_range(RangeSet *rs, BigInt *first, BigInt *last, AstNode *source_node); | |
| 28 | bool rangeset_spans(RangeSet *rs, BigInt *first, BigInt *last); | |
| 29 | 29 | |
| 30 | 30 | #endif |
src/tokenizer.cpp+87-58| ... | ... | @@ -225,13 +225,13 @@ struct Tokenize { |
| 225 | 225 | uint32_t radix; |
| 226 | 226 | int32_t exp_add_amt; |
| 227 | 227 | bool is_exp_negative; |
| 228 | bool is_num_lit_float; | |
| 229 | 228 | size_t char_code_index; |
| 230 | 229 | size_t char_code_end; |
| 231 | 230 | bool unicode; |
| 232 | 231 | uint32_t char_code; |
| 233 | 232 | int exponent_in_bin_or_dec; |
| 234 | BigNum specified_exponent; | |
| 233 | BigInt specified_exponent; | |
| 234 | BigInt significand; | |
| 235 | 235 | }; |
| 236 | 236 | |
| 237 | 237 | __attribute__ ((format (printf, 2, 3))) |
| ... | ... | @@ -255,8 +255,11 @@ static void tokenize_error(Tokenize *t, const char *format, ...) { |
| 255 | 255 | static void set_token_id(Tokenize *t, Token *token, TokenId id) { |
| 256 | 256 | token->id = id; |
| 257 | 257 | |
| 258 | if (id == TokenIdNumberLiteral) { | |
| 259 | token->data.num_lit.overflow = false; | |
| 258 | if (id == TokenIdIntLiteral) { | |
| 259 | bigint_init_unsigned(&token->data.int_lit.bigint, 0); | |
| 260 | } else if (id == TokenIdFloatLiteral) { | |
| 261 | bigfloat_init_float(&token->data.float_lit.bigfloat, 0.0); | |
| 262 | token->data.float_lit.overflow = false; | |
| 260 | 263 | } else if (id == TokenIdStringLiteral || id == TokenIdSymbol) { |
| 261 | 264 | memset(&token->data.str_lit.str, 0, sizeof(Buf)); |
| 262 | 265 | buf_resize(&token->data.str_lit.str, 0); |
| ... | ... | @@ -283,34 +286,40 @@ static void cancel_token(Tokenize *t) { |
| 283 | 286 | } |
| 284 | 287 | |
| 285 | 288 | static void end_float_token(Tokenize *t) { |
| 286 | t->cur_tok->data.num_lit.bignum.kind = BigNumKindFloat; | |
| 287 | ||
| 288 | 289 | if (t->radix == 10) { |
| 289 | char *str_begin = buf_ptr(t->buf) + t->cur_tok->start_pos; | |
| 290 | char *str_end; | |
| 291 | errno = 0; | |
| 292 | t->cur_tok->data.num_lit.bignum.data.x_float = strtod(str_begin, &str_end); | |
| 293 | if (errno) { | |
| 294 | t->cur_tok->data.num_lit.overflow = true; | |
| 295 | return; | |
| 290 | uint8_t *ptr_buf = (uint8_t*)buf_ptr(t->buf) + t->cur_tok->start_pos; | |
| 291 | size_t buf_len = t->cur_tok->end_pos - t->cur_tok->start_pos; | |
| 292 | if (bigfloat_init_buf_base10(&t->cur_tok->data.float_lit.bigfloat, ptr_buf, buf_len)) { | |
| 293 | t->cur_tok->data.float_lit.overflow = true; | |
| 296 | 294 | } |
| 297 | assert(str_end <= buf_ptr(t->buf) + t->cur_tok->end_pos); | |
| 298 | 295 | return; |
| 299 | 296 | } |
| 300 | 297 | |
| 298 | BigInt int_max; | |
| 299 | bigint_init_unsigned(&int_max, INT_MAX); | |
| 300 | ||
| 301 | if (bigint_cmp(&t->specified_exponent, &int_max) != CmpLT) { | |
| 302 | t->cur_tok->data.float_lit.overflow = true; | |
| 303 | return; | |
| 304 | } | |
| 301 | 305 | |
| 302 | if (t->specified_exponent.data.x_uint >= INT_MAX) { | |
| 303 | t->cur_tok->data.num_lit.overflow = true; | |
| 306 | if (!bigint_fits_in_bits(&t->specified_exponent, 64, true)) { | |
| 307 | t->cur_tok->data.float_lit.overflow = true; | |
| 304 | 308 | return; |
| 305 | 309 | } |
| 306 | 310 | |
| 307 | int64_t specified_exponent = t->specified_exponent.data.x_uint; | |
| 311 | int64_t specified_exponent = bigint_as_signed(&t->specified_exponent); | |
| 308 | 312 | if (t->is_exp_negative) { |
| 309 | 313 | specified_exponent = -specified_exponent; |
| 310 | 314 | } |
| 311 | 315 | t->exponent_in_bin_or_dec = (int)(t->exponent_in_bin_or_dec + specified_exponent); |
| 312 | 316 | |
| 313 | uint64_t significand = t->cur_tok->data.num_lit.bignum.data.x_uint; | |
| 317 | if (!bigint_fits_in_bits(&t->significand, 64, false)) { | |
| 318 | t->cur_tok->data.float_lit.overflow = true; | |
| 319 | return; | |
| 320 | } | |
| 321 | ||
| 322 | uint64_t significand = bigint_as_unsigned(&t->significand); | |
| 314 | 323 | uint64_t significand_bits; |
| 315 | 324 | uint64_t exponent_bits; |
| 316 | 325 | if (significand == 0) { |
| ... | ... | @@ -325,7 +334,7 @@ static void end_float_token(Tokenize *t) { |
| 325 | 334 | int significand_magnitude_in_bin = __builtin_clzll(1) - __builtin_clzll(significand); |
| 326 | 335 | t->exponent_in_bin_or_dec += significand_magnitude_in_bin; |
| 327 | 336 | if (!(-1023 <= t->exponent_in_bin_or_dec && t->exponent_in_bin_or_dec < 1023)) { |
| 328 | t->cur_tok->data.num_lit.overflow = true; | |
| 337 | t->cur_tok->data.float_lit.overflow = true; | |
| 329 | 338 | return; |
| 330 | 339 | } else { |
| 331 | 340 | // this should chop off exactly one 1 bit from the top. |
| ... | ... | @@ -335,20 +344,17 @@ static void end_float_token(Tokenize *t) { |
| 335 | 344 | } |
| 336 | 345 | } |
| 337 | 346 | uint64_t double_bits = (exponent_bits << 52) | significand_bits; |
| 338 | safe_memcpy(&t->cur_tok->data.num_lit.bignum.data.x_float, (double *)&double_bits, 1); | |
| 347 | double dbl_value; | |
| 348 | safe_memcpy(&dbl_value, (double *)&double_bits, 1); | |
| 349 | bigfloat_init_float(&t->cur_tok->data.float_lit.bigfloat, dbl_value); | |
| 339 | 350 | } |
| 340 | 351 | |
| 341 | 352 | static void end_token(Tokenize *t) { |
| 342 | 353 | assert(t->cur_tok); |
| 343 | 354 | t->cur_tok->end_pos = t->pos + 1; |
| 344 | 355 | |
| 345 | if (t->cur_tok->id == TokenIdNumberLiteral) { | |
| 346 | if (t->cur_tok->data.num_lit.overflow) { | |
| 347 | return; | |
| 348 | } | |
| 349 | if (t->is_num_lit_float) { | |
| 350 | end_float_token(t); | |
| 351 | } | |
| 356 | if (t->cur_tok->id == TokenIdFloatLiteral) { | |
| 357 | end_float_token(t); | |
| 352 | 358 | } else if (t->cur_tok->id == TokenIdSymbol) { |
| 353 | 359 | char *token_mem = buf_ptr(t->buf) + t->cur_tok->start_pos; |
| 354 | 360 | int token_len = (int)(t->cur_tok->end_pos - t->cur_tok->start_pos); |
| ... | ... | @@ -428,23 +434,21 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 428 | 434 | break; |
| 429 | 435 | case '0': |
| 430 | 436 | t.state = TokenizeStateZero; |
| 431 | begin_token(&t, TokenIdNumberLiteral); | |
| 437 | begin_token(&t, TokenIdIntLiteral); | |
| 432 | 438 | t.radix = 10; |
| 433 | 439 | t.exp_add_amt = 1; |
| 434 | 440 | t.exponent_in_bin_or_dec = 0; |
| 435 | t.is_num_lit_float = false; | |
| 436 | bignum_init_unsigned(&t.cur_tok->data.num_lit.bignum, 0); | |
| 437 | bignum_init_unsigned(&t.specified_exponent, 0); | |
| 441 | bigint_init_unsigned(&t.cur_tok->data.int_lit.bigint, 0); | |
| 442 | bigint_init_unsigned(&t.specified_exponent, 0); | |
| 438 | 443 | break; |
| 439 | 444 | case DIGIT_NON_ZERO: |
| 440 | 445 | t.state = TokenizeStateNumber; |
| 441 | begin_token(&t, TokenIdNumberLiteral); | |
| 446 | begin_token(&t, TokenIdIntLiteral); | |
| 442 | 447 | t.radix = 10; |
| 443 | 448 | t.exp_add_amt = 1; |
| 444 | 449 | t.exponent_in_bin_or_dec = 0; |
| 445 | t.is_num_lit_float = false; | |
| 446 | bignum_init_unsigned(&t.cur_tok->data.num_lit.bignum, get_digit_value(c)); | |
| 447 | bignum_init_unsigned(&t.specified_exponent, 0); | |
| 450 | bigint_init_unsigned(&t.cur_tok->data.int_lit.bigint, get_digit_value(c)); | |
| 451 | bigint_init_unsigned(&t.specified_exponent, 0); | |
| 448 | 452 | break; |
| 449 | 453 | case '"': |
| 450 | 454 | begin_token(&t, TokenIdStringLiteral); |
| ... | ... | @@ -1182,7 +1186,9 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 1182 | 1186 | } |
| 1183 | 1187 | if (is_exponent_signifier(c, t.radix)) { |
| 1184 | 1188 | t.state = TokenizeStateFloatExponentUnsigned; |
| 1185 | t.is_num_lit_float = true; | |
| 1189 | assert(t.cur_tok->id == TokenIdIntLiteral); | |
| 1190 | bigint_init_bigint(&t.significand, &t.cur_tok->data.int_lit.bigint); | |
| 1191 | set_token_id(&t, t.cur_tok, TokenIdFloatLiteral); | |
| 1186 | 1192 | break; |
| 1187 | 1193 | } |
| 1188 | 1194 | uint32_t digit_value = get_digit_value(c); |
| ... | ... | @@ -1196,23 +1202,33 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 1196 | 1202 | t.state = TokenizeStateStart; |
| 1197 | 1203 | continue; |
| 1198 | 1204 | } |
| 1199 | t.cur_tok->data.num_lit.overflow = t.cur_tok->data.num_lit.overflow || | |
| 1200 | bignum_multiply_by_scalar(&t.cur_tok->data.num_lit.bignum, t.radix); | |
| 1201 | t.cur_tok->data.num_lit.overflow = t.cur_tok->data.num_lit.overflow || | |
| 1202 | bignum_increment_by_scalar(&t.cur_tok->data.num_lit.bignum, digit_value); | |
| 1205 | BigInt digit_value_bi; | |
| 1206 | bigint_init_unsigned(&digit_value_bi, digit_value); | |
| 1207 | ||
| 1208 | BigInt radix_bi; | |
| 1209 | bigint_init_unsigned(&radix_bi, t.radix); | |
| 1210 | ||
| 1211 | BigInt multiplied; | |
| 1212 | bigint_mul(&multiplied, &t.cur_tok->data.int_lit.bigint, &radix_bi); | |
| 1213 | ||
| 1214 | bigint_add(&t.cur_tok->data.int_lit.bigint, &multiplied, &digit_value_bi); | |
| 1203 | 1215 | break; |
| 1204 | 1216 | } |
| 1205 | 1217 | case TokenizeStateNumberDot: |
| 1206 | if (c == '.') { | |
| 1207 | t.pos -= 2; | |
| 1208 | end_token(&t); | |
| 1209 | t.state = TokenizeStateStart; | |
| 1218 | { | |
| 1219 | if (c == '.') { | |
| 1220 | t.pos -= 2; | |
| 1221 | end_token(&t); | |
| 1222 | t.state = TokenizeStateStart; | |
| 1223 | continue; | |
| 1224 | } | |
| 1225 | t.pos -= 1; | |
| 1226 | t.state = TokenizeStateFloatFraction; | |
| 1227 | assert(t.cur_tok->id == TokenIdIntLiteral); | |
| 1228 | bigint_init_bigint(&t.significand, &t.cur_tok->data.int_lit.bigint); | |
| 1229 | set_token_id(&t, t.cur_tok, TokenIdFloatLiteral); | |
| 1210 | 1230 | continue; |
| 1211 | 1231 | } |
| 1212 | t.pos -= 1; | |
| 1213 | t.state = TokenizeStateFloatFraction; | |
| 1214 | t.is_num_lit_float = true; | |
| 1215 | continue; | |
| 1216 | 1232 | case TokenizeStateFloatFraction: |
| 1217 | 1233 | { |
| 1218 | 1234 | if (is_exponent_signifier(c, t.radix)) { |
| ... | ... | @@ -1236,10 +1252,16 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 1236 | 1252 | // end of the token. |
| 1237 | 1253 | break; |
| 1238 | 1254 | } |
| 1239 | t.cur_tok->data.num_lit.overflow = t.cur_tok->data.num_lit.overflow || | |
| 1240 | bignum_multiply_by_scalar(&t.cur_tok->data.num_lit.bignum, t.radix); | |
| 1241 | t.cur_tok->data.num_lit.overflow = t.cur_tok->data.num_lit.overflow || | |
| 1242 | bignum_increment_by_scalar(&t.cur_tok->data.num_lit.bignum, digit_value); | |
| 1255 | BigInt digit_value_bi; | |
| 1256 | bigint_init_unsigned(&digit_value_bi, digit_value); | |
| 1257 | ||
| 1258 | BigInt radix_bi; | |
| 1259 | bigint_init_unsigned(&radix_bi, t.radix); | |
| 1260 | ||
| 1261 | BigInt multiplied; | |
| 1262 | bigint_mul(&multiplied, &t.significand, &radix_bi); | |
| 1263 | ||
| 1264 | bigint_add(&t.significand, &multiplied, &digit_value_bi); | |
| 1243 | 1265 | break; |
| 1244 | 1266 | } |
| 1245 | 1267 | case TokenizeStateFloatExponentUnsigned: |
| ... | ... | @@ -1278,10 +1300,16 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 1278 | 1300 | // end of the token. |
| 1279 | 1301 | break; |
| 1280 | 1302 | } |
| 1281 | t.cur_tok->data.num_lit.overflow = t.cur_tok->data.num_lit.overflow || | |
| 1282 | bignum_multiply_by_scalar(&t.specified_exponent, 10); | |
| 1283 | t.cur_tok->data.num_lit.overflow = t.cur_tok->data.num_lit.overflow || | |
| 1284 | bignum_increment_by_scalar(&t.specified_exponent, digit_value); | |
| 1303 | BigInt digit_value_bi; | |
| 1304 | bigint_init_unsigned(&digit_value_bi, digit_value); | |
| 1305 | ||
| 1306 | BigInt radix_bi; | |
| 1307 | bigint_init_unsigned(&radix_bi, 10); | |
| 1308 | ||
| 1309 | BigInt multiplied; | |
| 1310 | bigint_mul(&multiplied, &t.specified_exponent, &radix_bi); | |
| 1311 | ||
| 1312 | bigint_add(&t.specified_exponent, &multiplied, &digit_value_bi); | |
| 1285 | 1313 | } |
| 1286 | 1314 | break; |
| 1287 | 1315 | case TokenizeStateSawDash: |
| ... | ... | @@ -1441,11 +1469,13 @@ const char * token_name(TokenId id) { |
| 1441 | 1469 | case TokenIdDivEq: return "/="; |
| 1442 | 1470 | case TokenIdDot: return "."; |
| 1443 | 1471 | case TokenIdDoubleQuestion: return "??"; |
| 1444 | case TokenIdEllipsis3: return "..."; | |
| 1445 | 1472 | case TokenIdEllipsis2: return ".."; |
| 1473 | case TokenIdEllipsis3: return "..."; | |
| 1446 | 1474 | case TokenIdEof: return "EOF"; |
| 1447 | 1475 | case TokenIdEq: return "="; |
| 1448 | 1476 | case TokenIdFatArrow: return "=>"; |
| 1477 | case TokenIdFloatLiteral: return "FloatLiteral"; | |
| 1478 | case TokenIdIntLiteral: return "IntLiteral"; | |
| 1449 | 1479 | case TokenIdKeywordAnd: return "and"; |
| 1450 | 1480 | case TokenIdKeywordAsm: return "asm"; |
| 1451 | 1481 | case TokenIdKeywordBreak: return "break"; |
| ... | ... | @@ -1494,7 +1524,6 @@ const char * token_name(TokenId id) { |
| 1494 | 1524 | case TokenIdMinusPercent: return "-%"; |
| 1495 | 1525 | case TokenIdMinusPercentEq: return "-%="; |
| 1496 | 1526 | case TokenIdModEq: return "%="; |
| 1497 | case TokenIdNumberLiteral: return "NumberLiteral"; | |
| 1498 | 1527 | case TokenIdNumberSign: return "#"; |
| 1499 | 1528 | case TokenIdPercent: return "%"; |
| 1500 | 1529 | case TokenIdPercentDot: return "%."; |
src/tokenizer.hpp+18-9| ... | ... | @@ -9,7 +9,8 @@ |
| 9 | 9 | #define ZIG_TOKENIZER_HPP |
| 10 | 10 | |
| 11 | 11 | #include "buffer.hpp" |
| 12 | #include "bignum.hpp" | |
| 12 | #include "bigint.hpp" | |
| 13 | #include "bigfloat.hpp" | |
| 13 | 14 | |
| 14 | 15 | enum TokenId { |
| 15 | 16 | TokenIdAmpersand, |
| ... | ... | @@ -40,11 +41,13 @@ enum TokenId { |
| 40 | 41 | TokenIdDivEq, |
| 41 | 42 | TokenIdDot, |
| 42 | 43 | TokenIdDoubleQuestion, |
| 43 | TokenIdEllipsis3, | |
| 44 | 44 | TokenIdEllipsis2, |
| 45 | TokenIdEllipsis3, | |
| 45 | 46 | TokenIdEof, |
| 46 | 47 | TokenIdEq, |
| 47 | 48 | TokenIdFatArrow, |
| 49 | TokenIdFloatLiteral, | |
| 50 | TokenIdIntLiteral, | |
| 48 | 51 | TokenIdKeywordAnd, |
| 49 | 52 | TokenIdKeywordAsm, |
| 50 | 53 | TokenIdKeywordBreak, |
| ... | ... | @@ -93,7 +96,6 @@ enum TokenId { |
| 93 | 96 | TokenIdMinusPercent, |
| 94 | 97 | TokenIdMinusPercentEq, |
| 95 | 98 | TokenIdModEq, |
| 96 | TokenIdNumberLiteral, | |
| 97 | 99 | TokenIdNumberSign, |
| 98 | 100 | TokenIdPercent, |
| 99 | 101 | TokenIdPercentDot, |
| ... | ... | @@ -118,13 +120,17 @@ enum TokenId { |
| 118 | 120 | TokenIdTimesPercentEq, |
| 119 | 121 | }; |
| 120 | 122 | |
| 121 | struct TokenNumLit { | |
| 122 | BigNum bignum; | |
| 123 | // overflow is true if when parsing the number, we discovered it would not | |
| 124 | // fit without losing data in a uint64_t or double | |
| 123 | struct TokenFloatLit { | |
| 124 | BigFloat bigfloat; | |
| 125 | // overflow is true if when parsing the number, we discovered it would not fit | |
| 126 | // without losing data | |
| 125 | 127 | bool overflow; |
| 126 | 128 | }; |
| 127 | 129 | |
| 130 | struct TokenIntLit { | |
| 131 | BigInt bigint; | |
| 132 | }; | |
| 133 | ||
| 128 | 134 | struct TokenStrLit { |
| 129 | 135 | Buf str; |
| 130 | 136 | bool is_c_str; |
| ... | ... | @@ -142,8 +148,11 @@ struct Token { |
| 142 | 148 | size_t start_column; |
| 143 | 149 | |
| 144 | 150 | union { |
| 145 | // TokenIdNumberLiteral | |
| 146 | TokenNumLit num_lit; | |
| 151 | // TokenIdIntLiteral | |
| 152 | TokenIntLit int_lit; | |
| 153 | ||
| 154 | // TokenIdFloatLiteral | |
| 155 | TokenFloatLit float_lit; | |
| 147 | 156 | |
| 148 | 157 | // TokenIdStringLiteral or TokenIdSymbol |
| 149 | 158 | TokenStrLit str_lit; |
std/math/fabs.zig+2-2| ... | ... | @@ -36,8 +36,8 @@ test "math.fabs" { |
| 36 | 36 | } |
| 37 | 37 | |
| 38 | 38 | test "math.fabs32" { |
| 39 | assert(fabs64(1.0) == 1.0); | |
| 40 | assert(fabs64(-1.0) == 1.0); | |
| 39 | assert(fabs32(1.0) == 1.0); | |
| 40 | assert(fabs32(-1.0) == 1.0); | |
| 41 | 41 | } |
| 42 | 42 | |
| 43 | 43 | test "math.fabs64" { |
std/math/log10.zig+1-1| ... | ... | @@ -139,7 +139,7 @@ fn log10_64(x_: f64) -> f64 { |
| 139 | 139 | // hi + lo = f - hfsq + s * (hfsq + R) ~ log(1 + f) |
| 140 | 140 | var hi = f - hfsq; |
| 141 | 141 | var hii = @bitCast(u64, hi); |
| 142 | hii &= @maxValue(u64) << 32; | |
| 142 | hii &= u64(@maxValue(u64)) <<% 32; | |
| 143 | 143 | hi = @bitCast(f64, hii); |
| 144 | 144 | const lo = f - hi - hfsq + s * (hfsq + R); |
| 145 | 145 |
std/math/log2.zig+1-1| ... | ... | @@ -133,7 +133,7 @@ fn log2_64(x_: f64) -> f64 { |
| 133 | 133 | // hi + lo = f - hfsq + s * (hfsq + R) ~ log(1 + f) |
| 134 | 134 | var hi = f - hfsq; |
| 135 | 135 | var hii = @bitCast(u64, hi); |
| 136 | hii &= @maxValue(u64) << 32; | |
| 136 | hii &= u64(@maxValue(u64)) <<% 32; | |
| 137 | 137 | hi = @bitCast(f64, hii); |
| 138 | 138 | const lo = f - hi - hfsq + s * (hfsq + R); |
| 139 | 139 |
test/cases/math.zig+28-6| ... | ... | @@ -58,15 +58,33 @@ test "@shlWithOverflow" { |
| 58 | 58 | } |
| 59 | 59 | |
| 60 | 60 | test "@clz" { |
| 61 | assert(@clz(u8(0b00001010)) == 4); | |
| 62 | assert(@clz(u8(0b10001010)) == 0); | |
| 63 | assert(@clz(u8(0b00000000)) == 8); | |
| 61 | testClz(); | |
| 62 | comptime testClz(); | |
| 63 | } | |
| 64 | ||
| 65 | fn testClz() { | |
| 66 | assert(clz(u8(0b00001010)) == 4); | |
| 67 | assert(clz(u8(0b10001010)) == 0); | |
| 68 | assert(clz(u8(0b00000000)) == 8); | |
| 69 | } | |
| 70 | ||
| 71 | fn clz(x: var) -> usize { | |
| 72 | @clz(x) | |
| 64 | 73 | } |
| 65 | 74 | |
| 66 | 75 | test "@ctz" { |
| 67 | assert(@ctz(u8(0b10100000)) == 5); | |
| 68 | assert(@ctz(u8(0b10001010)) == 1); | |
| 69 | assert(@ctz(u8(0b00000000)) == 8); | |
| 76 | testCtz(); | |
| 77 | comptime testCtz(); | |
| 78 | } | |
| 79 | ||
| 80 | fn testCtz() { | |
| 81 | assert(ctz(u8(0b10100000)) == 5); | |
| 82 | assert(ctz(u8(0b10001010)) == 1); | |
| 83 | assert(ctz(u8(0b00000000)) == 8); | |
| 84 | } | |
| 85 | ||
| 86 | fn ctz(x: var) -> usize { | |
| 87 | @ctz(x) | |
| 70 | 88 | } |
| 71 | 89 | |
| 72 | 90 | test "assignment operators" { |
| ... | ... | @@ -229,3 +247,7 @@ test "allow signed integer division/remainder when values are comptime known and |
| 229 | 247 | assert(5 % 3 == 2); |
| 230 | 248 | assert(-6 % 3 == 0); |
| 231 | 249 | } |
| 250 | ||
| 251 | test "float literal parsing" { | |
| 252 | comptime assert(0x1.0 == 1.0); | |
| 253 | } |