| author | |
| committer | |
| log | 1f6dacbb2f9a91a20309b271a31e781f11f81819 |
| tree | 418c311fc703a4163ebf16cc90e89346b5113785 |
| parent | c10ae8622bc07baeea1fb81522b01fc6e953eaf6 |
12 files changed, 514 insertions(+), 607 deletions(-)
CMakeLists.txt-1| ... | ... | @@ -46,7 +46,6 @@ set(ZIG_SOURCES |
| 46 | 46 | "${CMAKE_SOURCE_DIR}/src/codegen.cpp" |
| 47 | 47 | "${CMAKE_SOURCE_DIR}/src/errmsg.cpp" |
| 48 | 48 | "${CMAKE_SOURCE_DIR}/src/error.cpp" |
| 49 | "${CMAKE_SOURCE_DIR}/src/eval.cpp" | |
| 50 | 49 | "${CMAKE_SOURCE_DIR}/src/ir.cpp" |
| 51 | 50 | "${CMAKE_SOURCE_DIR}/src/ir_print.cpp" |
| 52 | 51 | "${CMAKE_SOURCE_DIR}/src/link.cpp" |
src/all_types.hpp+17| ... | ... | @@ -848,6 +848,11 @@ struct TypeTableEntryEnum { |
| 848 | 848 | bool complete; |
| 849 | 849 | }; |
| 850 | 850 | |
| 851 | struct TypeTableEntryEnumTag { | |
| 852 | TypeTableEntry *enum_type; | |
| 853 | TypeTableEntry *int_type; | |
| 854 | }; | |
| 855 | ||
| 851 | 856 | struct TypeTableEntryUnion { |
| 852 | 857 | AstNode *decl_node; |
| 853 | 858 | bool is_extern; |
| ... | ... | @@ -914,6 +919,7 @@ enum TypeTableEntryId { |
| 914 | 919 | TypeTableEntryIdErrorUnion, |
| 915 | 920 | TypeTableEntryIdPureError, |
| 916 | 921 | TypeTableEntryIdEnum, |
| 922 | TypeTableEntryIdEnumTag, | |
| 917 | 923 | TypeTableEntryIdUnion, |
| 918 | 924 | TypeTableEntryIdFn, |
| 919 | 925 | TypeTableEntryIdTypeDecl, |
| ... | ... | @@ -940,6 +946,7 @@ struct TypeTableEntry { |
| 940 | 946 | TypeTableEntryMaybe maybe; |
| 941 | 947 | TypeTableEntryError error; |
| 942 | 948 | TypeTableEntryEnum enumeration; |
| 949 | TypeTableEntryEnumTag enum_tag; | |
| 943 | 950 | TypeTableEntryUnion unionation; |
| 944 | 951 | TypeTableEntryFn fn; |
| 945 | 952 | TypeTableEntryTypeDecl type_decl; |
| ... | ... | @@ -1452,6 +1459,7 @@ enum IrInstructionId { |
| 1452 | 1459 | IrInstructionIdErrWrapPayload, |
| 1453 | 1460 | IrInstructionIdFnProto, |
| 1454 | 1461 | IrInstructionIdTestComptime, |
| 1462 | IrInstructionIdInitEnum, | |
| 1455 | 1463 | }; |
| 1456 | 1464 | |
| 1457 | 1465 | struct IrInstruction { |
| ... | ... | @@ -2078,6 +2086,15 @@ struct IrInstructionTestComptime { |
| 2078 | 2086 | IrInstruction *value; |
| 2079 | 2087 | }; |
| 2080 | 2088 | |
| 2089 | struct IrInstructionInitEnum { | |
| 2090 | IrInstruction base; | |
| 2091 | ||
| 2092 | TypeTableEntry *enum_type; | |
| 2093 | TypeEnumField *field; | |
| 2094 | IrInstruction *init_value; | |
| 2095 | LLVMValueRef tmp_ptr; | |
| 2096 | }; | |
| 2097 | ||
| 2081 | 2098 | enum LValPurpose { |
| 2082 | 2099 | LValPurposeNone, |
| 2083 | 2100 | LValPurposeAssign, |
src/analyze.cpp+183-11| ... | ... | @@ -9,7 +9,6 @@ |
| 9 | 9 | #include "ast_render.hpp" |
| 10 | 10 | #include "config.h" |
| 11 | 11 | #include "error.hpp" |
| 12 | #include "eval.hpp" | |
| 13 | 12 | #include "ir.hpp" |
| 14 | 13 | #include "ir_print.hpp" |
| 15 | 14 | #include "os.hpp" |
| ... | ... | @@ -252,6 +251,7 @@ bool type_is_complete(TypeTableEntry *type_entry) { |
| 252 | 251 | case TypeTableEntryIdNamespace: |
| 253 | 252 | case TypeTableEntryIdBlock: |
| 254 | 253 | case TypeTableEntryIdBoundFn: |
| 254 | case TypeTableEntryIdEnumTag: | |
| 255 | 255 | return true; |
| 256 | 256 | } |
| 257 | 257 | zig_unreachable(); |
| ... | ... | @@ -677,14 +677,8 @@ TypeTableEntry *get_typedecl_type(CodeGen *g, const char *name, TypeTableEntry * |
| 677 | 677 | entry->type_ref = child_type->type_ref; |
| 678 | 678 | entry->di_type = child_type->di_type; |
| 679 | 679 | entry->zero_bits = child_type->zero_bits; |
| 680 | ||
| 681 | 680 | entry->data.type_decl.child_type = child_type; |
| 682 | ||
| 683 | if (child_type->id == TypeTableEntryIdTypeDecl) { | |
| 684 | entry->data.type_decl.canonical_type = child_type->data.type_decl.canonical_type; | |
| 685 | } else { | |
| 686 | entry->data.type_decl.canonical_type = child_type; | |
| 687 | } | |
| 681 | entry->data.type_decl.canonical_type = get_underlying_type(child_type); | |
| 688 | 682 | |
| 689 | 683 | return entry; |
| 690 | 684 | } |
| ... | ... | @@ -985,6 +979,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c |
| 985 | 979 | case TypeTableEntryIdUnion: |
| 986 | 980 | case TypeTableEntryIdFn: |
| 987 | 981 | case TypeTableEntryIdTypeDecl: |
| 982 | case TypeTableEntryIdEnumTag: | |
| 988 | 983 | break; |
| 989 | 984 | } |
| 990 | 985 | FnTypeParamInfo *param_info = &fn_type_id.param_info[fn_type_id.next_param_index]; |
| ... | ... | @@ -1033,12 +1028,28 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c |
| 1033 | 1028 | case TypeTableEntryIdUnion: |
| 1034 | 1029 | case TypeTableEntryIdFn: |
| 1035 | 1030 | case TypeTableEntryIdTypeDecl: |
| 1031 | case TypeTableEntryIdEnumTag: | |
| 1036 | 1032 | break; |
| 1037 | 1033 | } |
| 1038 | 1034 | |
| 1039 | 1035 | return get_fn_type(g, &fn_type_id); |
| 1040 | 1036 | } |
| 1041 | 1037 | |
| 1038 | static TypeTableEntry *create_enum_tag_type(CodeGen *g, TypeTableEntry *enum_type, TypeTableEntry *int_type) { | |
| 1039 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnumTag); | |
| 1040 | ||
| 1041 | buf_resize(&entry->name, 0); | |
| 1042 | buf_appendf(&entry->name, "@enumTagType(%s)", buf_ptr(&enum_type->name)); | |
| 1043 | ||
| 1044 | entry->data.enum_tag.enum_type = enum_type; | |
| 1045 | entry->data.enum_tag.int_type = int_type; | |
| 1046 | entry->type_ref = int_type->type_ref; | |
| 1047 | entry->di_type = int_type->di_type; | |
| 1048 | entry->zero_bits = int_type->zero_bits; | |
| 1049 | ||
| 1050 | return entry; | |
| 1051 | } | |
| 1052 | ||
| 1042 | 1053 | static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) { |
| 1043 | 1054 | // if you change this logic you likely must also change similar logic in parseh.cpp |
| 1044 | 1055 | assert(enum_type->id == TypeTableEntryIdEnum); |
| ... | ... | @@ -1134,7 +1145,8 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) { |
| 1134 | 1145 | enum_type->data.enumeration.gen_field_count = gen_field_index; |
| 1135 | 1146 | enum_type->data.enumeration.union_type = biggest_union_member; |
| 1136 | 1147 | |
| 1137 | TypeTableEntry *tag_type_entry = get_smallest_unsigned_int_type(g, field_count); | |
| 1148 | TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count); | |
| 1149 | TypeTableEntry *tag_type_entry = create_enum_tag_type(g, enum_type, tag_int_type); | |
| 1138 | 1150 | enum_type->data.enumeration.tag_type = tag_type_entry; |
| 1139 | 1151 | |
| 1140 | 1152 | if (biggest_union_member) { |
| ... | ... | @@ -1686,6 +1698,7 @@ TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEnt |
| 1686 | 1698 | case TypeTableEntryIdUnion: |
| 1687 | 1699 | case TypeTableEntryIdFn: |
| 1688 | 1700 | case TypeTableEntryIdBoundFn: |
| 1701 | case TypeTableEntryIdEnumTag: | |
| 1689 | 1702 | return type_entry; |
| 1690 | 1703 | } |
| 1691 | 1704 | zig_unreachable(); |
| ... | ... | @@ -1890,6 +1903,7 @@ static bool type_has_codegen_value(TypeTableEntry *type_entry) { |
| 1890 | 1903 | case TypeTableEntryIdEnum: |
| 1891 | 1904 | case TypeTableEntryIdUnion: |
| 1892 | 1905 | case TypeTableEntryIdFn: |
| 1906 | case TypeTableEntryIdEnumTag: | |
| 1893 | 1907 | return true; |
| 1894 | 1908 | |
| 1895 | 1909 | case TypeTableEntryIdTypeDecl: |
| ... | ... | @@ -2110,6 +2124,7 @@ static bool is_container(TypeTableEntry *type_entry) { |
| 2110 | 2124 | case TypeTableEntryIdNamespace: |
| 2111 | 2125 | case TypeTableEntryIdBlock: |
| 2112 | 2126 | case TypeTableEntryIdBoundFn: |
| 2127 | case TypeTableEntryIdEnumTag: | |
| 2113 | 2128 | return false; |
| 2114 | 2129 | } |
| 2115 | 2130 | zig_unreachable(); |
| ... | ... | @@ -2159,6 +2174,7 @@ void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry) { |
| 2159 | 2174 | case TypeTableEntryIdBoundFn: |
| 2160 | 2175 | case TypeTableEntryIdInvalid: |
| 2161 | 2176 | case TypeTableEntryIdVar: |
| 2177 | case TypeTableEntryIdEnumTag: | |
| 2162 | 2178 | zig_unreachable(); |
| 2163 | 2179 | } |
| 2164 | 2180 | } |
| ... | ... | @@ -2509,6 +2525,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) { |
| 2509 | 2525 | case TypeTableEntryIdPointer: |
| 2510 | 2526 | case TypeTableEntryIdPureError: |
| 2511 | 2527 | case TypeTableEntryIdFn: |
| 2528 | case TypeTableEntryIdEnumTag: | |
| 2512 | 2529 | return false; |
| 2513 | 2530 | case TypeTableEntryIdArray: |
| 2514 | 2531 | case TypeTableEntryIdStruct: |
| ... | ... | @@ -2650,6 +2667,8 @@ static uint32_t hash_const_val(TypeTableEntry *type, ConstExprValue *const_val) |
| 2650 | 2667 | return hash_ptr(const_val->data.x_import); |
| 2651 | 2668 | case TypeTableEntryIdBlock: |
| 2652 | 2669 | return hash_ptr(const_val->data.x_block); |
| 2670 | case TypeTableEntryIdEnumTag: | |
| 2671 | return 983996406 + hash_const_val(type->data.enum_tag.int_type, const_val); | |
| 2653 | 2672 | case TypeTableEntryIdBoundFn: |
| 2654 | 2673 | case TypeTableEntryIdInvalid: |
| 2655 | 2674 | case TypeTableEntryIdUnreachable: |
| ... | ... | @@ -2794,16 +2813,18 @@ static TypeTableEntry *type_of_first_thing_in_memory(TypeTableEntry *type_entry) |
| 2794 | 2813 | case TypeTableEntryIdInt: |
| 2795 | 2814 | case TypeTableEntryIdFloat: |
| 2796 | 2815 | case TypeTableEntryIdPointer: |
| 2816 | case TypeTableEntryIdEnumTag: | |
| 2797 | 2817 | return type_entry; |
| 2798 | 2818 | } |
| 2799 | 2819 | zig_unreachable(); |
| 2800 | 2820 | } |
| 2801 | 2821 | |
| 2802 | 2822 | bool type_requires_comptime(TypeTableEntry *type_entry) { |
| 2803 | switch (type_entry->id) { | |
| 2823 | switch (get_underlying_type(type_entry)->id) { | |
| 2804 | 2824 | case TypeTableEntryIdInvalid: |
| 2805 | 2825 | case TypeTableEntryIdUnreachable: |
| 2806 | 2826 | case TypeTableEntryIdVar: |
| 2827 | case TypeTableEntryIdTypeDecl: | |
| 2807 | 2828 | zig_unreachable(); |
| 2808 | 2829 | case TypeTableEntryIdNumLitFloat: |
| 2809 | 2830 | case TypeTableEntryIdNumLitInt: |
| ... | ... | @@ -2820,7 +2841,6 @@ bool type_requires_comptime(TypeTableEntry *type_entry) { |
| 2820 | 2841 | case TypeTableEntryIdUnion: |
| 2821 | 2842 | case TypeTableEntryIdMaybe: |
| 2822 | 2843 | case TypeTableEntryIdErrorUnion: |
| 2823 | case TypeTableEntryIdTypeDecl: | |
| 2824 | 2844 | case TypeTableEntryIdEnum: |
| 2825 | 2845 | case TypeTableEntryIdPureError: |
| 2826 | 2846 | case TypeTableEntryIdFn: |
| ... | ... | @@ -2828,6 +2848,7 @@ bool type_requires_comptime(TypeTableEntry *type_entry) { |
| 2828 | 2848 | case TypeTableEntryIdInt: |
| 2829 | 2849 | case TypeTableEntryIdFloat: |
| 2830 | 2850 | case TypeTableEntryIdPointer: |
| 2851 | case TypeTableEntryIdEnumTag: | |
| 2831 | 2852 | return false; |
| 2832 | 2853 | } |
| 2833 | 2854 | zig_unreachable(); |
| ... | ... | @@ -2933,3 +2954,154 @@ bool ir_get_var_is_comptime(VariableTableEntry *var) { |
| 2933 | 2954 | return var->is_comptime->static_value.data.x_bool; |
| 2934 | 2955 | } |
| 2935 | 2956 | |
| 2957 | bool const_values_equal(ConstExprValue *a, ConstExprValue *b, TypeTableEntry *type_entry) { | |
| 2958 | switch (type_entry->id) { | |
| 2959 | case TypeTableEntryIdEnum: | |
| 2960 | { | |
| 2961 | ConstEnumValue *enum1 = &a->data.x_enum; | |
| 2962 | ConstEnumValue *enum2 = &b->data.x_enum; | |
| 2963 | if (enum1->tag == enum2->tag) { | |
| 2964 | TypeEnumField *enum_field = &type_entry->data.enumeration.fields[enum1->tag]; | |
| 2965 | if (type_has_bits(enum_field->type_entry)) { | |
| 2966 | zig_panic("TODO const expr analyze enum special value for equality"); | |
| 2967 | } else { | |
| 2968 | return true; | |
| 2969 | } | |
| 2970 | } | |
| 2971 | return false; | |
| 2972 | } | |
| 2973 | case TypeTableEntryIdMetaType: | |
| 2974 | return a->data.x_type == b->data.x_type; | |
| 2975 | case TypeTableEntryIdVoid: | |
| 2976 | return true; | |
| 2977 | case TypeTableEntryIdPureError: | |
| 2978 | return a->data.x_pure_err == b->data.x_pure_err; | |
| 2979 | case TypeTableEntryIdFn: | |
| 2980 | return a->data.x_fn == b->data.x_fn; | |
| 2981 | case TypeTableEntryIdBool: | |
| 2982 | return a->data.x_bool == b->data.x_bool; | |
| 2983 | case TypeTableEntryIdInt: | |
| 2984 | case TypeTableEntryIdFloat: | |
| 2985 | case TypeTableEntryIdNumLitFloat: | |
| 2986 | case TypeTableEntryIdNumLitInt: | |
| 2987 | return bignum_cmp_eq(&a->data.x_bignum, &b->data.x_bignum); | |
| 2988 | case TypeTableEntryIdEnumTag: | |
| 2989 | return const_values_equal(a, b, type_entry->data.enum_tag.int_type); | |
| 2990 | case TypeTableEntryIdPointer: | |
| 2991 | zig_panic("TODO"); | |
| 2992 | case TypeTableEntryIdArray: | |
| 2993 | zig_panic("TODO"); | |
| 2994 | case TypeTableEntryIdStruct: | |
| 2995 | zig_panic("TODO"); | |
| 2996 | case TypeTableEntryIdUnion: | |
| 2997 | zig_panic("TODO"); | |
| 2998 | case TypeTableEntryIdUndefLit: | |
| 2999 | zig_panic("TODO"); | |
| 3000 | case TypeTableEntryIdNullLit: | |
| 3001 | zig_panic("TODO"); | |
| 3002 | case TypeTableEntryIdMaybe: | |
| 3003 | zig_panic("TODO"); | |
| 3004 | case TypeTableEntryIdErrorUnion: | |
| 3005 | zig_panic("TODO"); | |
| 3006 | case TypeTableEntryIdTypeDecl: | |
| 3007 | zig_panic("TODO"); | |
| 3008 | case TypeTableEntryIdNamespace: | |
| 3009 | zig_panic("TODO"); | |
| 3010 | case TypeTableEntryIdBlock: | |
| 3011 | zig_panic("TODO"); | |
| 3012 | case TypeTableEntryIdBoundFn: | |
| 3013 | case TypeTableEntryIdInvalid: | |
| 3014 | case TypeTableEntryIdUnreachable: | |
| 3015 | case TypeTableEntryIdVar: | |
| 3016 | zig_unreachable(); | |
| 3017 | } | |
| 3018 | zig_unreachable(); | |
| 3019 | } | |
| 3020 | ||
| 3021 | static bool int_type_depends_on_compile_var(CodeGen *g, TypeTableEntry *int_type) { | |
| 3022 | assert(int_type->id == TypeTableEntryIdInt); | |
| 3023 | ||
| 3024 | for (size_t i = 0; i < CIntTypeCount; i += 1) { | |
| 3025 | if (int_type == g->builtin_types.entry_c_int[i]) { | |
| 3026 | return true; | |
| 3027 | } | |
| 3028 | } | |
| 3029 | return false; | |
| 3030 | } | |
| 3031 | ||
| 3032 | static uint64_t max_unsigned_val(TypeTableEntry *type_entry) { | |
| 3033 | assert(type_entry->id == TypeTableEntryIdInt); | |
| 3034 | if (type_entry->data.integral.bit_count == 64) { | |
| 3035 | return UINT64_MAX; | |
| 3036 | } else if (type_entry->data.integral.bit_count == 32) { | |
| 3037 | return UINT32_MAX; | |
| 3038 | } else if (type_entry->data.integral.bit_count == 16) { | |
| 3039 | return UINT16_MAX; | |
| 3040 | } else if (type_entry->data.integral.bit_count == 8) { | |
| 3041 | return UINT8_MAX; | |
| 3042 | } else { | |
| 3043 | zig_unreachable(); | |
| 3044 | } | |
| 3045 | } | |
| 3046 | ||
| 3047 | static int64_t max_signed_val(TypeTableEntry *type_entry) { | |
| 3048 | assert(type_entry->id == TypeTableEntryIdInt); | |
| 3049 | if (type_entry->data.integral.bit_count == 64) { | |
| 3050 | return INT64_MAX; | |
| 3051 | } else if (type_entry->data.integral.bit_count == 32) { | |
| 3052 | return INT32_MAX; | |
| 3053 | } else if (type_entry->data.integral.bit_count == 16) { | |
| 3054 | return INT16_MAX; | |
| 3055 | } else if (type_entry->data.integral.bit_count == 8) { | |
| 3056 | return INT8_MAX; | |
| 3057 | } else { | |
| 3058 | zig_unreachable(); | |
| 3059 | } | |
| 3060 | } | |
| 3061 | ||
| 3062 | static int64_t min_signed_val(TypeTableEntry *type_entry) { | |
| 3063 | assert(type_entry->id == TypeTableEntryIdInt); | |
| 3064 | if (type_entry->data.integral.bit_count == 64) { | |
| 3065 | return INT64_MIN; | |
| 3066 | } else if (type_entry->data.integral.bit_count == 32) { | |
| 3067 | return INT32_MIN; | |
| 3068 | } else if (type_entry->data.integral.bit_count == 16) { | |
| 3069 | return INT16_MIN; | |
| 3070 | } else if (type_entry->data.integral.bit_count == 8) { | |
| 3071 | return INT8_MIN; | |
| 3072 | } else { | |
| 3073 | zig_unreachable(); | |
| 3074 | } | |
| 3075 | } | |
| 3076 | ||
| 3077 | void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val, bool is_max) { | |
| 3078 | if (type_entry->id == TypeTableEntryIdInt) { | |
| 3079 | const_val->special = ConstValSpecialStatic; | |
| 3080 | const_val->depends_on_compile_var = int_type_depends_on_compile_var(g, type_entry); | |
| 3081 | if (is_max) { | |
| 3082 | if (type_entry->data.integral.is_signed) { | |
| 3083 | int64_t val = max_signed_val(type_entry); | |
| 3084 | bignum_init_signed(&const_val->data.x_bignum, val); | |
| 3085 | } else { | |
| 3086 | uint64_t val = max_unsigned_val(type_entry); | |
| 3087 | bignum_init_unsigned(&const_val->data.x_bignum, val); | |
| 3088 | } | |
| 3089 | } else { | |
| 3090 | if (type_entry->data.integral.is_signed) { | |
| 3091 | int64_t val = min_signed_val(type_entry); | |
| 3092 | bignum_init_signed(&const_val->data.x_bignum, val); | |
| 3093 | } else { | |
| 3094 | bignum_init_unsigned(&const_val->data.x_bignum, 0); | |
| 3095 | } | |
| 3096 | } | |
| 3097 | } else if (type_entry->id == TypeTableEntryIdFloat) { | |
| 3098 | zig_panic("TODO analyze_min_max_value float"); | |
| 3099 | } else if (type_entry->id == TypeTableEntryIdBool) { | |
| 3100 | const_val->special = ConstValSpecialStatic; | |
| 3101 | const_val->data.x_bool = is_max; | |
| 3102 | } else if (type_entry->id == TypeTableEntryIdVoid) { | |
| 3103 | // nothing to do | |
| 3104 | } else { | |
| 3105 | zig_unreachable(); | |
| 3106 | } | |
| 3107 | } |
src/analyze.hpp+2| ... | ... | @@ -77,6 +77,8 @@ bool type_requires_comptime(TypeTableEntry *type_entry); |
| 77 | 77 | void ensure_complete_type(CodeGen *g, TypeTableEntry *type_entry); |
| 78 | 78 | void complete_enum(CodeGen *g, TypeTableEntry *enum_type); |
| 79 | 79 | bool ir_get_var_is_comptime(VariableTableEntry *var); |
| 80 | bool const_values_equal(ConstExprValue *a, ConstExprValue *b, TypeTableEntry *type_entry); | |
| 81 | void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val, bool is_max); | |
| 80 | 82 | |
| 81 | 83 | ScopeBlock *create_block_scope(AstNode *node, Scope *parent); |
| 82 | 84 | ScopeDefer *create_defer_scope(AstNode *node, Scope *parent); |
src/codegen.cpp+13-1| ... | ... | @@ -2144,6 +2144,10 @@ static LLVMValueRef ir_render_enum_tag(CodeGen *g, IrExecutable *executable, IrI |
| 2144 | 2144 | return get_handle_value(g, tag_field_ptr, tag_type); |
| 2145 | 2145 | } |
| 2146 | 2146 | |
| 2147 | static LLVMValueRef ir_render_init_enum(CodeGen *g, IrExecutable *executable, IrInstructionInitEnum *instruction) { | |
| 2148 | zig_panic("TODO ir_render_init_enum"); | |
| 2149 | } | |
| 2150 | ||
| 2147 | 2151 | static void set_debug_location(CodeGen *g, IrInstruction *instruction) { |
| 2148 | 2152 | AstNode *source_node = instruction->source_node; |
| 2149 | 2153 | Scope *scope = instruction->scope; |
| ... | ... | @@ -2278,6 +2282,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 2278 | 2282 | return ir_render_err_wrap_payload(g, executable, (IrInstructionErrWrapPayload *)instruction); |
| 2279 | 2283 | case IrInstructionIdEnumTag: |
| 2280 | 2284 | return ir_render_enum_tag(g, executable, (IrInstructionEnumTag *)instruction); |
| 2285 | case IrInstructionIdInitEnum: | |
| 2286 | return ir_render_init_enum(g, executable, (IrInstructionInitEnum *)instruction); | |
| 2281 | 2287 | case IrInstructionIdSwitchVar: |
| 2282 | 2288 | zig_panic("TODO render switch var instruction to LLVM"); |
| 2283 | 2289 | case IrInstructionIdContainerInitList: |
| ... | ... | @@ -2497,6 +2503,8 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE |
| 2497 | 2503 | } |
| 2498 | 2504 | case TypeTableEntryIdVoid: |
| 2499 | 2505 | return nullptr; |
| 2506 | case TypeTableEntryIdEnumTag: | |
| 2507 | return gen_const_val(g, type_entry->data.enum_tag.int_type, const_val); | |
| 2500 | 2508 | case TypeTableEntryIdInvalid: |
| 2501 | 2509 | case TypeTableEntryIdMetaType: |
| 2502 | 2510 | case TypeTableEntryIdUnreachable: |
| ... | ... | @@ -2876,6 +2884,9 @@ static void do_code_gen(CodeGen *g) { |
| 2876 | 2884 | } else if (instruction->id == IrInstructionIdErrWrapCode) { |
| 2877 | 2885 | IrInstructionErrWrapCode *err_wrap_code_instruction = (IrInstructionErrWrapCode *)instruction; |
| 2878 | 2886 | slot = &err_wrap_code_instruction->tmp_ptr; |
| 2887 | } else if (instruction->id == IrInstructionIdInitEnum) { | |
| 2888 | IrInstructionInitEnum *init_enum_instruction = (IrInstructionInitEnum *)instruction; | |
| 2889 | slot = &init_enum_instruction->tmp_ptr; | |
| 2879 | 2890 | } else { |
| 2880 | 2891 | zig_unreachable(); |
| 2881 | 2892 | } |
| ... | ... | @@ -3793,7 +3804,8 @@ static void get_c_type(CodeGen *g, TypeTableEntry *type_entry, Buf *out_buf) { |
| 3793 | 3804 | case TypeTableEntryIdUnion: |
| 3794 | 3805 | case TypeTableEntryIdFn: |
| 3795 | 3806 | case TypeTableEntryIdTypeDecl: |
| 3796 | zig_panic("TODO"); | |
| 3807 | case TypeTableEntryIdEnumTag: | |
| 3808 | zig_panic("TODO implement get_c_type for more types"); | |
| 3797 | 3809 | case TypeTableEntryIdInvalid: |
| 3798 | 3810 | case TypeTableEntryIdMetaType: |
| 3799 | 3811 | case TypeTableEntryIdBoundFn: |
src/eval.cpp deleted-429| ... | ... | @@ -1,429 +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 "eval.hpp" | |
| 9 | #include "analyze.hpp" | |
| 10 | #include "error.hpp" | |
| 11 | ||
| 12 | bool const_values_equal(ConstExprValue *a, ConstExprValue *b, TypeTableEntry *type_entry) { | |
| 13 | switch (type_entry->id) { | |
| 14 | case TypeTableEntryIdEnum: | |
| 15 | { | |
| 16 | ConstEnumValue *enum1 = &a->data.x_enum; | |
| 17 | ConstEnumValue *enum2 = &b->data.x_enum; | |
| 18 | if (enum1->tag == enum2->tag) { | |
| 19 | TypeEnumField *enum_field = &type_entry->data.enumeration.fields[enum1->tag]; | |
| 20 | if (type_has_bits(enum_field->type_entry)) { | |
| 21 | zig_panic("TODO const expr analyze enum special value for equality"); | |
| 22 | } else { | |
| 23 | return true; | |
| 24 | } | |
| 25 | } | |
| 26 | return false; | |
| 27 | } | |
| 28 | case TypeTableEntryIdMetaType: | |
| 29 | return a->data.x_type == b->data.x_type; | |
| 30 | case TypeTableEntryIdVoid: | |
| 31 | return true; | |
| 32 | case TypeTableEntryIdPureError: | |
| 33 | return a->data.x_pure_err == b->data.x_pure_err; | |
| 34 | case TypeTableEntryIdFn: | |
| 35 | return a->data.x_fn == b->data.x_fn; | |
| 36 | case TypeTableEntryIdBool: | |
| 37 | return a->data.x_bool == b->data.x_bool; | |
| 38 | case TypeTableEntryIdInt: | |
| 39 | case TypeTableEntryIdFloat: | |
| 40 | case TypeTableEntryIdNumLitFloat: | |
| 41 | case TypeTableEntryIdNumLitInt: | |
| 42 | return bignum_cmp_eq(&a->data.x_bignum, &b->data.x_bignum); | |
| 43 | case TypeTableEntryIdPointer: | |
| 44 | zig_panic("TODO"); | |
| 45 | case TypeTableEntryIdArray: | |
| 46 | zig_panic("TODO"); | |
| 47 | case TypeTableEntryIdStruct: | |
| 48 | zig_panic("TODO"); | |
| 49 | case TypeTableEntryIdUnion: | |
| 50 | zig_panic("TODO"); | |
| 51 | case TypeTableEntryIdUndefLit: | |
| 52 | zig_panic("TODO"); | |
| 53 | case TypeTableEntryIdNullLit: | |
| 54 | zig_panic("TODO"); | |
| 55 | case TypeTableEntryIdMaybe: | |
| 56 | zig_panic("TODO"); | |
| 57 | case TypeTableEntryIdErrorUnion: | |
| 58 | zig_panic("TODO"); | |
| 59 | case TypeTableEntryIdTypeDecl: | |
| 60 | zig_panic("TODO"); | |
| 61 | case TypeTableEntryIdNamespace: | |
| 62 | zig_panic("TODO"); | |
| 63 | case TypeTableEntryIdBlock: | |
| 64 | zig_panic("TODO"); | |
| 65 | case TypeTableEntryIdBoundFn: | |
| 66 | case TypeTableEntryIdInvalid: | |
| 67 | case TypeTableEntryIdUnreachable: | |
| 68 | case TypeTableEntryIdVar: | |
| 69 | zig_unreachable(); | |
| 70 | } | |
| 71 | zig_unreachable(); | |
| 72 | } | |
| 73 | ||
| 74 | ||
| 75 | static bool eval_bool_bin_op_bool(bool a, BinOpType bin_op, bool b) { | |
| 76 | if (bin_op == BinOpTypeBoolOr || bin_op == BinOpTypeAssignBoolOr) { | |
| 77 | return a || b; | |
| 78 | } else if (bin_op == BinOpTypeBoolAnd || bin_op == BinOpTypeAssignBoolAnd) { | |
| 79 | return a && b; | |
| 80 | } else { | |
| 81 | zig_unreachable(); | |
| 82 | } | |
| 83 | } | |
| 84 | ||
| 85 | static uint64_t max_unsigned_val(TypeTableEntry *type_entry) { | |
| 86 | assert(type_entry->id == TypeTableEntryIdInt); | |
| 87 | if (type_entry->data.integral.bit_count == 64) { | |
| 88 | return UINT64_MAX; | |
| 89 | } else if (type_entry->data.integral.bit_count == 32) { | |
| 90 | return UINT32_MAX; | |
| 91 | } else if (type_entry->data.integral.bit_count == 16) { | |
| 92 | return UINT16_MAX; | |
| 93 | } else if (type_entry->data.integral.bit_count == 8) { | |
| 94 | return UINT8_MAX; | |
| 95 | } else { | |
| 96 | zig_unreachable(); | |
| 97 | } | |
| 98 | } | |
| 99 | ||
| 100 | static int64_t max_signed_val(TypeTableEntry *type_entry) { | |
| 101 | assert(type_entry->id == TypeTableEntryIdInt); | |
| 102 | if (type_entry->data.integral.bit_count == 64) { | |
| 103 | return INT64_MAX; | |
| 104 | } else if (type_entry->data.integral.bit_count == 32) { | |
| 105 | return INT32_MAX; | |
| 106 | } else if (type_entry->data.integral.bit_count == 16) { | |
| 107 | return INT16_MAX; | |
| 108 | } else if (type_entry->data.integral.bit_count == 8) { | |
| 109 | return INT8_MAX; | |
| 110 | } else { | |
| 111 | zig_unreachable(); | |
| 112 | } | |
| 113 | } | |
| 114 | ||
| 115 | static int64_t min_signed_val(TypeTableEntry *type_entry) { | |
| 116 | assert(type_entry->id == TypeTableEntryIdInt); | |
| 117 | if (type_entry->data.integral.bit_count == 64) { | |
| 118 | return INT64_MIN; | |
| 119 | } else if (type_entry->data.integral.bit_count == 32) { | |
| 120 | return INT32_MIN; | |
| 121 | } else if (type_entry->data.integral.bit_count == 16) { | |
| 122 | return INT16_MIN; | |
| 123 | } else if (type_entry->data.integral.bit_count == 8) { | |
| 124 | return INT8_MIN; | |
| 125 | } else { | |
| 126 | zig_unreachable(); | |
| 127 | } | |
| 128 | } | |
| 129 | ||
| 130 | static int eval_const_expr_bin_op_bignum(ConstExprValue *op1_val, ConstExprValue *op2_val, | |
| 131 | ConstExprValue *out_val, bool (*bignum_fn)(BigNum *, BigNum *, BigNum *), | |
| 132 | TypeTableEntry *type, bool wrapping_op) | |
| 133 | { | |
| 134 | bool overflow = bignum_fn(&out_val->data.x_bignum, &op1_val->data.x_bignum, &op2_val->data.x_bignum); | |
| 135 | if (overflow) { | |
| 136 | return ErrorOverflow; | |
| 137 | } | |
| 138 | ||
| 139 | if (type->id == TypeTableEntryIdInt && !bignum_fits_in_bits(&out_val->data.x_bignum, | |
| 140 | type->data.integral.bit_count, type->data.integral.is_signed)) | |
| 141 | { | |
| 142 | if (wrapping_op) { | |
| 143 | if (type->data.integral.is_signed) { | |
| 144 | out_val->data.x_bignum.data.x_uint = max_unsigned_val(type) - out_val->data.x_bignum.data.x_uint + 1; | |
| 145 | out_val->data.x_bignum.is_negative = !out_val->data.x_bignum.is_negative; | |
| 146 | } else if (out_val->data.x_bignum.is_negative) { | |
| 147 | out_val->data.x_bignum.data.x_uint = max_unsigned_val(type) - out_val->data.x_bignum.data.x_uint + 1; | |
| 148 | out_val->data.x_bignum.is_negative = false; | |
| 149 | } else { | |
| 150 | bignum_truncate(&out_val->data.x_bignum, type->data.integral.bit_count); | |
| 151 | } | |
| 152 | } else { | |
| 153 | return ErrorOverflow; | |
| 154 | } | |
| 155 | } | |
| 156 | ||
| 157 | out_val->special = ConstValSpecialStatic; | |
| 158 | out_val->depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var; | |
| 159 | return 0; | |
| 160 | } | |
| 161 | ||
| 162 | int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type, | |
| 163 | BinOpType bin_op, ConstExprValue *op2_val, TypeTableEntry *op2_type, ConstExprValue *out_val) | |
| 164 | { | |
| 165 | assert(op1_val->special != ConstValSpecialRuntime); | |
| 166 | assert(op2_val->special != ConstValSpecialRuntime); | |
| 167 | assert(op1_type->id != TypeTableEntryIdInvalid); | |
| 168 | assert(op2_type->id != TypeTableEntryIdInvalid); | |
| 169 | ||
| 170 | switch (bin_op) { | |
| 171 | case BinOpTypeAssign: | |
| 172 | *out_val = *op2_val; | |
| 173 | return 0; | |
| 174 | case BinOpTypeBoolOr: | |
| 175 | case BinOpTypeBoolAnd: | |
| 176 | case BinOpTypeAssignBoolAnd: | |
| 177 | case BinOpTypeAssignBoolOr: | |
| 178 | assert(op1_type->id == TypeTableEntryIdBool); | |
| 179 | assert(op2_type->id == TypeTableEntryIdBool); | |
| 180 | out_val->data.x_bool = eval_bool_bin_op_bool(op1_val->data.x_bool, bin_op, op2_val->data.x_bool); | |
| 181 | out_val->special = ConstValSpecialStatic; | |
| 182 | out_val->depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var; | |
| 183 | return 0; | |
| 184 | case BinOpTypeCmpEq: | |
| 185 | case BinOpTypeCmpNotEq: | |
| 186 | case BinOpTypeCmpLessThan: | |
| 187 | case BinOpTypeCmpGreaterThan: | |
| 188 | case BinOpTypeCmpLessOrEq: | |
| 189 | case BinOpTypeCmpGreaterOrEq: | |
| 190 | { | |
| 191 | bool type_can_gt_lt_cmp = (op1_type->id == TypeTableEntryIdNumLitFloat || | |
| 192 | op1_type->id == TypeTableEntryIdNumLitInt || | |
| 193 | op1_type->id == TypeTableEntryIdFloat || | |
| 194 | op1_type->id == TypeTableEntryIdInt); | |
| 195 | bool answer; | |
| 196 | if (type_can_gt_lt_cmp) { | |
| 197 | bool (*bignum_cmp)(BigNum *, BigNum *); | |
| 198 | if (bin_op == BinOpTypeCmpEq) { | |
| 199 | bignum_cmp = bignum_cmp_eq; | |
| 200 | } else if (bin_op == BinOpTypeCmpNotEq) { | |
| 201 | bignum_cmp = bignum_cmp_neq; | |
| 202 | } else if (bin_op == BinOpTypeCmpLessThan) { | |
| 203 | bignum_cmp = bignum_cmp_lt; | |
| 204 | } else if (bin_op == BinOpTypeCmpGreaterThan) { | |
| 205 | bignum_cmp = bignum_cmp_gt; | |
| 206 | } else if (bin_op == BinOpTypeCmpLessOrEq) { | |
| 207 | bignum_cmp = bignum_cmp_lte; | |
| 208 | } else if (bin_op == BinOpTypeCmpGreaterOrEq) { | |
| 209 | bignum_cmp = bignum_cmp_gte; | |
| 210 | } else { | |
| 211 | zig_unreachable(); | |
| 212 | } | |
| 213 | ||
| 214 | answer = bignum_cmp(&op1_val->data.x_bignum, &op2_val->data.x_bignum); | |
| 215 | } else { | |
| 216 | bool are_equal = const_values_equal(op1_val, op2_val, op1_type); | |
| 217 | if (bin_op == BinOpTypeCmpEq) { | |
| 218 | answer = are_equal; | |
| 219 | } else if (bin_op == BinOpTypeCmpNotEq) { | |
| 220 | answer = !are_equal; | |
| 221 | } else { | |
| 222 | zig_unreachable(); | |
| 223 | } | |
| 224 | } | |
| 225 | ||
| 226 | out_val->depends_on_compile_var = | |
| 227 | op1_val->depends_on_compile_var || op2_val->depends_on_compile_var; | |
| 228 | out_val->data.x_bool = answer; | |
| 229 | out_val->special = ConstValSpecialStatic; | |
| 230 | return 0; | |
| 231 | } | |
| 232 | case BinOpTypeAdd: | |
| 233 | case BinOpTypeAssignPlus: | |
| 234 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_add, op1_type, false); | |
| 235 | case BinOpTypeAddWrap: | |
| 236 | case BinOpTypeAssignPlusWrap: | |
| 237 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_add, op1_type, true); | |
| 238 | case BinOpTypeBinOr: | |
| 239 | case BinOpTypeAssignBitOr: | |
| 240 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_or, op1_type, false); | |
| 241 | case BinOpTypeBinXor: | |
| 242 | case BinOpTypeAssignBitXor: | |
| 243 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_xor, op1_type, false); | |
| 244 | case BinOpTypeBinAnd: | |
| 245 | case BinOpTypeAssignBitAnd: | |
| 246 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_and, op1_type, false); | |
| 247 | case BinOpTypeBitShiftLeft: | |
| 248 | case BinOpTypeAssignBitShiftLeft: | |
| 249 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_shl, op1_type, false); | |
| 250 | case BinOpTypeBitShiftLeftWrap: | |
| 251 | case BinOpTypeAssignBitShiftLeftWrap: | |
| 252 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_shl, op1_type, true); | |
| 253 | case BinOpTypeBitShiftRight: | |
| 254 | case BinOpTypeAssignBitShiftRight: | |
| 255 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_shr, op1_type, false); | |
| 256 | case BinOpTypeSub: | |
| 257 | case BinOpTypeAssignMinus: | |
| 258 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_sub, op1_type, false); | |
| 259 | case BinOpTypeSubWrap: | |
| 260 | case BinOpTypeAssignMinusWrap: | |
| 261 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_sub, op1_type, true); | |
| 262 | case BinOpTypeMult: | |
| 263 | case BinOpTypeAssignTimes: | |
| 264 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_mul, op1_type, false); | |
| 265 | case BinOpTypeMultWrap: | |
| 266 | case BinOpTypeAssignTimesWrap: | |
| 267 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_mul, op1_type, true); | |
| 268 | case BinOpTypeDiv: | |
| 269 | case BinOpTypeAssignDiv: | |
| 270 | { | |
| 271 | bool is_int = false; | |
| 272 | bool is_float = false; | |
| 273 | if (op1_type->id == TypeTableEntryIdInt || | |
| 274 | op1_type->id == TypeTableEntryIdNumLitInt) | |
| 275 | { | |
| 276 | is_int = true; | |
| 277 | } else if (op1_type->id == TypeTableEntryIdFloat || | |
| 278 | op1_type->id == TypeTableEntryIdNumLitFloat) | |
| 279 | { | |
| 280 | is_float = true; | |
| 281 | } | |
| 282 | if ((is_int && op2_val->data.x_bignum.data.x_uint == 0) || | |
| 283 | (is_float && op2_val->data.x_bignum.data.x_float == 0.0)) | |
| 284 | { | |
| 285 | return ErrorDivByZero; | |
| 286 | } else { | |
| 287 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_div, op1_type, false); | |
| 288 | } | |
| 289 | } | |
| 290 | case BinOpTypeMod: | |
| 291 | case BinOpTypeAssignMod: | |
| 292 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_mod, op1_type, false); | |
| 293 | case BinOpTypeUnwrapMaybe: | |
| 294 | zig_panic("TODO"); | |
| 295 | case BinOpTypeArrayCat: | |
| 296 | case BinOpTypeArrayMult: | |
| 297 | case BinOpTypeInvalid: | |
| 298 | zig_unreachable(); | |
| 299 | } | |
| 300 | zig_unreachable(); | |
| 301 | } | |
| 302 | ||
| 303 | void eval_const_expr_implicit_cast(CastOp cast_op, | |
| 304 | ConstExprValue *other_val, TypeTableEntry *other_type, | |
| 305 | ConstExprValue *const_val, TypeTableEntry *new_type) | |
| 306 | { | |
| 307 | const_val->depends_on_compile_var = other_val->depends_on_compile_var; | |
| 308 | const_val->special = other_val->special; | |
| 309 | ||
| 310 | assert(other_val != const_val); | |
| 311 | switch (cast_op) { | |
| 312 | case CastOpNoCast: | |
| 313 | zig_unreachable(); | |
| 314 | case CastOpNoop: | |
| 315 | case CastOpWidenOrShorten: | |
| 316 | *const_val = *other_val; | |
| 317 | break; | |
| 318 | case CastOpPointerReinterpret: | |
| 319 | zig_panic("TODO compile time pointer reinterpret"); | |
| 320 | break; | |
| 321 | case CastOpPtrToInt: | |
| 322 | case CastOpIntToPtr: | |
| 323 | case CastOpResizeSlice: | |
| 324 | case CastOpBytesToSlice: | |
| 325 | // can't do it | |
| 326 | break; | |
| 327 | case CastOpToUnknownSizeArray: | |
| 328 | { | |
| 329 | assert(other_type->id == TypeTableEntryIdArray); | |
| 330 | assert(other_val->data.x_array.size == other_type->data.array.len); | |
| 331 | ||
| 332 | const_val->data.x_struct.fields = allocate<ConstExprValue>(2); | |
| 333 | ConstExprValue *ptr_field = &const_val->data.x_struct.fields[slice_ptr_index]; | |
| 334 | ConstExprValue *len_field = &const_val->data.x_struct.fields[slice_len_index]; | |
| 335 | ||
| 336 | ptr_field->special = ConstValSpecialStatic; | |
| 337 | ptr_field->data.x_ptr.base_ptr = other_val; | |
| 338 | ||
| 339 | len_field->special = ConstValSpecialStatic; | |
| 340 | bignum_init_unsigned(&len_field->data.x_bignum, other_type->data.array.len); | |
| 341 | ||
| 342 | const_val->special = ConstValSpecialStatic; | |
| 343 | break; | |
| 344 | } | |
| 345 | case CastOpErrToInt: | |
| 346 | { | |
| 347 | uint64_t value; | |
| 348 | if (other_type->id == TypeTableEntryIdErrorUnion) { | |
| 349 | value = other_val->data.x_err_union.err ? other_val->data.x_err_union.err->value : 0; | |
| 350 | } else if (other_type->id == TypeTableEntryIdPureError) { | |
| 351 | value = other_val->data.x_pure_err->value; | |
| 352 | } else { | |
| 353 | zig_unreachable(); | |
| 354 | } | |
| 355 | bignum_init_unsigned(&const_val->data.x_bignum, value); | |
| 356 | const_val->special = ConstValSpecialStatic; | |
| 357 | break; | |
| 358 | } | |
| 359 | case CastOpIntToFloat: | |
| 360 | bignum_cast_to_float(&const_val->data.x_bignum, &other_val->data.x_bignum); | |
| 361 | const_val->special = ConstValSpecialStatic; | |
| 362 | break; | |
| 363 | case CastOpFloatToInt: | |
| 364 | bignum_cast_to_int(&const_val->data.x_bignum, &other_val->data.x_bignum); | |
| 365 | const_val->special = ConstValSpecialStatic; | |
| 366 | break; | |
| 367 | case CastOpBoolToInt: | |
| 368 | bignum_init_unsigned(&const_val->data.x_bignum, other_val->data.x_bool ? 1 : 0); | |
| 369 | const_val->special = ConstValSpecialStatic; | |
| 370 | break; | |
| 371 | case CastOpIntToEnum: | |
| 372 | { | |
| 373 | uint64_t value = other_val->data.x_bignum.data.x_uint; | |
| 374 | assert(new_type->id == TypeTableEntryIdEnum); | |
| 375 | assert(value < new_type->data.enumeration.src_field_count); | |
| 376 | const_val->data.x_enum.tag = value; | |
| 377 | const_val->data.x_enum.payload = NULL; | |
| 378 | const_val->special = ConstValSpecialStatic; | |
| 379 | break; | |
| 380 | } | |
| 381 | case CastOpEnumToInt: | |
| 382 | bignum_init_unsigned(&const_val->data.x_bignum, other_val->data.x_enum.tag); | |
| 383 | const_val->special = ConstValSpecialStatic; | |
| 384 | break; | |
| 385 | } | |
| 386 | } | |
| 387 | ||
| 388 | static bool int_type_depends_on_compile_var(CodeGen *g, TypeTableEntry *int_type) { | |
| 389 | assert(int_type->id == TypeTableEntryIdInt); | |
| 390 | ||
| 391 | for (size_t i = 0; i < CIntTypeCount; i += 1) { | |
| 392 | if (int_type == g->builtin_types.entry_c_int[i]) { | |
| 393 | return true; | |
| 394 | } | |
| 395 | } | |
| 396 | return false; | |
| 397 | } | |
| 398 | ||
| 399 | void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val, bool is_max) { | |
| 400 | if (type_entry->id == TypeTableEntryIdInt) { | |
| 401 | const_val->special = ConstValSpecialStatic; | |
| 402 | const_val->depends_on_compile_var = int_type_depends_on_compile_var(g, type_entry); | |
| 403 | if (is_max) { | |
| 404 | if (type_entry->data.integral.is_signed) { | |
| 405 | int64_t val = max_signed_val(type_entry); | |
| 406 | bignum_init_signed(&const_val->data.x_bignum, val); | |
| 407 | } else { | |
| 408 | uint64_t val = max_unsigned_val(type_entry); | |
| 409 | bignum_init_unsigned(&const_val->data.x_bignum, val); | |
| 410 | } | |
| 411 | } else { | |
| 412 | if (type_entry->data.integral.is_signed) { | |
| 413 | int64_t val = min_signed_val(type_entry); | |
| 414 | bignum_init_signed(&const_val->data.x_bignum, val); | |
| 415 | } else { | |
| 416 | bignum_init_unsigned(&const_val->data.x_bignum, 0); | |
| 417 | } | |
| 418 | } | |
| 419 | } else if (type_entry->id == TypeTableEntryIdFloat) { | |
| 420 | zig_panic("TODO analyze_min_max_value float"); | |
| 421 | } else if (type_entry->id == TypeTableEntryIdBool) { | |
| 422 | const_val->special = ConstValSpecialStatic; | |
| 423 | const_val->data.x_bool = is_max; | |
| 424 | } else if (type_entry->id == TypeTableEntryIdVoid) { | |
| 425 | // nothing to do | |
| 426 | } else { | |
| 427 | zig_unreachable(); | |
| 428 | } | |
| 429 | } |
src/eval.hpp deleted-23| ... | ... | @@ -1,23 +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_EVAL_HPP | |
| 9 | #define ZIG_EVAL_HPP | |
| 10 | ||
| 11 | #include "all_types.hpp" | |
| 12 | ||
| 13 | bool const_values_equal(ConstExprValue *a, ConstExprValue *b, TypeTableEntry *type_entry); | |
| 14 | int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type, | |
| 15 | BinOpType bin_op, ConstExprValue *op2_val, TypeTableEntry *op2_type, ConstExprValue *out_val); | |
| 16 | ||
| 17 | void eval_const_expr_implicit_cast(CastOp cast_op, | |
| 18 | ConstExprValue *other_val, TypeTableEntry *other_type, | |
| 19 | ConstExprValue *const_val, TypeTableEntry *new_type); | |
| 20 | ||
| 21 | void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val, bool is_max); | |
| 22 | ||
| 23 | #endif |
src/ir.cpp+245-107| ... | ... | @@ -8,7 +8,6 @@ |
| 8 | 8 | #include "analyze.hpp" |
| 9 | 9 | #include "ast_render.hpp" |
| 10 | 10 | #include "error.hpp" |
| 11 | #include "eval.hpp" | |
| 12 | 11 | #include "ir.hpp" |
| 13 | 12 | #include "ir_print.hpp" |
| 14 | 13 | #include "os.hpp" |
| ... | ... | @@ -447,6 +446,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTestComptime *) |
| 447 | 446 | return IrInstructionIdTestComptime; |
| 448 | 447 | } |
| 449 | 448 | |
| 449 | static constexpr IrInstructionId ir_instruction_id(IrInstructionInitEnum *) { | |
| 450 | return IrInstructionIdInitEnum; | |
| 451 | } | |
| 452 | ||
| 450 | 453 | template<typename T> |
| 451 | 454 | static T *ir_create_instruction(IrExecutable *exec, Scope *scope, AstNode *source_node) { |
| 452 | 455 | T *special_instruction = allocate<T>(1); |
| ... | ... | @@ -1861,6 +1864,28 @@ static IrInstruction *ir_build_test_comptime(IrBuilder *irb, Scope *scope, AstNo |
| 1861 | 1864 | return &instruction->base; |
| 1862 | 1865 | } |
| 1863 | 1866 | |
| 1867 | static IrInstruction *ir_build_init_enum(IrBuilder *irb, Scope *scope, AstNode *source_node, | |
| 1868 | TypeTableEntry *enum_type, TypeEnumField *field, IrInstruction *init_value) | |
| 1869 | { | |
| 1870 | IrInstructionInitEnum *instruction = ir_build_instruction<IrInstructionInitEnum>(irb, scope, source_node); | |
| 1871 | instruction->enum_type = enum_type; | |
| 1872 | instruction->field = field; | |
| 1873 | instruction->init_value = init_value; | |
| 1874 | ||
| 1875 | ir_ref_instruction(init_value); | |
| 1876 | ||
| 1877 | return &instruction->base; | |
| 1878 | } | |
| 1879 | ||
| 1880 | static IrInstruction *ir_build_init_enum_from(IrBuilder *irb, IrInstruction *old_instruction, | |
| 1881 | TypeTableEntry *enum_type, TypeEnumField *field, IrInstruction *init_value) | |
| 1882 | { | |
| 1883 | IrInstruction *new_instruction = ir_build_init_enum(irb, old_instruction->scope, old_instruction->source_node, | |
| 1884 | enum_type, field, init_value); | |
| 1885 | ir_link_new_instruction(new_instruction, old_instruction); | |
| 1886 | return new_instruction; | |
| 1887 | } | |
| 1888 | ||
| 1864 | 1889 | static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) { |
| 1865 | 1890 | results[ReturnKindUnconditional] = 0; |
| 1866 | 1891 | results[ReturnKindError] = 0; |
| ... | ... | @@ -4596,6 +4621,90 @@ static void ir_add_alloca(IrAnalyze *ira, IrInstruction *instruction, TypeTableE |
| 4596 | 4621 | } |
| 4597 | 4622 | } |
| 4598 | 4623 | |
| 4624 | static void eval_const_expr_implicit_cast(CastOp cast_op, | |
| 4625 | ConstExprValue *other_val, TypeTableEntry *other_type, | |
| 4626 | ConstExprValue *const_val, TypeTableEntry *new_type) | |
| 4627 | { | |
| 4628 | const_val->depends_on_compile_var = other_val->depends_on_compile_var; | |
| 4629 | const_val->special = other_val->special; | |
| 4630 | ||
| 4631 | assert(other_val != const_val); | |
| 4632 | switch (cast_op) { | |
| 4633 | case CastOpNoCast: | |
| 4634 | zig_unreachable(); | |
| 4635 | case CastOpNoop: | |
| 4636 | case CastOpWidenOrShorten: | |
| 4637 | *const_val = *other_val; | |
| 4638 | break; | |
| 4639 | case CastOpPointerReinterpret: | |
| 4640 | zig_panic("TODO compile time pointer reinterpret"); | |
| 4641 | break; | |
| 4642 | case CastOpPtrToInt: | |
| 4643 | case CastOpIntToPtr: | |
| 4644 | case CastOpResizeSlice: | |
| 4645 | case CastOpBytesToSlice: | |
| 4646 | // can't do it | |
| 4647 | break; | |
| 4648 | case CastOpToUnknownSizeArray: | |
| 4649 | { | |
| 4650 | assert(other_type->id == TypeTableEntryIdArray); | |
| 4651 | assert(other_val->data.x_array.size == other_type->data.array.len); | |
| 4652 | ||
| 4653 | const_val->data.x_struct.fields = allocate<ConstExprValue>(2); | |
| 4654 | ConstExprValue *ptr_field = &const_val->data.x_struct.fields[slice_ptr_index]; | |
| 4655 | ConstExprValue *len_field = &const_val->data.x_struct.fields[slice_len_index]; | |
| 4656 | ||
| 4657 | ptr_field->special = ConstValSpecialStatic; | |
| 4658 | ptr_field->data.x_ptr.base_ptr = other_val; | |
| 4659 | ||
| 4660 | len_field->special = ConstValSpecialStatic; | |
| 4661 | bignum_init_unsigned(&len_field->data.x_bignum, other_type->data.array.len); | |
| 4662 | ||
| 4663 | const_val->special = ConstValSpecialStatic; | |
| 4664 | break; | |
| 4665 | } | |
| 4666 | case CastOpErrToInt: | |
| 4667 | { | |
| 4668 | uint64_t value; | |
| 4669 | if (other_type->id == TypeTableEntryIdErrorUnion) { | |
| 4670 | value = other_val->data.x_err_union.err ? other_val->data.x_err_union.err->value : 0; | |
| 4671 | } else if (other_type->id == TypeTableEntryIdPureError) { | |
| 4672 | value = other_val->data.x_pure_err->value; | |
| 4673 | } else { | |
| 4674 | zig_unreachable(); | |
| 4675 | } | |
| 4676 | bignum_init_unsigned(&const_val->data.x_bignum, value); | |
| 4677 | const_val->special = ConstValSpecialStatic; | |
| 4678 | break; | |
| 4679 | } | |
| 4680 | case CastOpIntToFloat: | |
| 4681 | bignum_cast_to_float(&const_val->data.x_bignum, &other_val->data.x_bignum); | |
| 4682 | const_val->special = ConstValSpecialStatic; | |
| 4683 | break; | |
| 4684 | case CastOpFloatToInt: | |
| 4685 | bignum_cast_to_int(&const_val->data.x_bignum, &other_val->data.x_bignum); | |
| 4686 | const_val->special = ConstValSpecialStatic; | |
| 4687 | break; | |
| 4688 | case CastOpBoolToInt: | |
| 4689 | bignum_init_unsigned(&const_val->data.x_bignum, other_val->data.x_bool ? 1 : 0); | |
| 4690 | const_val->special = ConstValSpecialStatic; | |
| 4691 | break; | |
| 4692 | case CastOpIntToEnum: | |
| 4693 | { | |
| 4694 | uint64_t value = other_val->data.x_bignum.data.x_uint; | |
| 4695 | assert(new_type->id == TypeTableEntryIdEnum); | |
| 4696 | assert(value < new_type->data.enumeration.src_field_count); | |
| 4697 | const_val->data.x_enum.tag = value; | |
| 4698 | const_val->data.x_enum.payload = NULL; | |
| 4699 | const_val->special = ConstValSpecialStatic; | |
| 4700 | break; | |
| 4701 | } | |
| 4702 | case CastOpEnumToInt: | |
| 4703 | bignum_init_unsigned(&const_val->data.x_bignum, other_val->data.x_enum.tag); | |
| 4704 | const_val->special = ConstValSpecialStatic; | |
| 4705 | break; | |
| 4706 | } | |
| 4707 | } | |
| 4599 | 4708 | static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, |
| 4600 | 4709 | TypeTableEntry *wanted_type, CastOp cast_op, bool need_alloca) |
| 4601 | 4710 | { |
| ... | ... | @@ -5562,6 +5671,9 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp |
| 5562 | 5671 | buf_sprintf("operator not allowed for type '%s'", buf_ptr(&resolved_type->name))); |
| 5563 | 5672 | return ira->codegen->builtin_types.entry_invalid; |
| 5564 | 5673 | |
| 5674 | case TypeTableEntryIdEnumTag: | |
| 5675 | zig_panic("TODO implement comparison for enum tag type"); | |
| 5676 | ||
| 5565 | 5677 | case TypeTableEntryIdVar: |
| 5566 | 5678 | zig_unreachable(); |
| 5567 | 5679 | } |
| ... | ... | @@ -6074,6 +6186,7 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc |
| 6074 | 6186 | case TypeTableEntryIdUnion: |
| 6075 | 6187 | case TypeTableEntryIdFn: |
| 6076 | 6188 | case TypeTableEntryIdBoundFn: |
| 6189 | case TypeTableEntryIdEnumTag: | |
| 6077 | 6190 | // OK |
| 6078 | 6191 | break; |
| 6079 | 6192 | } |
| ... | ... | @@ -6517,6 +6630,7 @@ static TypeTableEntry *ir_analyze_unary_prefix_op_err(IrAnalyze *ira, IrInstruct |
| 6517 | 6630 | case TypeTableEntryIdUnion: |
| 6518 | 6631 | case TypeTableEntryIdFn: |
| 6519 | 6632 | case TypeTableEntryIdBoundFn: |
| 6633 | case TypeTableEntryIdEnumTag: | |
| 6520 | 6634 | { |
| 6521 | 6635 | ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base, |
| 6522 | 6636 | value->static_value.depends_on_compile_var); |
| ... | ... | @@ -6603,6 +6717,7 @@ static TypeTableEntry *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op |
| 6603 | 6717 | case TypeTableEntryIdNamespace: |
| 6604 | 6718 | case TypeTableEntryIdBlock: |
| 6605 | 6719 | case TypeTableEntryIdBoundFn: |
| 6720 | case TypeTableEntryIdEnumTag: | |
| 6606 | 6721 | { |
| 6607 | 6722 | ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base, |
| 6608 | 6723 | value->static_value.depends_on_compile_var); |
| ... | ... | @@ -7175,7 +7290,11 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru |
| 7175 | 7290 | create_const_enum_tag(field->value), child_type, depends_on_compile_var, |
| 7176 | 7291 | ConstPtrSpecialNone, ptr_is_const); |
| 7177 | 7292 | } else { |
| 7178 | zig_panic("TODO enum tag type"); | |
| 7293 | bool ptr_is_const = true; | |
| 7294 | return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, | |
| 7295 | create_const_unsigned_negative(field->value, false), | |
| 7296 | child_type->data.enumeration.tag_type, depends_on_compile_var, | |
| 7297 | ConstPtrSpecialNone, ptr_is_const); | |
| 7179 | 7298 | } |
| 7180 | 7299 | } |
| 7181 | 7300 | } |
| ... | ... | @@ -7377,6 +7496,7 @@ static TypeTableEntry *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructi |
| 7377 | 7496 | case TypeTableEntryIdUnion: |
| 7378 | 7497 | case TypeTableEntryIdFn: |
| 7379 | 7498 | case TypeTableEntryIdTypeDecl: |
| 7499 | case TypeTableEntryIdEnumTag: | |
| 7380 | 7500 | { |
| 7381 | 7501 | ConstExprValue *out_val = ir_build_const_from(ira, &typeof_instruction->base, false); |
| 7382 | 7502 | // TODO depends_on_compile_var should be set based on whether the type of the expression |
| ... | ... | @@ -7596,6 +7716,7 @@ static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira, |
| 7596 | 7716 | case TypeTableEntryIdFn: |
| 7597 | 7717 | case TypeTableEntryIdNamespace: |
| 7598 | 7718 | case TypeTableEntryIdBoundFn: |
| 7719 | case TypeTableEntryIdEnumTag: | |
| 7599 | 7720 | { |
| 7600 | 7721 | TypeTableEntry *result_type = get_slice_type(ira->codegen, resolved_child_type, is_const); |
| 7601 | 7722 | ConstExprValue *out_val = ir_build_const_from(ira, &slice_type_instruction->base, |
| ... | ... | @@ -7685,6 +7806,7 @@ static TypeTableEntry *ir_analyze_instruction_array_type(IrAnalyze *ira, |
| 7685 | 7806 | case TypeTableEntryIdFn: |
| 7686 | 7807 | case TypeTableEntryIdNamespace: |
| 7687 | 7808 | case TypeTableEntryIdBoundFn: |
| 7809 | case TypeTableEntryIdEnumTag: | |
| 7688 | 7810 | { |
| 7689 | 7811 | TypeTableEntry *result_type = get_array_type(ira->codegen, child_type, size); |
| 7690 | 7812 | bool depends_on_compile_var = child_type_value->static_value.depends_on_compile_var || |
| ... | ... | @@ -7774,6 +7896,7 @@ static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira, |
| 7774 | 7896 | case TypeTableEntryIdPureError: |
| 7775 | 7897 | case TypeTableEntryIdEnum: |
| 7776 | 7898 | case TypeTableEntryIdUnion: |
| 7899 | case TypeTableEntryIdEnumTag: | |
| 7777 | 7900 | { |
| 7778 | 7901 | uint64_t size_in_bytes = type_size(ira->codegen, type_entry); |
| 7779 | 7902 | bool depends_on_compile_var = false; // TODO types should be able to depend on compile var |
| ... | ... | @@ -8089,6 +8212,8 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira, |
| 8089 | 8212 | case TypeTableEntryIdErrorUnion: |
| 8090 | 8213 | // see https://github.com/andrewrk/zig/issues/83 |
| 8091 | 8214 | zig_panic("TODO switch on error union"); |
| 8215 | case TypeTableEntryIdEnumTag: | |
| 8216 | zig_panic("TODO switch on enum tag type"); | |
| 8092 | 8217 | case TypeTableEntryIdUnreachable: |
| 8093 | 8218 | case TypeTableEntryIdArray: |
| 8094 | 8219 | case TypeTableEntryIdStruct: |
| ... | ... | @@ -8347,86 +8472,133 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru |
| 8347 | 8472 | |
| 8348 | 8473 | static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira, IrInstructionContainerInitList *instruction) { |
| 8349 | 8474 | IrInstruction *container_type_value = instruction->container_type->other; |
| 8350 | TypeTableEntry *container_type = ir_resolve_type(ira, container_type_value); | |
| 8351 | if (container_type->id == TypeTableEntryIdInvalid) | |
| 8475 | if (container_type_value->type_entry->id == TypeTableEntryIdInvalid) | |
| 8352 | 8476 | return ira->codegen->builtin_types.entry_invalid; |
| 8353 | 8477 | |
| 8354 | 8478 | size_t elem_count = instruction->item_count; |
| 8355 | bool depends_on_compile_var = container_type_value->static_value.depends_on_compile_var; | |
| 8479 | if (container_type_value->type_entry->id == TypeTableEntryIdMetaType) { | |
| 8480 | TypeTableEntry *container_type = ir_resolve_type(ira, container_type_value); | |
| 8481 | if (container_type->id == TypeTableEntryIdInvalid) | |
| 8482 | return ira->codegen->builtin_types.entry_invalid; | |
| 8356 | 8483 | |
| 8357 | if (container_type->id == TypeTableEntryIdStruct && !is_slice(container_type) && elem_count == 0) { | |
| 8358 | return ir_analyze_container_init_fields(ira, &instruction->base, container_type, 0, nullptr, depends_on_compile_var); | |
| 8359 | } else if (is_slice(container_type)) { | |
| 8360 | TypeTableEntry *pointer_type = container_type->data.structure.fields[slice_ptr_index].type_entry; | |
| 8361 | assert(pointer_type->id == TypeTableEntryIdPointer); | |
| 8362 | TypeTableEntry *child_type = pointer_type->data.pointer.child_type; | |
| 8484 | bool depends_on_compile_var = container_type_value->static_value.depends_on_compile_var; | |
| 8363 | 8485 | |
| 8364 | ConstExprValue const_val = {}; | |
| 8365 | const_val.special = ConstValSpecialStatic; | |
| 8366 | const_val.depends_on_compile_var = depends_on_compile_var; | |
| 8367 | const_val.data.x_array.elements = allocate<ConstExprValue>(elem_count); | |
| 8368 | const_val.data.x_array.size = elem_count; | |
| 8486 | if (container_type->id == TypeTableEntryIdStruct && !is_slice(container_type) && elem_count == 0) { | |
| 8487 | return ir_analyze_container_init_fields(ira, &instruction->base, container_type, 0, nullptr, depends_on_compile_var); | |
| 8488 | } else if (is_slice(container_type)) { | |
| 8489 | TypeTableEntry *pointer_type = container_type->data.structure.fields[slice_ptr_index].type_entry; | |
| 8490 | assert(pointer_type->id == TypeTableEntryIdPointer); | |
| 8491 | TypeTableEntry *child_type = pointer_type->data.pointer.child_type; | |
| 8369 | 8492 | |
| 8370 | FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec); | |
| 8371 | bool outside_fn = (fn_entry == nullptr); | |
| 8493 | ConstExprValue const_val = {}; | |
| 8494 | const_val.special = ConstValSpecialStatic; | |
| 8495 | const_val.depends_on_compile_var = depends_on_compile_var; | |
| 8496 | const_val.data.x_array.elements = allocate<ConstExprValue>(elem_count); | |
| 8497 | const_val.data.x_array.size = elem_count; | |
| 8372 | 8498 | |
| 8373 | IrInstruction **new_items = allocate<IrInstruction *>(elem_count); | |
| 8499 | FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec); | |
| 8500 | bool outside_fn = (fn_entry == nullptr); | |
| 8374 | 8501 | |
| 8375 | IrInstruction *first_non_const_instruction = nullptr; | |
| 8502 | IrInstruction **new_items = allocate<IrInstruction *>(elem_count); | |
| 8376 | 8503 | |
| 8377 | for (size_t i = 0; i < elem_count; i += 1) { | |
| 8378 | IrInstruction *arg_value = instruction->items[i]->other; | |
| 8379 | if (arg_value->type_entry->id == TypeTableEntryIdInvalid) | |
| 8380 | return ira->codegen->builtin_types.entry_invalid; | |
| 8504 | IrInstruction *first_non_const_instruction = nullptr; | |
| 8381 | 8505 | |
| 8382 | new_items[i] = arg_value; | |
| 8506 | for (size_t i = 0; i < elem_count; i += 1) { | |
| 8507 | IrInstruction *arg_value = instruction->items[i]->other; | |
| 8508 | if (arg_value->type_entry->id == TypeTableEntryIdInvalid) | |
| 8509 | return ira->codegen->builtin_types.entry_invalid; | |
| 8383 | 8510 | |
| 8384 | if (const_val.special == ConstValSpecialStatic) { | |
| 8385 | if (outside_fn || arg_value->static_value.special != ConstValSpecialRuntime) { | |
| 8386 | ConstExprValue *elem_val = ir_resolve_const(ira, arg_value, UndefBad); | |
| 8387 | if (!elem_val) | |
| 8388 | return ira->codegen->builtin_types.entry_invalid; | |
| 8511 | new_items[i] = arg_value; | |
| 8389 | 8512 | |
| 8390 | const_val.data.x_array.elements[i] = *elem_val; | |
| 8391 | const_val.depends_on_compile_var = const_val.depends_on_compile_var || elem_val->depends_on_compile_var; | |
| 8392 | } else { | |
| 8393 | first_non_const_instruction = arg_value; | |
| 8394 | const_val.special = ConstValSpecialRuntime; | |
| 8513 | if (const_val.special == ConstValSpecialStatic) { | |
| 8514 | if (outside_fn || arg_value->static_value.special != ConstValSpecialRuntime) { | |
| 8515 | ConstExprValue *elem_val = ir_resolve_const(ira, arg_value, UndefBad); | |
| 8516 | if (!elem_val) | |
| 8517 | return ira->codegen->builtin_types.entry_invalid; | |
| 8518 | ||
| 8519 | const_val.data.x_array.elements[i] = *elem_val; | |
| 8520 | const_val.depends_on_compile_var = const_val.depends_on_compile_var || elem_val->depends_on_compile_var; | |
| 8521 | } else { | |
| 8522 | first_non_const_instruction = arg_value; | |
| 8523 | const_val.special = ConstValSpecialRuntime; | |
| 8524 | } | |
| 8395 | 8525 | } |
| 8396 | 8526 | } |
| 8397 | } | |
| 8398 | 8527 | |
| 8399 | TypeTableEntry *fixed_size_array_type = get_array_type(ira->codegen, child_type, elem_count); | |
| 8400 | if (const_val.special == ConstValSpecialStatic) { | |
| 8401 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, const_val.depends_on_compile_var); | |
| 8402 | *out_val = const_val; | |
| 8528 | TypeTableEntry *fixed_size_array_type = get_array_type(ira->codegen, child_type, elem_count); | |
| 8529 | if (const_val.special == ConstValSpecialStatic) { | |
| 8530 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, const_val.depends_on_compile_var); | |
| 8531 | *out_val = const_val; | |
| 8532 | return fixed_size_array_type; | |
| 8533 | } | |
| 8534 | ||
| 8535 | if (outside_fn) { | |
| 8536 | ir_add_error_node(ira, first_non_const_instruction->source_node, | |
| 8537 | buf_sprintf("unable to evaluate constant expression")); | |
| 8538 | return ira->codegen->builtin_types.entry_invalid; | |
| 8539 | } | |
| 8540 | ||
| 8541 | IrInstruction *new_instruction = ir_build_container_init_list_from(&ira->new_irb, &instruction->base, | |
| 8542 | container_type_value, elem_count, new_items); | |
| 8543 | ir_add_alloca(ira, new_instruction, fixed_size_array_type); | |
| 8403 | 8544 | return fixed_size_array_type; |
| 8545 | } else if (container_type->id == TypeTableEntryIdArray) { | |
| 8546 | // same as slice init but we make a compile error if the length is wrong | |
| 8547 | zig_panic("TODO array container init"); | |
| 8548 | } else if (container_type->id == TypeTableEntryIdVoid) { | |
| 8549 | if (elem_count != 0) { | |
| 8550 | ir_add_error_node(ira, instruction->base.source_node, | |
| 8551 | buf_sprintf("void expression expects no arguments")); | |
| 8552 | return ira->codegen->builtin_types.entry_invalid; | |
| 8553 | } | |
| 8554 | return ir_analyze_void(ira, &instruction->base); | |
| 8555 | } else { | |
| 8556 | ir_add_error_node(ira, instruction->base.source_node, | |
| 8557 | buf_sprintf("type '%s' does not support array initialization", | |
| 8558 | buf_ptr(&container_type->name))); | |
| 8559 | return ira->codegen->builtin_types.entry_invalid; | |
| 8404 | 8560 | } |
| 8405 | ||
| 8406 | if (outside_fn) { | |
| 8407 | ir_add_error_node(ira, first_non_const_instruction->source_node, | |
| 8408 | buf_sprintf("unable to evaluate constant expression")); | |
| 8561 | } else if (container_type_value->type_entry->id == TypeTableEntryIdEnumTag) { | |
| 8562 | // TODO I wrote this commit message when I had some sake | |
| 8563 | // might be worth re-examining sober | |
| 8564 | if (elem_count != 1) { | |
| 8565 | ir_add_error(ira, &instruction->base, buf_sprintf("expected 1 elment")); | |
| 8409 | 8566 | return ira->codegen->builtin_types.entry_invalid; |
| 8410 | 8567 | } |
| 8568 | ConstExprValue *tag_value = ir_resolve_const(ira, container_type_value, UndefBad); | |
| 8569 | if (!tag_value) | |
| 8570 | return ira->codegen->builtin_types.entry_invalid; | |
| 8411 | 8571 | |
| 8412 | IrInstruction *new_instruction = ir_build_container_init_list_from(&ira->new_irb, &instruction->base, | |
| 8413 | container_type_value, elem_count, new_items); | |
| 8414 | ir_add_alloca(ira, new_instruction, fixed_size_array_type); | |
| 8415 | return fixed_size_array_type; | |
| 8416 | } else if (container_type->id == TypeTableEntryIdArray) { | |
| 8417 | // same as slice init but we make a compile error if the length is wrong | |
| 8418 | zig_panic("TODO array container init"); | |
| 8419 | } else if (container_type->id == TypeTableEntryIdVoid) { | |
| 8420 | if (elem_count != 0) { | |
| 8421 | ir_add_error_node(ira, instruction->base.source_node, | |
| 8422 | buf_sprintf("void expression expects no arguments")); | |
| 8572 | TypeTableEntry *enum_type = container_type_value->type_entry->data.enum_tag.enum_type; | |
| 8573 | ||
| 8574 | uint64_t tag_uint = tag_value->data.x_bignum.data.x_uint; | |
| 8575 | TypeEnumField *field = &enum_type->data.enumeration.fields[tag_uint]; | |
| 8576 | TypeTableEntry *this_field_type = field->type_entry; | |
| 8577 | ||
| 8578 | IrInstruction *init_value = instruction->items[0]->other; | |
| 8579 | ||
| 8580 | IrInstruction *casted_init_value = ir_implicit_cast(ira, init_value, this_field_type); | |
| 8581 | if (casted_init_value == ira->codegen->invalid_instruction) | |
| 8423 | 8582 | return ira->codegen->builtin_types.entry_invalid; |
| 8583 | ||
| 8584 | if (instr_is_comptime(casted_init_value)) { | |
| 8585 | ConstExprValue *init_val = ir_resolve_const(ira, casted_init_value, UndefOk); | |
| 8586 | if (!init_val) | |
| 8587 | return ira->codegen->builtin_types.entry_invalid; | |
| 8588 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, | |
| 8589 | casted_init_value->static_value.depends_on_compile_var); | |
| 8590 | out_val->data.x_enum.tag = tag_uint; | |
| 8591 | out_val->data.x_enum.payload = init_val; | |
| 8592 | return enum_type; | |
| 8424 | 8593 | } |
| 8425 | return ir_analyze_void(ira, &instruction->base); | |
| 8594 | ||
| 8595 | IrInstruction *new_instruction = ir_build_init_enum_from(&ira->new_irb, &instruction->base, | |
| 8596 | enum_type, field, casted_init_value); | |
| 8597 | ir_add_alloca(ira, new_instruction, enum_type); | |
| 8598 | return enum_type; | |
| 8426 | 8599 | } else { |
| 8427 | ir_add_error_node(ira, instruction->base.source_node, | |
| 8428 | buf_sprintf("type '%s' does not support array initialization", | |
| 8429 | buf_ptr(&container_type->name))); | |
| 8600 | ir_add_error(ira, container_type_value, | |
| 8601 | buf_sprintf("expected type, found '%s'", buf_ptr(&container_type_value->type_entry->name))); | |
| 8430 | 8602 | return ira->codegen->builtin_types.entry_invalid; |
| 8431 | 8603 | } |
| 8432 | 8604 | } |
| ... | ... | @@ -8471,6 +8643,8 @@ static TypeTableEntry *ir_analyze_min_max(IrAnalyze *ira, IrInstruction *source_ |
| 8471 | 8643 | eval_min_max_value(ira->codegen, canon_type, out_val, is_max); |
| 8472 | 8644 | return target_type; |
| 8473 | 8645 | } |
| 8646 | case TypeTableEntryIdEnumTag: | |
| 8647 | zig_panic("TODO min/max value for enum tag type"); | |
| 8474 | 8648 | case TypeTableEntryIdVar: |
| 8475 | 8649 | case TypeTableEntryIdMetaType: |
| 8476 | 8650 | case TypeTableEntryIdUnreachable: |
| ... | ... | @@ -8984,55 +9158,17 @@ static TypeTableEntry *ir_analyze_instruction_alloca(IrAnalyze *ira, IrInstructi |
| 8984 | 9158 | return ira->codegen->builtin_types.entry_invalid; |
| 8985 | 9159 | |
| 8986 | 9160 | TypeTableEntry *child_type = ir_resolve_type(ira, type_value); |
| 8987 | TypeTableEntry *canon_type = get_underlying_type(child_type); | |
| 8988 | 9161 | |
| 8989 | if (count_value->static_value.special == ConstValSpecialStatic) { | |
| 8990 | // this should be the same as an array declaration | |
| 8991 | ||
| 8992 | uint64_t count; | |
| 8993 | if (!ir_resolve_usize(ira, count_value, &count)) | |
| 8994 | return ira->codegen->builtin_types.entry_invalid; | |
| 8995 | ||
| 8996 | zig_panic("TODO alloca with compile time known count"); | |
| 8997 | } | |
| 8998 | ||
| 8999 | switch (canon_type->id) { | |
| 9000 | case TypeTableEntryIdInvalid: | |
| 9001 | case TypeTableEntryIdTypeDecl: | |
| 9002 | zig_unreachable(); | |
| 9003 | case TypeTableEntryIdBool: | |
| 9004 | case TypeTableEntryIdVoid: | |
| 9005 | case TypeTableEntryIdInt: | |
| 9006 | case TypeTableEntryIdFloat: | |
| 9007 | case TypeTableEntryIdPointer: | |
| 9008 | case TypeTableEntryIdArray: | |
| 9009 | case TypeTableEntryIdStruct: | |
| 9010 | case TypeTableEntryIdMaybe: | |
| 9011 | case TypeTableEntryIdErrorUnion: | |
| 9012 | case TypeTableEntryIdPureError: | |
| 9013 | case TypeTableEntryIdEnum: | |
| 9014 | case TypeTableEntryIdUnion: | |
| 9015 | case TypeTableEntryIdFn: | |
| 9016 | { | |
| 9017 | TypeTableEntry *slice_type = get_slice_type(ira->codegen, child_type, false); | |
| 9018 | IrInstruction *new_instruction = ir_build_alloca_from(&ira->new_irb, &instruction->base, type_value, count_value); | |
| 9019 | ir_add_alloca(ira, new_instruction, slice_type); | |
| 9020 | return slice_type; | |
| 9021 | } | |
| 9022 | case TypeTableEntryIdVar: | |
| 9023 | case TypeTableEntryIdMetaType: | |
| 9024 | case TypeTableEntryIdUnreachable: | |
| 9025 | case TypeTableEntryIdNumLitFloat: | |
| 9026 | case TypeTableEntryIdNumLitInt: | |
| 9027 | case TypeTableEntryIdUndefLit: | |
| 9028 | case TypeTableEntryIdNullLit: | |
| 9029 | case TypeTableEntryIdNamespace: | |
| 9030 | case TypeTableEntryIdBlock: | |
| 9031 | case TypeTableEntryIdBoundFn: | |
| 9032 | ir_add_error(ira, type_value, | |
| 9033 | buf_sprintf("invalid alloca type '%s'", buf_ptr(&child_type->name))); | |
| 9034 | // TODO if this is a typedecl, add error note showing the declaration of the type decl | |
| 9035 | return ira->codegen->builtin_types.entry_invalid; | |
| 9162 | if (type_requires_comptime(child_type)) { | |
| 9163 | ir_add_error(ira, type_value, | |
| 9164 | buf_sprintf("invalid alloca type '%s'", buf_ptr(&child_type->name))); | |
| 9165 | // TODO if this is a typedecl, add error note showing the declaration of the type decl | |
| 9166 | return ira->codegen->builtin_types.entry_invalid; | |
| 9167 | } else { | |
| 9168 | TypeTableEntry *slice_type = get_slice_type(ira->codegen, child_type, false); | |
| 9169 | IrInstruction *new_instruction = ir_build_alloca_from(&ira->new_irb, &instruction->base, type_value, count_value); | |
| 9170 | ir_add_alloca(ira, new_instruction, slice_type); | |
| 9171 | return slice_type; | |
| 9036 | 9172 | } |
| 9037 | 9173 | zig_unreachable(); |
| 9038 | 9174 | } |
| ... | ... | @@ -9804,6 +9940,7 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 9804 | 9940 | case IrInstructionIdStructFieldPtr: |
| 9805 | 9941 | case IrInstructionIdEnumFieldPtr: |
| 9806 | 9942 | case IrInstructionIdStructInit: |
| 9943 | case IrInstructionIdInitEnum: | |
| 9807 | 9944 | zig_panic("TODO analyze more instructions"); |
| 9808 | 9945 | } |
| 9809 | 9946 | zig_unreachable(); |
| ... | ... | @@ -9959,6 +10096,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 9959 | 10096 | case IrInstructionIdErrWrapPayload: |
| 9960 | 10097 | case IrInstructionIdFnProto: |
| 9961 | 10098 | case IrInstructionIdTestComptime: |
| 10099 | case IrInstructionIdInitEnum: | |
| 9962 | 10100 | return false; |
| 9963 | 10101 | case IrInstructionIdAsm: |
| 9964 | 10102 | { |
src/ir_print.cpp+16| ... | ... | @@ -183,6 +183,13 @@ static void ir_print_const_value(IrPrint *irp, TypeTableEntry *type_entry, Const |
| 183 | 183 | fprintf(irp->f, "(pure error constant)"); |
| 184 | 184 | return; |
| 185 | 185 | } |
| 186 | case TypeTableEntryIdEnumTag: | |
| 187 | { | |
| 188 | TypeTableEntry *enum_type = type_entry->data.enum_tag.enum_type; | |
| 189 | TypeEnumField *field = &enum_type->data.enumeration.fields[const_val->data.x_bignum.data.x_uint]; | |
| 190 | fprintf(irp->f, "%s.%s", buf_ptr(&enum_type->name), buf_ptr(field->name)); | |
| 191 | return; | |
| 192 | } | |
| 186 | 193 | } |
| 187 | 194 | zig_unreachable(); |
| 188 | 195 | } |
| ... | ... | @@ -911,6 +918,12 @@ static void ir_print_test_comptime(IrPrint *irp, IrInstructionTestComptime *inst |
| 911 | 918 | fprintf(irp->f, ")"); |
| 912 | 919 | } |
| 913 | 920 | |
| 921 | static void ir_print_init_enum(IrPrint *irp, IrInstructionInitEnum *instruction) { | |
| 922 | fprintf(irp->f, "%s.%s { ", buf_ptr(&instruction->enum_type->name), buf_ptr(instruction->field->name)); | |
| 923 | ir_print_other_instruction(irp, instruction->init_value); | |
| 924 | fprintf(irp->f, "{"); | |
| 925 | } | |
| 926 | ||
| 914 | 927 | static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 915 | 928 | ir_print_prefix(irp, instruction); |
| 916 | 929 | switch (instruction->id) { |
| ... | ... | @@ -1147,6 +1160,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1147 | 1160 | case IrInstructionIdTestComptime: |
| 1148 | 1161 | ir_print_test_comptime(irp, (IrInstructionTestComptime *)instruction); |
| 1149 | 1162 | break; |
| 1163 | case IrInstructionIdInitEnum: | |
| 1164 | ir_print_init_enum(irp, (IrInstructionInitEnum *)instruction); | |
| 1165 | break; | |
| 1150 | 1166 | } |
| 1151 | 1167 | fprintf(irp->f, "\n"); |
| 1152 | 1168 | } |
test/cases3/enum.zig created+37| ... | ... | @@ -0,0 +1,37 @@ |
| 1 | fn enumType() { | |
| 2 | @setFnTest(this); | |
| 3 | ||
| 4 | const foo1 = Foo.One {13}; | |
| 5 | const foo2 = Foo.Two { Point { .x = 1234, .y = 5678, }}; | |
| 6 | const bar = Bar.B; | |
| 7 | ||
| 8 | assert(bar == Bar.B); | |
| 9 | assert(@memberCount(Foo) == 3); | |
| 10 | assert(@memberCount(Bar) == 4); | |
| 11 | const expected_foo_size = 16 + @sizeOf(usize); | |
| 12 | assert(@sizeOf(Foo) == expected_foo_size); | |
| 13 | assert(@sizeOf(Bar) == 1); | |
| 14 | } | |
| 15 | const Point = struct { | |
| 16 | x: u64, | |
| 17 | y: u64, | |
| 18 | }; | |
| 19 | const Foo = enum { | |
| 20 | One: i32, | |
| 21 | Two: Point, | |
| 22 | Three: void, | |
| 23 | }; | |
| 24 | const Bar = enum { | |
| 25 | A, | |
| 26 | B, | |
| 27 | C, | |
| 28 | D, | |
| 29 | }; | |
| 30 | ||
| 31 | fn assert(ok: bool) { | |
| 32 | if (!ok) | |
| 33 | @unreachable(); | |
| 34 | } | |
| 35 | ||
| 36 | ||
| 37 |
test/self_hosted.zig-35| ... | ... | @@ -333,41 +333,6 @@ fn maybeType() { |
| 333 | 333 | } |
| 334 | 334 | |
| 335 | 335 | |
| 336 | fn enumType() { | |
| 337 | @setFnTest(this, true); | |
| 338 | ||
| 339 | const foo1 = EnumTypeFoo.One {13}; | |
| 340 | const foo2 = EnumTypeFoo.Two {EnumType { .x = 1234, .y = 5678, }}; | |
| 341 | const bar = EnumTypeBar.B; | |
| 342 | ||
| 343 | assert(bar == EnumTypeBar.B); | |
| 344 | assert(@memberCount(EnumTypeFoo) == 3); | |
| 345 | assert(@memberCount(EnumTypeBar) == 4); | |
| 346 | const expected_foo_size = switch (@compileVar("arch")) { | |
| 347 | i386 => 20, | |
| 348 | x86_64 => 24, | |
| 349 | else => @unreachable(), | |
| 350 | }; | |
| 351 | assert(@sizeOf(EnumTypeFoo) == expected_foo_size); | |
| 352 | assert(@sizeOf(EnumTypeBar) == 1); | |
| 353 | } | |
| 354 | struct EnumType { | |
| 355 | x: u64, | |
| 356 | y: u64, | |
| 357 | } | |
| 358 | enum EnumTypeFoo { | |
| 359 | One: i32, | |
| 360 | Two: EnumType, | |
| 361 | Three: void, | |
| 362 | } | |
| 363 | enum EnumTypeBar { | |
| 364 | A, | |
| 365 | B, | |
| 366 | C, | |
| 367 | D, | |
| 368 | } | |
| 369 | ||
| 370 | ||
| 371 | 336 | fn arrayLiteral() { |
| 372 | 337 | @setFnTest(this, true); |
| 373 | 338 |
test/self_hosted3.zig+1| ... | ... | @@ -8,3 +8,4 @@ const test_for = @import("cases3/for.zig"); |
| 8 | 8 | const test_math = @import("cases3/math.zig"); |
| 9 | 9 | const test_generics = @import("cases3/generics.zig"); |
| 10 | 10 | const test_defer = @import("cases3/defer.zig"); |
| 11 | const test_enum = @import("cases3/enum.zig"); |