| author | |
| committer | |
| log | ccc8e9f4c328cb29fa7f21101d8c20fd23e4942a |
| tree | d26d3a0b31e281352b8327924e7aae4ffd095307 |
| parent | 733830f8a5c7c1a3f24aaeda451114b839a7eba9 |
4 files changed, 243 insertions(+), 56 deletions(-)
src/all_types.hpp+4| ... | @@ -324,6 +324,7 @@ struct AstNodeFieldAccessExpr { | ... | @@ -324,6 +324,7 @@ struct AstNodeFieldAccessExpr { |
| 324 | TypeStructField *type_struct_field; | 324 | TypeStructField *type_struct_field; |
| 325 | TypeEnumField *type_enum_field; | 325 | TypeEnumField *type_enum_field; |
| 326 | Expr resolved_expr; | 326 | Expr resolved_expr; |
| 327 | StructValExprCodeGen resolved_struct_val_expr; // for enum values | ||
| 327 | }; | 328 | }; |
| 328 | 329 | ||
| 329 | struct AstNodeExternBlock { | 330 | struct AstNodeExternBlock { |
| ... | @@ -718,8 +719,10 @@ struct TypeTableEntryMetaType { | ... | @@ -718,8 +719,10 @@ struct TypeTableEntryMetaType { |
| 718 | struct TypeTableEntryEnum { | 719 | struct TypeTableEntryEnum { |
| 719 | AstNode *decl_node; | 720 | AstNode *decl_node; |
| 720 | uint32_t field_count; | 721 | uint32_t field_count; |
| 722 | uint32_t gen_field_count; | ||
| 721 | TypeEnumField *fields; | 723 | TypeEnumField *fields; |
| 722 | bool is_invalid; // true if any fields are invalid | 724 | bool is_invalid; // true if any fields are invalid |
| 725 | TypeTableEntry *tag_type; | ||
| 723 | 726 | ||
| 724 | // reminder: hash tables must be initialized before use | 727 | // reminder: hash tables must be initialized before use |
| 725 | HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table; | 728 | HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table; |
| ... | @@ -916,6 +919,7 @@ struct CodeGen { | ... | @@ -916,6 +919,7 @@ struct CodeGen { |
| 916 | ImportTableEntry *root_import; | 919 | ImportTableEntry *root_import; |
| 917 | ImportTableEntry *bootstrap_import; | 920 | ImportTableEntry *bootstrap_import; |
| 918 | LLVMValueRef memcpy_fn_val; | 921 | LLVMValueRef memcpy_fn_val; |
| 922 | LLVMValueRef memset_fn_val; | ||
| 919 | bool error_during_imports; | 923 | bool error_during_imports; |
| 920 | }; | 924 | }; |
| 921 | 925 |
src/analyze.cpp+62-18| ... | @@ -465,6 +465,8 @@ static TypeTableEntry *eval_const_expr(CodeGen *g, BlockContext *context, | ... | @@ -465,6 +465,8 @@ static TypeTableEntry *eval_const_expr(CodeGen *g, BlockContext *context, |
| 465 | zig_panic("TODO eval_const_expr max_value"); | 465 | zig_panic("TODO eval_const_expr max_value"); |
| 466 | } else if (buf_eql_str(name, "min_value")) { | 466 | } else if (buf_eql_str(name, "min_value")) { |
| 467 | zig_panic("TODO eval_const_expr min_value"); | 467 | zig_panic("TODO eval_const_expr min_value"); |
| 468 | } else if (buf_eql_str(name, "value_count")) { | ||
| 469 | zig_panic("TODO eval_const_expr value_count"); | ||
| 468 | } else { | 470 | } else { |
| 469 | return g->builtin_types.entry_invalid; | 471 | return g->builtin_types.entry_invalid; |
| 470 | } | 472 | } |
| ... | @@ -767,10 +769,13 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt | ... | @@ -767,10 +769,13 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt |
| 767 | enum_type->data.enumeration.embedded_in_current = false; | 769 | enum_type->data.enumeration.embedded_in_current = false; |
| 768 | 770 | ||
| 769 | if (!enum_type->data.enumeration.is_invalid) { | 771 | if (!enum_type->data.enumeration.is_invalid) { |
| 770 | uint64_t tag_size_in_bits = get_number_literal_type_unsigned(g, field_count)->size_in_bits; | 772 | enum_type->data.enumeration.gen_field_count = gen_field_index; |
| 773 | |||
| 774 | uint64_t tag_size_in_bits = num_lit_bit_count(get_number_literal_kind_unsigned(field_count)); | ||
| 771 | enum_type->align_in_bits = tag_size_in_bits; | 775 | enum_type->align_in_bits = tag_size_in_bits; |
| 772 | enum_type->size_in_bits = tag_size_in_bits + biggest_union_member_size_in_bits; | 776 | enum_type->size_in_bits = tag_size_in_bits + biggest_union_member_size_in_bits; |
| 773 | TypeTableEntry *tag_type_entry = get_int_type_unsigned(g, field_count); | 777 | TypeTableEntry *tag_type_entry = get_int_type_unsigned(g, field_count); |
| 778 | enum_type->data.enumeration.tag_type = tag_type_entry; | ||
| 774 | 779 | ||
| 775 | if (biggest_union_member) { | 780 | if (biggest_union_member) { |
| 776 | // create llvm type for union | 781 | // create llvm type for union |
| ... | @@ -1520,22 +1525,20 @@ static TypeStructField *get_struct_field(TypeTableEntry *struct_type, Buf *name) | ... | @@ -1520,22 +1525,20 @@ static TypeStructField *get_struct_field(TypeTableEntry *struct_type, Buf *name) |
| 1520 | static TypeTableEntry *analyze_enum_value_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 1525 | static TypeTableEntry *analyze_enum_value_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 1521 | AstNode *field_access_node, AstNode *value_node, TypeTableEntry *enum_type, Buf *field_name) | 1526 | AstNode *field_access_node, AstNode *value_node, TypeTableEntry *enum_type, Buf *field_name) |
| 1522 | { | 1527 | { |
| 1528 | assert(field_access_node->type == NodeTypeFieldAccessExpr); | ||
| 1529 | |||
| 1523 | TypeEnumField *type_enum_field = get_enum_field(enum_type, field_name); | 1530 | TypeEnumField *type_enum_field = get_enum_field(enum_type, field_name); |
| 1524 | field_access_node->data.field_access_expr.type_enum_field = type_enum_field; | 1531 | field_access_node->data.field_access_expr.type_enum_field = type_enum_field; |
| 1532 | |||
| 1525 | if (type_enum_field) { | 1533 | if (type_enum_field) { |
| 1526 | if (value_node) { | 1534 | if (value_node) { |
| 1527 | if (type_enum_field->type_entry->id == TypeTableEntryIdVoid) { | 1535 | analyze_expression(g, import, context, type_enum_field->type_entry, value_node); |
| 1528 | add_node_error(g, field_access_node, | ||
| 1529 | buf_sprintf("enum value '%s.%s' has void parameter", | ||
| 1530 | buf_ptr(&enum_type->name), | ||
| 1531 | buf_ptr(field_name))); | ||
| 1532 | 1536 | ||
| 1533 | } else { | 1537 | StructValExprCodeGen *codegen = &field_access_node->data.field_access_expr.resolved_struct_val_expr; |
| 1534 | analyze_expression(g, import, context, type_enum_field->type_entry, value_node); | 1538 | codegen->type_entry = enum_type; |
| 1535 | } | 1539 | codegen->source_node = field_access_node; |
| 1536 | } else if (type_enum_field->type_entry->id == TypeTableEntryIdVoid) { | 1540 | context->struct_val_expr_alloca_list.append(codegen); |
| 1537 | // OK | 1541 | } else if (type_enum_field->type_entry->id != TypeTableEntryIdVoid) { |
| 1538 | } else { | ||
| 1539 | add_node_error(g, field_access_node, | 1542 | add_node_error(g, field_access_node, |
| 1540 | buf_sprintf("enum value '%s.%s' requires parameter of type '%s'", | 1543 | buf_sprintf("enum value '%s.%s' requires parameter of type '%s'", |
| 1541 | buf_ptr(&enum_type->name), | 1544 | buf_ptr(&enum_type->name), |
| ... | @@ -2295,7 +2298,8 @@ static TypeTableEntry *analyze_min_max_value(CodeGen *g, AstNode *node, TypeTabl | ... | @@ -2295,7 +2298,8 @@ static TypeTableEntry *analyze_min_max_value(CodeGen *g, AstNode *node, TypeTabl |
| 2295 | { | 2298 | { |
| 2296 | if (type_entry->id == TypeTableEntryIdInt || | 2299 | if (type_entry->id == TypeTableEntryIdInt || |
| 2297 | type_entry->id == TypeTableEntryIdFloat || | 2300 | type_entry->id == TypeTableEntryIdFloat || |
| 2298 | type_entry->id == TypeTableEntryIdBool) | 2301 | type_entry->id == TypeTableEntryIdBool || |
| 2302 | type_entry->id == TypeTableEntryIdInvalid) | ||
| 2299 | { | 2303 | { |
| 2300 | return type_entry; | 2304 | return type_entry; |
| 2301 | } else { | 2305 | } else { |
| ... | @@ -2314,15 +2318,38 @@ static TypeTableEntry *analyze_compiler_fn_type(CodeGen *g, ImportTableEntry *im | ... | @@ -2314,15 +2318,38 @@ static TypeTableEntry *analyze_compiler_fn_type(CodeGen *g, ImportTableEntry *im |
| 2314 | TypeTableEntry *type_entry = resolve_type(g, node->data.compiler_fn_type.type, import, context, false); | 2318 | TypeTableEntry *type_entry = resolve_type(g, node->data.compiler_fn_type.type, import, context, false); |
| 2315 | 2319 | ||
| 2316 | if (buf_eql_str(name, "sizeof")) { | 2320 | if (buf_eql_str(name, "sizeof")) { |
| 2317 | uint64_t size_in_bytes = type_entry->size_in_bits / 8; | 2321 | if (type_entry->id == TypeTableEntryIdInvalid) { |
| 2322 | return type_entry; | ||
| 2323 | } else if (type_entry->id == TypeTableEntryIdUnreachable) { | ||
| 2324 | add_node_error(g, node, | ||
| 2325 | buf_sprintf("no size available for type '%s'", buf_ptr(&type_entry->name))); | ||
| 2326 | return g->builtin_types.entry_invalid; | ||
| 2327 | } else { | ||
| 2328 | uint64_t size_in_bytes = type_entry->size_in_bits / 8; | ||
| 2318 | 2329 | ||
| 2319 | TypeTableEntry *num_lit_type = get_number_literal_type_unsigned(g, size_in_bytes); | 2330 | TypeTableEntry *num_lit_type = get_number_literal_type_unsigned(g, size_in_bytes); |
| 2320 | TypeTableEntry *resolved_type = resolve_rhs_number_literal(g, nullptr, expected_type, node, num_lit_type); | 2331 | TypeTableEntry *resolved_type = resolve_rhs_number_literal(g, nullptr, expected_type, node, num_lit_type); |
| 2321 | return resolved_type ? resolved_type : num_lit_type; | 2332 | return resolved_type ? resolved_type : num_lit_type; |
| 2333 | } | ||
| 2322 | } else if (buf_eql_str(name, "min_value")) { | 2334 | } else if (buf_eql_str(name, "min_value")) { |
| 2323 | return analyze_min_max_value(g, node, type_entry, "no min value available for type '%s'"); | 2335 | return analyze_min_max_value(g, node, type_entry, "no min value available for type '%s'"); |
| 2324 | } else if (buf_eql_str(name, "max_value")) { | 2336 | } else if (buf_eql_str(name, "max_value")) { |
| 2325 | return analyze_min_max_value(g, node, type_entry, "no max value available for type '%s'"); | 2337 | return analyze_min_max_value(g, node, type_entry, "no max value available for type '%s'"); |
| 2338 | } else if (buf_eql_str(name, "value_count")) { | ||
| 2339 | if (type_entry->id == TypeTableEntryIdInvalid) { | ||
| 2340 | return type_entry; | ||
| 2341 | } else if (type_entry->id == TypeTableEntryIdEnum) { | ||
| 2342 | uint64_t value_count = type_entry->data.enumeration.field_count; | ||
| 2343 | |||
| 2344 | TypeTableEntry *num_lit_type = get_number_literal_type_unsigned(g, value_count); | ||
| 2345 | TypeTableEntry *resolved_type = resolve_rhs_number_literal(g, nullptr, expected_type, node, num_lit_type); | ||
| 2346 | return resolved_type ? resolved_type : num_lit_type; | ||
| 2347 | |||
| 2348 | } else { | ||
| 2349 | add_node_error(g, node, | ||
| 2350 | buf_sprintf("no value count available for type '%s'", buf_ptr(&type_entry->name))); | ||
| 2351 | return g->builtin_types.entry_invalid; | ||
| 2352 | } | ||
| 2326 | } else { | 2353 | } else { |
| 2327 | add_node_error(g, node, | 2354 | add_node_error(g, node, |
| 2328 | buf_sprintf("invalid compiler function: '%s'", buf_ptr(name))); | 2355 | buf_sprintf("invalid compiler function: '%s'", buf_ptr(name))); |
| ... | @@ -2451,7 +2478,24 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import | ... | @@ -2451,7 +2478,24 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import |
| 2451 | } else if (struct_type->id == TypeTableEntryIdMetaType && | 2478 | } else if (struct_type->id == TypeTableEntryIdMetaType && |
| 2452 | struct_type->data.meta_type.child_type->id == TypeTableEntryIdEnum) | 2479 | struct_type->data.meta_type.child_type->id == TypeTableEntryIdEnum) |
| 2453 | { | 2480 | { |
| 2454 | zig_panic("TODO enum initialization"); | 2481 | TypeTableEntry *enum_type = struct_type->data.meta_type.child_type; |
| 2482 | Buf *field_name = &fn_ref_expr->data.field_access_expr.field_name; | ||
| 2483 | int param_count = node->data.fn_call_expr.params.length; | ||
| 2484 | if (param_count > 1) { | ||
| 2485 | add_node_error(g, first_executing_node(node->data.fn_call_expr.params.at(1)), | ||
| 2486 | buf_sprintf("enum values accept only one parameter")); | ||
| 2487 | return enum_type; | ||
| 2488 | } else { | ||
| 2489 | AstNode *value_node; | ||
| 2490 | if (param_count == 1) { | ||
| 2491 | value_node = node->data.fn_call_expr.params.at(0); | ||
| 2492 | } else { | ||
| 2493 | value_node = nullptr; | ||
| 2494 | } | ||
| 2495 | |||
| 2496 | return analyze_enum_value_expr(g, import, context, fn_ref_expr, value_node, | ||
| 2497 | enum_type, field_name); | ||
| 2498 | } | ||
| 2455 | } else { | 2499 | } else { |
| 2456 | add_node_error(g, fn_ref_expr->data.field_access_expr.struct_expr, | 2500 | add_node_error(g, fn_ref_expr->data.field_access_expr.struct_expr, |
| 2457 | buf_sprintf("member reference base type not struct or enum")); | 2501 | buf_sprintf("member reference base type not struct or enum")); |
src/codegen.cpp+127-36| ... | @@ -137,8 +137,13 @@ static LLVMValueRef find_or_create_string(CodeGen *g, Buf *str, bool c) { | ... | @@ -137,8 +137,13 @@ static LLVMValueRef find_or_create_string(CodeGen *g, Buf *str, bool c) { |
| 137 | 137 | ||
| 138 | static TypeTableEntry *get_expr_type(AstNode *node) { | 138 | static TypeTableEntry *get_expr_type(AstNode *node) { |
| 139 | Expr *expr = get_resolved_expr(node); | 139 | Expr *expr = get_resolved_expr(node); |
| 140 | TypeTableEntry *cast_type = expr->implicit_cast.after_type; | 140 | if (expr->implicit_maybe_cast.after_type) { |
| 141 | return cast_type ? cast_type : expr->type_entry; | 141 | return expr->implicit_maybe_cast.after_type; |
| 142 | } | ||
| 143 | if (expr->implicit_cast.after_type) { | ||
| 144 | return expr->implicit_cast.after_type; | ||
| 145 | } | ||
| 146 | return expr->type_entry; | ||
| 142 | } | 147 | } |
| 143 | 148 | ||
| 144 | static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) { | 149 | static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) { |
| ... | @@ -237,6 +242,51 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) { | ... | @@ -237,6 +242,51 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) { |
| 237 | zig_unreachable(); | 242 | zig_unreachable(); |
| 238 | } | 243 | } |
| 239 | 244 | ||
| 245 | static LLVMValueRef gen_enum_value_expr(CodeGen *g, AstNode *node, TypeTableEntry *enum_type, | ||
| 246 | AstNode *arg_node) | ||
| 247 | { | ||
| 248 | assert(node->type == NodeTypeFieldAccessExpr); | ||
| 249 | |||
| 250 | uint64_t value = node->data.field_access_expr.type_enum_field->value; | ||
| 251 | LLVMTypeRef tag_type_ref = enum_type->data.enumeration.tag_type->type_ref; | ||
| 252 | LLVMValueRef tag_value = LLVMConstInt(tag_type_ref, value, false); | ||
| 253 | |||
| 254 | if (enum_type->data.enumeration.gen_field_count == 0) { | ||
| 255 | return tag_value; | ||
| 256 | } else { | ||
| 257 | TypeTableEntry *arg_node_type = nullptr; | ||
| 258 | LLVMValueRef new_union_val = gen_expr(g, arg_node); | ||
| 259 | if (arg_node) { | ||
| 260 | arg_node_type = get_expr_type(arg_node); | ||
| 261 | new_union_val = gen_expr(g, arg_node); | ||
| 262 | } else { | ||
| 263 | arg_node_type = g->builtin_types.entry_void; | ||
| 264 | } | ||
| 265 | |||
| 266 | LLVMValueRef tmp_struct_ptr = node->data.field_access_expr.resolved_struct_val_expr.ptr; | ||
| 267 | |||
| 268 | // populate the new tag value | ||
| 269 | add_debug_source_node(g, node); | ||
| 270 | LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, 0, ""); | ||
| 271 | LLVMBuildStore(g->builder, tag_value, tag_field_ptr); | ||
| 272 | |||
| 273 | if (arg_node_type->id != TypeTableEntryIdVoid) { | ||
| 274 | // populate the union value | ||
| 275 | TypeTableEntry *union_val_type = get_expr_type(arg_node); | ||
| 276 | LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, 1, ""); | ||
| 277 | LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr, | ||
| 278 | LLVMPointerType(union_val_type->type_ref, 0), ""); | ||
| 279 | |||
| 280 | gen_assign_raw(g, arg_node, BinOpTypeAssign, bitcasted_union_field_ptr, new_union_val, | ||
| 281 | union_val_type, union_val_type); | ||
| 282 | |||
| 283 | } | ||
| 284 | |||
| 285 | return tmp_struct_ptr; | ||
| 286 | } | ||
| 287 | } | ||
| 288 | |||
| 289 | |||
| 240 | static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) { | 290 | static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) { |
| 241 | assert(node->type == NodeTypeFnCallExpr); | 291 | assert(node->type == NodeTypeFnCallExpr); |
| 242 | 292 | ||
| ... | @@ -253,6 +303,19 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) { | ... | @@ -253,6 +303,19 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) { |
| 253 | } else if (struct_type->id == TypeTableEntryIdPointer) { | 303 | } else if (struct_type->id == TypeTableEntryIdPointer) { |
| 254 | assert(struct_type->data.pointer.child_type->id == TypeTableEntryIdStruct); | 304 | assert(struct_type->data.pointer.child_type->id == TypeTableEntryIdStruct); |
| 255 | fn_table_entry = struct_type->data.pointer.child_type->data.structure.fn_table.get(name); | 305 | fn_table_entry = struct_type->data.pointer.child_type->data.structure.fn_table.get(name); |
| 306 | } else if (struct_type->id == TypeTableEntryIdMetaType && | ||
| 307 | struct_type->data.meta_type.child_type->id == TypeTableEntryIdEnum) | ||
| 308 | { | ||
| 309 | TypeTableEntry *enum_type = struct_type->data.meta_type.child_type; | ||
| 310 | int param_count = node->data.fn_call_expr.params.length; | ||
| 311 | AstNode *arg1_node; | ||
| 312 | if (param_count == 1) { | ||
| 313 | arg1_node = node->data.fn_call_expr.params.at(0); | ||
| 314 | } else { | ||
| 315 | assert(param_count == 0); | ||
| 316 | arg1_node = nullptr; | ||
| 317 | } | ||
| 318 | return gen_enum_value_expr(g, fn_ref_expr, enum_type, arg1_node); | ||
| 256 | } else { | 319 | } else { |
| 257 | zig_unreachable(); | 320 | zig_unreachable(); |
| 258 | } | 321 | } |
| ... | @@ -500,15 +563,6 @@ static LLVMValueRef gen_array_access_expr(CodeGen *g, AstNode *node, bool is_lva | ... | @@ -500,15 +563,6 @@ static LLVMValueRef gen_array_access_expr(CodeGen *g, AstNode *node, bool is_lva |
| 500 | } | 563 | } |
| 501 | } | 564 | } |
| 502 | 565 | ||
| 503 | static LLVMValueRef gen_enum_value_expr(CodeGen *g, AstNode *node, TypeTableEntry *enum_type) { | ||
| 504 | assert(node->type == NodeTypeFieldAccessExpr); | ||
| 505 | |||
| 506 | uint64_t value = node->data.field_access_expr.type_enum_field->value; | ||
| 507 | LLVMTypeRef tag_type_ref = enum_type->type_ref; | ||
| 508 | |||
| 509 | return LLVMConstInt(tag_type_ref, value, false); | ||
| 510 | } | ||
| 511 | |||
| 512 | static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node, bool is_lvalue) { | 566 | static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node, bool is_lvalue) { |
| 513 | assert(node->type == NodeTypeFieldAccessExpr); | 567 | assert(node->type == NodeTypeFieldAccessExpr); |
| 514 | 568 | ||
| ... | @@ -546,7 +600,7 @@ static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node, bool is_lva | ... | @@ -546,7 +600,7 @@ static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node, bool is_lva |
| 546 | { | 600 | { |
| 547 | assert(!is_lvalue); | 601 | assert(!is_lvalue); |
| 548 | TypeTableEntry *enum_type = struct_type->data.meta_type.child_type; | 602 | TypeTableEntry *enum_type = struct_type->data.meta_type.child_type; |
| 549 | return gen_enum_value_expr(g, node, enum_type); | 603 | return gen_enum_value_expr(g, node, enum_type, nullptr); |
| 550 | } else { | 604 | } else { |
| 551 | zig_panic("gen_field_access_expr bad struct type"); | 605 | zig_panic("gen_field_access_expr bad struct type"); |
| 552 | } | 606 | } |
| ... | @@ -968,7 +1022,9 @@ static LLVMValueRef gen_bool_or_expr(CodeGen *g, AstNode *expr_node) { | ... | @@ -968,7 +1022,9 @@ static LLVMValueRef gen_bool_or_expr(CodeGen *g, AstNode *expr_node) { |
| 968 | static LLVMValueRef gen_struct_memcpy(CodeGen *g, AstNode *source_node, LLVMValueRef src, LLVMValueRef dest, | 1022 | static LLVMValueRef gen_struct_memcpy(CodeGen *g, AstNode *source_node, LLVMValueRef src, LLVMValueRef dest, |
| 969 | TypeTableEntry *type_entry) | 1023 | TypeTableEntry *type_entry) |
| 970 | { | 1024 | { |
| 971 | assert(type_entry->id == TypeTableEntryIdStruct || type_entry->id == TypeTableEntryIdMaybe); | 1025 | assert(type_entry->id == TypeTableEntryIdStruct || |
| 1026 | type_entry->id == TypeTableEntryIdMaybe || | ||
| 1027 | (type_entry->id == TypeTableEntryIdEnum && type_entry->data.enumeration.gen_field_count != 0)); | ||
| 972 | 1028 | ||
| 973 | LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0); | 1029 | LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0); |
| 974 | 1030 | ||
| ... | @@ -991,8 +1047,13 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, AstNode *source_node, BinOpType b | ... | @@ -991,8 +1047,13 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, AstNode *source_node, BinOpType b |
| 991 | LLVMValueRef target_ref, LLVMValueRef value, | 1047 | LLVMValueRef target_ref, LLVMValueRef value, |
| 992 | TypeTableEntry *op1_type, TypeTableEntry *op2_type) | 1048 | TypeTableEntry *op1_type, TypeTableEntry *op2_type) |
| 993 | { | 1049 | { |
| 994 | if (op1_type->id == TypeTableEntryIdStruct) { | 1050 | if (op1_type->id == TypeTableEntryIdStruct || |
| 995 | assert(op2_type->id == TypeTableEntryIdStruct); | 1051 | (op1_type->id == TypeTableEntryIdEnum && op1_type->data.enumeration.gen_field_count != 0) || |
| 1052 | op1_type->id == TypeTableEntryIdMaybe) | ||
| 1053 | { | ||
| 1054 | assert(op2_type->id == TypeTableEntryIdStruct || | ||
| 1055 | (op2_type->id == TypeTableEntryIdEnum && op2_type->data.enumeration.gen_field_count != 0) || | ||
| 1056 | op2_type->id == TypeTableEntryIdMaybe); | ||
| 996 | assert(op1_type == op2_type); | 1057 | assert(op1_type == op2_type); |
| 997 | assert(bin_op == BinOpTypeAssign); | 1058 | assert(bin_op == BinOpTypeAssign); |
| 998 | 1059 | ||
| ... | @@ -1546,32 +1607,48 @@ static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVa | ... | @@ -1546,32 +1607,48 @@ static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVa |
| 1546 | 1607 | ||
| 1547 | if (var_decl->expr) { | 1608 | if (var_decl->expr) { |
| 1548 | *init_value = gen_expr(g, var_decl->expr); | 1609 | *init_value = gen_expr(g, var_decl->expr); |
| 1549 | } else { | ||
| 1550 | *init_value = LLVMConstNull(variable->type->type_ref); | ||
| 1551 | } | 1610 | } |
| 1552 | if (variable->type->id == TypeTableEntryIdVoid) { | 1611 | if (variable->type->id == TypeTableEntryIdVoid) { |
| 1553 | return nullptr; | 1612 | return nullptr; |
| 1554 | } else { | 1613 | } else { |
| 1555 | LLVMValueRef store_instr; | 1614 | if (var_decl->expr) { |
| 1556 | LLVMValueRef value; | 1615 | TypeTableEntry *expr_type = get_expr_type(var_decl->expr); |
| 1557 | if (unwrap_maybe) { | 1616 | LLVMValueRef value; |
| 1558 | assert(var_decl->expr); | 1617 | if (unwrap_maybe) { |
| 1559 | value = gen_unwrap_maybe(g, source_node, *init_value); | 1618 | assert(var_decl->expr); |
| 1560 | } else { | 1619 | assert(expr_type->id == TypeTableEntryIdMaybe); |
| 1561 | value = *init_value; | 1620 | value = gen_unwrap_maybe(g, source_node, *init_value); |
| 1562 | } | 1621 | expr_type = expr_type->data.maybe.child_type; |
| 1563 | if ((variable->type->id == TypeTableEntryIdStruct || variable->type->id == TypeTableEntryIdMaybe) && | 1622 | } else { |
| 1564 | var_decl->expr) | 1623 | value = *init_value; |
| 1565 | { | 1624 | } |
| 1566 | store_instr = gen_struct_memcpy(g, source_node, value, variable->value_ref, variable->type); | 1625 | gen_assign_raw(g, var_decl->expr, BinOpTypeAssign, variable->value_ref, |
| 1567 | } else { | 1626 | value, variable->type, expr_type); |
| 1627 | } else if (g->build_type != CodeGenBuildTypeRelease) { | ||
| 1628 | // memset uninitialized memory to 0xa | ||
| 1568 | add_debug_source_node(g, source_node); | 1629 | add_debug_source_node(g, source_node); |
| 1569 | store_instr = LLVMBuildStore(g->builder, value, variable->value_ref); | 1630 | LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0); |
| 1631 | LLVMValueRef fill_char = LLVMConstInt(LLVMInt8Type(), 0xaa, false); | ||
| 1632 | LLVMValueRef dest_ptr = LLVMBuildBitCast(g->builder, variable->value_ref, ptr_u8, ""); | ||
| 1633 | LLVMValueRef byte_count = LLVMConstInt(LLVMIntType(g->pointer_size_bytes * 8), | ||
| 1634 | variable->type->size_in_bits / 8, false); | ||
| 1635 | LLVMValueRef align_in_bytes = LLVMConstInt(LLVMInt32Type(), | ||
| 1636 | variable->type->align_in_bits / 8, false); | ||
| 1637 | LLVMValueRef params[] = { | ||
| 1638 | dest_ptr, | ||
| 1639 | fill_char, | ||
| 1640 | byte_count, | ||
| 1641 | align_in_bytes, | ||
| 1642 | LLVMConstNull(LLVMInt1Type()), // is volatile | ||
| 1643 | }; | ||
| 1644 | |||
| 1645 | LLVMBuildCall(g->builder, g->memset_fn_val, params, 5, ""); | ||
| 1570 | } | 1646 | } |
| 1571 | 1647 | ||
| 1572 | LLVMZigDILocation *debug_loc = LLVMZigGetDebugLoc(source_node->line + 1, source_node->column + 1, | 1648 | LLVMZigDILocation *debug_loc = LLVMZigGetDebugLoc(source_node->line + 1, source_node->column + 1, |
| 1573 | g->cur_block_context->di_scope); | 1649 | g->cur_block_context->di_scope); |
| 1574 | LLVMZigInsertDeclare(g->dbuilder, variable->value_ref, variable->di_loc_var, debug_loc, store_instr); | 1650 | LLVMZigInsertDeclareAtEnd(g->dbuilder, variable->value_ref, variable->di_loc_var, debug_loc, |
| 1651 | LLVMGetInsertBlock(g->builder)); | ||
| 1575 | return nullptr; | 1652 | return nullptr; |
| 1576 | } | 1653 | } |
| 1577 | } | 1654 | } |
| ... | @@ -1644,6 +1721,17 @@ static LLVMValueRef gen_compiler_fn_type(CodeGen *g, AstNode *node) { | ... | @@ -1644,6 +1721,17 @@ static LLVMValueRef gen_compiler_fn_type(CodeGen *g, AstNode *node) { |
| 1644 | } else { | 1721 | } else { |
| 1645 | zig_unreachable(); | 1722 | zig_unreachable(); |
| 1646 | } | 1723 | } |
| 1724 | } else if (buf_eql_str(name, "value_count")) { | ||
| 1725 | if (type_entry->id == TypeTableEntryIdEnum) { | ||
| 1726 | NumLitCodeGen *codegen_num_lit = get_resolved_num_lit(node); | ||
| 1727 | AstNodeNumberLiteral num_lit_node; | ||
| 1728 | num_lit_node.kind = type_entry->data.num_lit.kind; | ||
| 1729 | num_lit_node.overflow = false; | ||
| 1730 | num_lit_node.data.x_uint = type_entry->data.enumeration.field_count; | ||
| 1731 | return gen_number_literal_raw(g, node, codegen_num_lit, &num_lit_node); | ||
| 1732 | } else { | ||
| 1733 | zig_unreachable(); | ||
| 1734 | } | ||
| 1647 | } else { | 1735 | } else { |
| 1648 | zig_unreachable(); | 1736 | zig_unreachable(); |
| 1649 | } | 1737 | } |
| ... | @@ -2112,6 +2200,7 @@ static void define_builtin_types(CodeGen *g) { | ... | @@ -2112,6 +2200,7 @@ static void define_builtin_types(CodeGen *g) { |
| 2112 | buf_resize(&entry->name, 0); | 2200 | buf_resize(&entry->name, 0); |
| 2113 | buf_appendf(&entry->name, "(%s literal)", num_lit_str(num_lit_kind)); | 2201 | buf_appendf(&entry->name, "(%s literal)", num_lit_str(num_lit_kind)); |
| 2114 | entry->data.num_lit.kind = num_lit_kind; | 2202 | entry->data.num_lit.kind = num_lit_kind; |
| 2203 | entry->size_in_bits = num_lit_bit_count(num_lit_kind); | ||
| 2115 | g->num_lit_types[i] = entry; | 2204 | g->num_lit_types[i] = entry; |
| 2116 | } | 2205 | } |
| 2117 | 2206 | ||
| ... | @@ -2377,10 +2466,10 @@ static void define_builtin_fns(CodeGen *g) { | ... | @@ -2377,10 +2466,10 @@ static void define_builtin_fns(CodeGen *g) { |
| 2377 | }; | 2466 | }; |
| 2378 | LLVMTypeRef fn_type = LLVMFunctionType(LLVMVoidType(), param_types, 5, false); | 2467 | LLVMTypeRef fn_type = LLVMFunctionType(LLVMVoidType(), param_types, 5, false); |
| 2379 | Buf *name = buf_sprintf("llvm.memcpy.p0i8.p0i8.i%d", g->pointer_size_bytes * 8); | 2468 | Buf *name = buf_sprintf("llvm.memcpy.p0i8.p0i8.i%d", g->pointer_size_bytes * 8); |
| 2380 | g->memcpy_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type); | 2469 | builtin_fn->fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type); |
| 2381 | builtin_fn->fn_val = g->memcpy_fn_val; | 2470 | assert(LLVMGetIntrinsicID(builtin_fn->fn_val)); |
| 2382 | assert(LLVMGetIntrinsicID(g->memcpy_fn_val)); | ||
| 2383 | 2471 | ||
| 2472 | g->memcpy_fn_val = builtin_fn->fn_val; | ||
| 2384 | g->builtin_fn_table.put(&builtin_fn->name, builtin_fn); | 2473 | g->builtin_fn_table.put(&builtin_fn->name, builtin_fn); |
| 2385 | } | 2474 | } |
| 2386 | { | 2475 | { |
| ... | @@ -2406,6 +2495,7 @@ static void define_builtin_fns(CodeGen *g) { | ... | @@ -2406,6 +2495,7 @@ static void define_builtin_fns(CodeGen *g) { |
| 2406 | builtin_fn->fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type); | 2495 | builtin_fn->fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type); |
| 2407 | assert(LLVMGetIntrinsicID(builtin_fn->fn_val)); | 2496 | assert(LLVMGetIntrinsicID(builtin_fn->fn_val)); |
| 2408 | 2497 | ||
| 2498 | g->memset_fn_val = builtin_fn->fn_val; | ||
| 2409 | g->builtin_fn_table.put(&builtin_fn->name, builtin_fn); | 2499 | g->builtin_fn_table.put(&builtin_fn->name, builtin_fn); |
| 2410 | } | 2500 | } |
| 2411 | } | 2501 | } |
| ... | @@ -2658,7 +2748,8 @@ void codegen_add_root_code(CodeGen *g, Buf *src_dir, Buf *src_basename, Buf *sou | ... | @@ -2658,7 +2748,8 @@ void codegen_add_root_code(CodeGen *g, Buf *src_dir, Buf *src_basename, Buf *sou |
| 2658 | g->bootstrap_import = add_special_code(g, "bootstrap.zig"); | 2748 | g->bootstrap_import = add_special_code(g, "bootstrap.zig"); |
| 2659 | } | 2749 | } |
| 2660 | 2750 | ||
| 2661 | add_special_code(g, "builtin.zig"); | 2751 | // TODO re-enable this |
| 2752 | //add_special_code(g, "builtin.zig"); | ||
| 2662 | } | 2753 | } |
| 2663 | 2754 | ||
| 2664 | if (g->verbose) { | 2755 | if (g->verbose) { |
test/run_tests.cpp+50-2| ... | @@ -355,7 +355,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | ... | @@ -355,7 +355,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { |
| 355 | use "std.zig"; | 355 | use "std.zig"; |
| 356 | 356 | ||
| 357 | pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | 357 | pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { |
| 358 | var zero : i32; | 358 | var zero : i32 = 0; |
| 359 | if (zero == 0) { print_str("zero\n"); } | 359 | if (zero == 0) { print_str("zero\n"); } |
| 360 | 360 | ||
| 361 | var i = 0 as i32; | 361 | var i = 0 as i32; |
| ... | @@ -619,6 +619,7 @@ use "std.zig"; | ... | @@ -619,6 +619,7 @@ use "std.zig"; |
| 619 | 619 | ||
| 620 | pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { | 620 | pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { |
| 621 | var foo : Foo; | 621 | var foo : Foo; |
| 622 | @memset(&foo, 0, #sizeof(Foo)); | ||
| 622 | foo.a += 1; | 623 | foo.a += 1; |
| 623 | foo.b = foo.a == 1; | 624 | foo.b = foo.a == 1; |
| 624 | test_foo(foo); | 625 | test_foo(foo); |
| ... | @@ -689,7 +690,7 @@ fn test_initializer() { | ... | @@ -689,7 +690,7 @@ fn test_initializer() { |
| 689 | use "std.zig"; | 690 | use "std.zig"; |
| 690 | 691 | ||
| 691 | const g1 : i32 = 1233 + 1; | 692 | const g1 : i32 = 1233 + 1; |
| 692 | var g2 : i32; | 693 | var g2 : i32 = 0; |
| 693 | 694 | ||
| 694 | pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { | 695 | pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { |
| 695 | if (g2 != 0) { print_str("BAD\n"); } | 696 | if (g2 != 0) { print_str("BAD\n"); } |
| ... | @@ -1044,6 +1045,53 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | ... | @@ -1044,6 +1045,53 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { |
| 1044 | return 0; | 1045 | return 0; |
| 1045 | } | 1046 | } |
| 1046 | )SOURCE", "OK\n"); | 1047 | )SOURCE", "OK\n"); |
| 1048 | |||
| 1049 | add_simple_case("enum type", R"SOURCE( | ||
| 1050 | use "std.zig"; | ||
| 1051 | |||
| 1052 | struct Point { | ||
| 1053 | x: u64, | ||
| 1054 | y: u64, | ||
| 1055 | } | ||
| 1056 | |||
| 1057 | enum Foo { | ||
| 1058 | One: i32, | ||
| 1059 | Two: Point, | ||
| 1060 | Three: void, | ||
| 1061 | } | ||
| 1062 | |||
| 1063 | enum Bar { | ||
| 1064 | A, | ||
| 1065 | B, | ||
| 1066 | C, | ||
| 1067 | D, | ||
| 1068 | } | ||
| 1069 | |||
| 1070 | pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | ||
| 1071 | const foo1 = Foo.One(13); | ||
| 1072 | const foo2 = Foo.Two(Point { .x = 1234, .y = 5678, }); | ||
| 1073 | const bar = Bar.A; | ||
| 1074 | |||
| 1075 | if (#value_count(Foo) != 3) { | ||
| 1076 | print_str("BAD\n"); | ||
| 1077 | } | ||
| 1078 | |||
| 1079 | if (#value_count(Bar) != 4) { | ||
| 1080 | print_str("BAD\n"); | ||
| 1081 | } | ||
| 1082 | |||
| 1083 | if (#sizeof(Foo) != 17) { | ||
| 1084 | print_str("BAD\n"); | ||
| 1085 | } | ||
| 1086 | if (#sizeof(Bar) != 1) { | ||
| 1087 | print_str("BAD\n"); | ||
| 1088 | } | ||
| 1089 | |||
| 1090 | print_str("OK\n"); | ||
| 1091 | |||
| 1092 | return 0; | ||
| 1093 | } | ||
| 1094 | )SOURCE", "OK\n"); | ||
| 1047 | } | 1095 | } |
| 1048 | 1096 | ||
| 1049 | 1097 |