| ... | ... | @@ -137,8 +137,13 @@ static LLVMValueRef find_or_create_string(CodeGen *g, Buf *str, bool c) { |
| 137 | 137 | |
| 138 | 138 | static TypeTableEntry *get_expr_type(AstNode *node) { |
| 139 | 139 | Expr *expr = get_resolved_expr(node); |
| 140 | | TypeTableEntry *cast_type = expr->implicit_cast.after_type; |
| 141 | | return cast_type ? cast_type : expr->type_entry; |
| 140 | if (expr->implicit_maybe_cast.after_type) { |
| 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 | 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 | 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 | 290 | static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) { |
| 241 | 291 | assert(node->type == NodeTypeFnCallExpr); |
| 242 | 292 | |
| ... | ... | @@ -253,6 +303,19 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) { |
| 253 | 303 | } else if (struct_type->id == TypeTableEntryIdPointer) { |
| 254 | 304 | assert(struct_type->data.pointer.child_type->id == TypeTableEntryIdStruct); |
| 255 | 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 | 319 | } else { |
| 257 | 320 | zig_unreachable(); |
| 258 | 321 | } |
| ... | ... | @@ -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 | 566 | static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node, bool is_lvalue) { |
| 513 | 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 | 600 | { |
| 547 | 601 | assert(!is_lvalue); |
| 548 | 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 | 604 | } else { |
| 551 | 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 | 1022 | static LLVMValueRef gen_struct_memcpy(CodeGen *g, AstNode *source_node, LLVMValueRef src, LLVMValueRef dest, |
| 969 | 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 | 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 | 1047 | LLVMValueRef target_ref, LLVMValueRef value, |
| 992 | 1048 | TypeTableEntry *op1_type, TypeTableEntry *op2_type) |
| 993 | 1049 | { |
| 994 | | if (op1_type->id == TypeTableEntryIdStruct) { |
| 995 | | assert(op2_type->id == TypeTableEntryIdStruct); |
| 1050 | if (op1_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 | 1057 | assert(op1_type == op2_type); |
| 997 | 1058 | assert(bin_op == BinOpTypeAssign); |
| 998 | 1059 | |
| ... | ... | @@ -1546,32 +1607,48 @@ static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVa |
| 1546 | 1607 | |
| 1547 | 1608 | if (var_decl->expr) { |
| 1548 | 1609 | *init_value = gen_expr(g, var_decl->expr); |
| 1549 | | } else { |
| 1550 | | *init_value = LLVMConstNull(variable->type->type_ref); |
| 1551 | 1610 | } |
| 1552 | 1611 | if (variable->type->id == TypeTableEntryIdVoid) { |
| 1553 | 1612 | return nullptr; |
| 1554 | 1613 | } else { |
| 1555 | | LLVMValueRef store_instr; |
| 1556 | | LLVMValueRef value; |
| 1557 | | if (unwrap_maybe) { |
| 1558 | | assert(var_decl->expr); |
| 1559 | | value = gen_unwrap_maybe(g, source_node, *init_value); |
| 1560 | | } else { |
| 1561 | | value = *init_value; |
| 1562 | | } |
| 1563 | | if ((variable->type->id == TypeTableEntryIdStruct || variable->type->id == TypeTableEntryIdMaybe) && |
| 1564 | | var_decl->expr) |
| 1565 | | { |
| 1566 | | store_instr = gen_struct_memcpy(g, source_node, value, variable->value_ref, variable->type); |
| 1567 | | } else { |
| 1614 | if (var_decl->expr) { |
| 1615 | TypeTableEntry *expr_type = get_expr_type(var_decl->expr); |
| 1616 | LLVMValueRef value; |
| 1617 | if (unwrap_maybe) { |
| 1618 | assert(var_decl->expr); |
| 1619 | assert(expr_type->id == TypeTableEntryIdMaybe); |
| 1620 | value = gen_unwrap_maybe(g, source_node, *init_value); |
| 1621 | expr_type = expr_type->data.maybe.child_type; |
| 1622 | } else { |
| 1623 | value = *init_value; |
| 1624 | } |
| 1625 | gen_assign_raw(g, var_decl->expr, BinOpTypeAssign, variable->value_ref, |
| 1626 | value, variable->type, expr_type); |
| 1627 | } else if (g->build_type != CodeGenBuildTypeRelease) { |
| 1628 | // memset uninitialized memory to 0xa |
| 1568 | 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 | 1648 | LLVMZigDILocation *debug_loc = LLVMZigGetDebugLoc(source_node->line + 1, source_node->column + 1, |
| 1573 | 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 | 1652 | return nullptr; |
| 1576 | 1653 | } |
| 1577 | 1654 | } |
| ... | ... | @@ -1644,6 +1721,17 @@ static LLVMValueRef gen_compiler_fn_type(CodeGen *g, AstNode *node) { |
| 1644 | 1721 | } else { |
| 1645 | 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 | 1735 | } else { |
| 1648 | 1736 | zig_unreachable(); |
| 1649 | 1737 | } |
| ... | ... | @@ -2112,6 +2200,7 @@ static void define_builtin_types(CodeGen *g) { |
| 2112 | 2200 | buf_resize(&entry->name, 0); |
| 2113 | 2201 | buf_appendf(&entry->name, "(%s literal)", num_lit_str(num_lit_kind)); |
| 2114 | 2202 | entry->data.num_lit.kind = num_lit_kind; |
| 2203 | entry->size_in_bits = num_lit_bit_count(num_lit_kind); |
| 2115 | 2204 | g->num_lit_types[i] = entry; |
| 2116 | 2205 | } |
| 2117 | 2206 | |
| ... | ... | @@ -2377,10 +2466,10 @@ static void define_builtin_fns(CodeGen *g) { |
| 2377 | 2466 | }; |
| 2378 | 2467 | LLVMTypeRef fn_type = LLVMFunctionType(LLVMVoidType(), param_types, 5, false); |
| 2379 | 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); |
| 2381 | | builtin_fn->fn_val = g->memcpy_fn_val; |
| 2382 | | assert(LLVMGetIntrinsicID(g->memcpy_fn_val)); |
| 2469 | builtin_fn->fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type); |
| 2470 | assert(LLVMGetIntrinsicID(builtin_fn->fn_val)); |
| 2383 | 2471 | |
| 2472 | g->memcpy_fn_val = builtin_fn->fn_val; |
| 2384 | 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 | 2495 | builtin_fn->fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type); |
| 2407 | 2496 | assert(LLVMGetIntrinsicID(builtin_fn->fn_val)); |
| 2408 | 2497 | |
| 2498 | g->memset_fn_val = builtin_fn->fn_val; |
| 2409 | 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 | 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 | 2755 | if (g->verbose) { |