authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-11-21 03:08:24-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-11-21 03:08:24-05:00
log71d95c6597bbca6ef44ba8a2a401c28c19a32bbb
tree01285870db232a793bb25ffbce594515d653fa6f
parentb47e2fa0604a5c785d9ed7d16c8086ecf99357f7

IR: support unwrap maybe operation


5 files changed, 317 insertions(+), 302 deletions(-)

src/all_types.hpp+20
......@@ -1453,6 +1453,8 @@ enum IrInstructionId {
14531453 IrInstructionIdAsm,
14541454 IrInstructionIdCompileVar,
14551455 IrInstructionIdSizeOf,
1456 IrInstructionIdTestNull,
1457 IrInstructionIdUnwrapMaybe,
14561458};
14571459
14581460struct IrInstruction {
......@@ -1749,6 +1751,21 @@ struct IrInstructionSizeOf {
17491751 IrInstruction *type_value;
17501752};
17511753
1754// returns true if nonnull, returns false if null
1755// this is so that `zeroes` sets maybe values to null
1756struct IrInstructionTestNull {
1757 IrInstruction base;
1758
1759 IrInstruction *value;
1760};
1761
1762struct IrInstructionUnwrapMaybe {
1763 IrInstruction base;
1764
1765 IrInstruction *value;
1766 bool safety_check_on;
1767};
1768
17521769enum LValPurpose {
17531770 LValPurposeNone,
17541771 LValPurposeAssign,
......@@ -1758,4 +1775,7 @@ enum LValPurpose {
17581775static const size_t slice_ptr_index = 0;
17591776static const size_t slice_len_index = 1;
17601777
1778static const size_t maybe_child_index = 0;
1779static const size_t maybe_null_index = 1;
1780
17611781#endif
src/ast_render.cpp+21-1
......@@ -706,6 +706,27 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
706706 fprintf(ar->f, "null");
707707 break;
708708 }
709 case NodeTypeIfVarExpr:
710 {
711 AstNodeVariableDeclaration *var_decl = &node->data.if_var_expr.var_decl;
712 const char *var_str = var_decl->is_const ? "const" : "var";
713 const char *var_name = buf_ptr(var_decl->symbol);
714 const char *ptr_str = node->data.if_var_expr.var_is_ptr ? "*" : "";
715 fprintf(ar->f, "if (%s %s%s", var_str, ptr_str, var_name);
716 if (var_decl->type) {
717 fprintf(ar->f, ": ");
718 render_node_ungrouped(ar, var_decl->type);
719 }
720 fprintf(ar->f, " = ");
721 render_node_grouped(ar, var_decl->expr);
722 fprintf(ar->f, ") ");
723 render_node_grouped(ar, node->data.if_var_expr.then_block);
724 if (node->data.if_var_expr.else_node) {
725 fprintf(ar->f, " else ");
726 render_node_grouped(ar, node->data.if_var_expr.else_node);
727 }
728 break;
729 }
709730 case NodeTypeFnDecl:
710731 case NodeTypeParamDecl:
711732 case NodeTypeErrorValueDecl:
......@@ -715,7 +736,6 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
715736 case NodeTypeStructValueField:
716737 case NodeTypeUse:
717738 case NodeTypeZeroesLiteral:
718 case NodeTypeIfVarExpr:
719739 case NodeTypeForExpr:
720740 case NodeTypeSwitchExpr:
721741 case NodeTypeSwitchProng:
src/codegen.cpp+53
......@@ -1427,7 +1427,56 @@ static LLVMValueRef ir_render_asm(CodeGen *g, IrExecutable *executable, IrInstru
14271427 return LLVMBuildCall(g->builder, asm_fn, param_values, input_and_output_count, "");
14281428}
14291429
1430// 0 - null, 1 - non null
1431static LLVMValueRef gen_null_bit(CodeGen *g, TypeTableEntry *ptr_type, LLVMValueRef maybe_ptr) {
1432 assert(ptr_type->id == TypeTableEntryIdPointer);
1433 TypeTableEntry *maybe_type = ptr_type->data.pointer.child_type;
1434 assert(maybe_type->id == TypeTableEntryIdMaybe);
1435 TypeTableEntry *child_type = maybe_type->data.maybe.child_type;
1436 LLVMValueRef maybe_struct_ref = get_handle_value(g, maybe_ptr, maybe_type);
1437 bool maybe_is_ptr = (child_type->id == TypeTableEntryIdPointer || child_type->id == TypeTableEntryIdFn);
1438 if (maybe_is_ptr) {
1439 return LLVMBuildICmp(g->builder, LLVMIntNE, maybe_struct_ref, LLVMConstNull(child_type->type_ref), "");
1440 } else {
1441 LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, maybe_struct_ref, maybe_null_index, "");
1442 return LLVMBuildLoad(g->builder, maybe_field_ptr, "");
1443 }
1444}
1445
1446static LLVMValueRef ir_render_test_null(CodeGen *g, IrExecutable *executable, IrInstructionTestNull *instruction) {
1447 TypeTableEntry *ptr_type = instruction->value->type_entry;
1448 assert(ptr_type->id == TypeTableEntryIdPointer);
1449 return gen_null_bit(g, ptr_type, ir_llvm_value(g, instruction->value));
1450}
1451
1452static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable,
1453 IrInstructionUnwrapMaybe *instruction)
1454{
1455 TypeTableEntry *ptr_type = instruction->value->type_entry;
1456 assert(ptr_type->id == TypeTableEntryIdPointer);
1457 TypeTableEntry *maybe_type = ptr_type->data.pointer.child_type;
1458 assert(maybe_type->id == TypeTableEntryIdMaybe);
1459 TypeTableEntry *child_type = maybe_type->data.maybe.child_type;
1460 bool maybe_is_ptr = (child_type->id == TypeTableEntryIdPointer || child_type->id == TypeTableEntryIdFn);
1461 LLVMValueRef maybe_ptr = ir_llvm_value(g, instruction->value);
1462 if (ir_want_debug_safety(g, &instruction->base) && instruction->safety_check_on) {
1463 LLVMValueRef nonnull_bit = gen_null_bit(g, ptr_type, maybe_ptr);
1464 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "UnwrapMaybeOk");
1465 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "UnwrapMaybeFail");
1466 LLVMBuildCondBr(g->builder, nonnull_bit, ok_block, fail_block);
14301467
1468 LLVMPositionBuilderAtEnd(g->builder, fail_block);
1469 gen_debug_safety_crash(g);
1470
1471 LLVMPositionBuilderAtEnd(g->builder, ok_block);
1472 }
1473 if (maybe_is_ptr) {
1474 return maybe_ptr;
1475 } else {
1476 LLVMValueRef maybe_struct_ref = get_handle_value(g, maybe_ptr, maybe_type);
1477 return LLVMBuildStructGEP(g->builder, maybe_struct_ref, maybe_child_index, "");
1478 }
1479}
14311480
14321481static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, IrInstruction *instruction) {
14331482 set_debug_source_node(g, instruction->source_node);
......@@ -1476,6 +1525,10 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
14761525 return ir_render_struct_field_ptr(g, executable, (IrInstructionStructFieldPtr *)instruction);
14771526 case IrInstructionIdAsm:
14781527 return ir_render_asm(g, executable, (IrInstructionAsm *)instruction);
1528 case IrInstructionIdTestNull:
1529 return ir_render_test_null(g, executable, (IrInstructionTestNull *)instruction);
1530 case IrInstructionIdUnwrapMaybe:
1531 return ir_render_unwrap_maybe(g, executable, (IrInstructionUnwrapMaybe *)instruction);
14791532 case IrInstructionIdSwitchBr:
14801533 case IrInstructionIdPhi:
14811534 case IrInstructionIdContainerInitList:
src/ir.cpp+203-301
......@@ -226,6 +226,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSizeOf *) {
226226 return IrInstructionIdSizeOf;
227227}
228228
229static constexpr IrInstructionId ir_instruction_id(IrInstructionTestNull *) {
230 return IrInstructionIdTestNull;
231}
232
233static constexpr IrInstructionId ir_instruction_id(IrInstructionUnwrapMaybe *) {
234 return IrInstructionIdUnwrapMaybe;
235}
236
229237template<typename T>
230238static T *ir_create_instruction(IrExecutable *exec, AstNode *source_node) {
231239 T *special_instruction = allocate<T>(1);
......@@ -878,6 +886,44 @@ static IrInstruction *ir_build_size_of(IrBuilder *irb, AstNode *source_node, IrI
878886 return &instruction->base;
879887}
880888
889static IrInstruction *ir_build_test_null(IrBuilder *irb, AstNode *source_node, IrInstruction *value) {
890 IrInstructionTestNull *instruction = ir_build_instruction<IrInstructionTestNull>(irb, source_node);
891 instruction->value = value;
892
893 ir_ref_instruction(value);
894
895 return &instruction->base;
896}
897
898static IrInstruction *ir_build_test_null_from(IrBuilder *irb, IrInstruction *old_instruction,
899 IrInstruction *value)
900{
901 IrInstruction *new_instruction = ir_build_test_null(irb, old_instruction->source_node, value);
902 ir_link_new_instruction(new_instruction, old_instruction);
903 return new_instruction;
904}
905
906static IrInstruction *ir_build_unwrap_maybe(IrBuilder *irb, AstNode *source_node, IrInstruction *value,
907 bool safety_check_on)
908{
909 IrInstructionUnwrapMaybe *instruction = ir_build_instruction<IrInstructionUnwrapMaybe>(irb, source_node);
910 instruction->value = value;
911 instruction->safety_check_on = safety_check_on;
912
913 ir_ref_instruction(value);
914
915 return &instruction->base;
916}
917
918static IrInstruction *ir_build_unwrap_maybe_from(IrBuilder *irb, IrInstruction *old_instruction,
919 IrInstruction *value, bool safety_check_on)
920{
921 IrInstruction *new_instruction = ir_build_unwrap_maybe(irb, old_instruction->source_node,
922 value, safety_check_on);
923 ir_link_new_instruction(new_instruction, old_instruction);
924 return new_instruction;
925}
926
881927static void ir_gen_defers_for_block(IrBuilder *irb, BlockContext *inner_block, BlockContext *outer_block,
882928 bool gen_error_defers, bool gen_maybe_defers)
883929{
......@@ -1164,7 +1210,6 @@ static IrInstruction *ir_gen_null_literal(IrBuilder *irb, AstNode *node) {
11641210 return ir_build_const_null(irb, node);
11651211}
11661212
1167
11681213static IrInstruction *ir_gen_decl_ref(IrBuilder *irb, AstNode *source_node, AstNode *decl_node,
11691214 LValPurpose lval, BlockContext *scope)
11701215{
......@@ -1502,6 +1547,15 @@ static IrInstruction *ir_gen_prefix_op_id(IrBuilder *irb, AstNode *node, IrUnOp
15021547 return ir_gen_prefix_op_id_lval(irb, node, op_id, LValPurposeNone);
15031548}
15041549
1550static IrInstruction *ir_gen_prefix_op_unwrap_maybe(IrBuilder *irb, AstNode *node) {
1551 AstNode *expr = node->data.prefix_op_expr.primary_expr;
1552 IrInstruction *value = ir_gen_node(irb, expr, node->block_context);
1553 if (value == irb->codegen->invalid_instruction)
1554 return value;
1555
1556 return ir_build_unwrap_maybe(irb, node, value, true);
1557}
1558
15051559static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, AstNode *node, LValPurpose lval) {
15061560 assert(node->type == NodeTypePrefixOpExpr);
15071561
......@@ -1531,7 +1585,7 @@ static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, AstNode *node, LValP
15311585 case PrefixOpUnwrapError:
15321586 return ir_gen_prefix_op_id(irb, node, IrUnOpUnwrapError);
15331587 case PrefixOpUnwrapMaybe:
1534 return ir_gen_prefix_op_id(irb, node, IrUnOpUnwrapMaybe);
1588 return ir_gen_prefix_op_unwrap_maybe(irb, node);
15351589 }
15361590 zig_unreachable();
15371591}
......@@ -1883,6 +1937,69 @@ static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, AstNode *node) {
18831937 return ir_build_asm(irb, node, input_list, output_types, return_count, is_volatile);
18841938}
18851939
1940static IrInstruction *ir_gen_if_var_expr(IrBuilder *irb, AstNode *node) {
1941 assert(node->type == NodeTypeIfVarExpr);
1942
1943 AstNodeVariableDeclaration *var_decl = &node->data.if_var_expr.var_decl;
1944 AstNode *expr_node = var_decl->expr;
1945 AstNode *then_node = node->data.if_var_expr.then_block;
1946 AstNode *else_node = node->data.if_var_expr.else_node;
1947 bool var_is_ptr = node->data.if_var_expr.var_is_ptr;
1948
1949 IrInstruction *expr_value = ir_gen_node_extra(irb, expr_node, node->block_context, LValPurposeAddressOf);
1950 if (expr_value == irb->codegen->invalid_instruction)
1951 return expr_value;
1952
1953 IrInstruction *is_nonnull_value = ir_build_test_null(irb, node, expr_value);
1954
1955 IrBasicBlock *then_block = ir_build_basic_block(irb, "MaybeThen");
1956 IrBasicBlock *else_block = ir_build_basic_block(irb, "MaybeElse");
1957 IrBasicBlock *endif_block = ir_build_basic_block(irb, "MaybeEndIf");
1958
1959 bool is_inline = (node->block_context->fn_entry == nullptr);
1960 ir_build_cond_br(irb, node, is_nonnull_value, then_block, else_block, is_inline);
1961
1962 ir_set_cursor_at_end(irb, then_block);
1963 IrInstruction *var_type = nullptr;
1964 if (var_decl->type)
1965 var_type = ir_gen_node(irb, var_decl->type, node->block_context);
1966 BlockContext *child_scope = new_block_context(node, node->block_context);
1967 bool is_shadowable = false;
1968 bool is_const = var_decl->is_const;
1969 VariableTableEntry *var = ir_add_local_var(irb, node, child_scope,
1970 var_decl->symbol, is_const, is_const, is_shadowable, is_inline);
1971 IrInstruction *var_ptr_value = ir_build_unwrap_maybe(irb, node, expr_value, false);
1972 IrInstruction *var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, node, var_ptr_value);
1973 ir_build_var_decl(irb, node, var, var_type, var_value);
1974 IrInstruction *then_expr_result = ir_gen_node(irb, then_node, child_scope);
1975 if (then_expr_result == irb->codegen->invalid_instruction)
1976 return then_expr_result;
1977 IrBasicBlock *after_then_block = irb->current_basic_block;
1978 ir_build_br(irb, node, endif_block, is_inline);
1979
1980 ir_set_cursor_at_end(irb, else_block);
1981 IrInstruction *else_expr_result;
1982 if (else_node) {
1983 else_expr_result = ir_gen_node(irb, else_node, node->block_context);
1984 if (else_expr_result == irb->codegen->invalid_instruction)
1985 return else_expr_result;
1986 } else {
1987 else_expr_result = ir_build_const_void(irb, node);
1988 }
1989 IrBasicBlock *after_else_block = irb->current_basic_block;
1990 ir_build_br(irb, node, endif_block, is_inline);
1991
1992 ir_set_cursor_at_end(irb, endif_block);
1993 IrInstruction **incoming_values = allocate<IrInstruction *>(2);
1994 incoming_values[0] = then_expr_result;
1995 incoming_values[1] = else_expr_result;
1996 IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2);
1997 incoming_blocks[0] = after_then_block;
1998 incoming_blocks[1] = after_else_block;
1999
2000 return ir_build_phi(irb, node, 2, incoming_blocks, incoming_values);
2001}
2002
18862003static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockContext *block_context,
18872004 LValPurpose lval)
18882005{
......@@ -1932,10 +2049,11 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockCont
19322049 return ir_gen_asm_expr(irb, node);
19332050 case NodeTypeNullLiteral:
19342051 return ir_gen_null_literal(irb, node);
2052 case NodeTypeIfVarExpr:
2053 return ir_gen_if_var_expr(irb, node);
19352054 case NodeTypeUnwrapErrorExpr:
19362055 case NodeTypeDefer:
19372056 case NodeTypeSliceExpr:
1938 case NodeTypeIfVarExpr:
19392057 case NodeTypeGoto:
19402058 case NodeTypeBreak:
19412059 case NodeTypeContinue:
......@@ -4488,6 +4606,82 @@ static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira,
44884606 zig_unreachable();
44894607}
44904608
4609static TypeTableEntry *ir_analyze_instruction_test_null(IrAnalyze *ira,
4610 IrInstructionTestNull *test_null_instruction)
4611{
4612 IrInstruction *value = test_null_instruction->value->other;
4613 if (value->type_entry->id == TypeTableEntryIdInvalid)
4614 return ira->codegen->builtin_types.entry_invalid;
4615
4616 // This will be a pointer type because test null IR instruction operates on a pointer to a thing.
4617 TypeTableEntry *ptr_type = value->type_entry;
4618 assert(ptr_type->id == TypeTableEntryIdPointer);
4619
4620 TypeTableEntry *type_entry = ptr_type->data.pointer.child_type;
4621 if (type_entry->id != TypeTableEntryIdMaybe) {
4622 add_node_error(ira->codegen, test_null_instruction->base.source_node,
4623 buf_sprintf("expected nullable type, found '%s'", buf_ptr(&type_entry->name)));
4624 return ira->codegen->builtin_types.entry_invalid;
4625 }
4626
4627 if (value->static_value.special != ConstValSpecialRuntime) {
4628 ConstExprValue *maybe_val = value->static_value.data.x_ptr.base_ptr;
4629 assert(value->static_value.data.x_ptr.index == SIZE_MAX);
4630
4631 if (maybe_val->special != ConstValSpecialRuntime) {
4632 bool depends_on_compile_var = maybe_val->depends_on_compile_var;
4633 ConstExprValue *out_val = ir_build_const_from(ira, &test_null_instruction->base,
4634 depends_on_compile_var);
4635 out_val->data.x_bool = (maybe_val->data.x_maybe == nullptr);
4636 return ira->codegen->builtin_types.entry_bool;
4637 }
4638 }
4639
4640 ir_build_test_null_from(&ira->new_irb, &test_null_instruction->base, value);
4641 return ira->codegen->builtin_types.entry_bool;
4642}
4643
4644static TypeTableEntry *ir_analyze_instruction_unwrap_maybe(IrAnalyze *ira,
4645 IrInstructionUnwrapMaybe *unwrap_maybe_instruction)
4646{
4647 IrInstruction *value = unwrap_maybe_instruction->value->other;
4648 if (value->type_entry->id == TypeTableEntryIdInvalid)
4649 return ira->codegen->builtin_types.entry_invalid;
4650
4651 // This will be a pointer type because test null IR instruction operates on a pointer to a thing.
4652 TypeTableEntry *ptr_type = value->type_entry;
4653 assert(ptr_type->id == TypeTableEntryIdPointer);
4654
4655 TypeTableEntry *type_entry = ptr_type->data.pointer.child_type;
4656 if (type_entry->id == TypeTableEntryIdInvalid) {
4657 return ira->codegen->builtin_types.entry_invalid;
4658 } else if (type_entry->id != TypeTableEntryIdMaybe) {
4659 add_node_error(ira->codegen, unwrap_maybe_instruction->base.source_node,
4660 buf_sprintf("expected nullable type, found '%s'", buf_ptr(&type_entry->name)));
4661 return ira->codegen->builtin_types.entry_invalid;
4662 }
4663 TypeTableEntry *child_type = type_entry->data.maybe.child_type;
4664 TypeTableEntry *result_type = get_pointer_to_type(ira->codegen, child_type, false);
4665
4666 if (value->static_value.special != ConstValSpecialRuntime) {
4667 ConstExprValue *maybe_val = value->static_value.data.x_ptr.base_ptr;
4668 assert(value->static_value.data.x_ptr.index == SIZE_MAX);
4669
4670 if (maybe_val->special != ConstValSpecialRuntime) {
4671 bool depends_on_compile_var = maybe_val->depends_on_compile_var;
4672 ConstExprValue *out_val = ir_build_const_from(ira, &unwrap_maybe_instruction->base,
4673 depends_on_compile_var);
4674 out_val->data.x_ptr.base_ptr = maybe_val;
4675 out_val->data.x_ptr.index = SIZE_MAX;
4676 return result_type;
4677 }
4678 }
4679
4680 ir_build_unwrap_maybe_from(&ira->new_irb, &unwrap_maybe_instruction->base, value,
4681 unwrap_maybe_instruction->safety_check_on);
4682 return result_type;
4683}
4684
44914685static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
44924686 switch (instruction->id) {
44934687 case IrInstructionIdInvalid:
......@@ -4544,6 +4738,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
45444738 return ir_analyze_instruction_compile_var(ira, (IrInstructionCompileVar *)instruction);
45454739 case IrInstructionIdSizeOf:
45464740 return ir_analyze_instruction_size_of(ira, (IrInstructionSizeOf *)instruction);
4741 case IrInstructionIdTestNull:
4742 return ir_analyze_instruction_test_null(ira, (IrInstructionTestNull *)instruction);
4743 case IrInstructionIdUnwrapMaybe:
4744 return ir_analyze_instruction_unwrap_maybe(ira, (IrInstructionUnwrapMaybe *)instruction);
45474745 case IrInstructionIdSwitchBr:
45484746 case IrInstructionIdCast:
45494747 case IrInstructionIdContainerInitList:
......@@ -4654,6 +4852,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
46544852 case IrInstructionIdSliceType:
46554853 case IrInstructionIdCompileVar:
46564854 case IrInstructionIdSizeOf:
4855 case IrInstructionIdTestNull:
4856 case IrInstructionIdUnwrapMaybe:
46574857 return false;
46584858 case IrInstructionIdAsm:
46594859 {
......@@ -6266,32 +6466,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) {
62666466// return result_type;
62676467//}
62686468//
6269//static TypeTableEntry *analyze_if_var_expr(CodeGen *g, ImportTableEntry *import, BlockContext *parent_context,
6270// TypeTableEntry *expected_type, AstNode *node)
6271//{
6272// assert(node->type == NodeTypeIfVarExpr);
6273//
6274// BlockContext *child_context = new_block_context(node, parent_context);
6275//
6276// analyze_variable_declaration_raw(g, import, child_context, node, &node->data.if_var_expr.var_decl, true,
6277// nullptr, node->data.if_var_expr.var_is_ptr);
6278// VariableTableEntry *var = node->data.if_var_expr.var_decl.variable;
6279// if (var->type->id == TypeTableEntryIdInvalid) {
6280// return g->builtin_types.entry_invalid;
6281// }
6282// AstNode *var_expr_node = node->data.if_var_expr.var_decl.expr;
6283// ConstExprValue *var_const_val = &get_resolved_expr(var_expr_node)->const_val;
6284// bool cond_is_const = var_const_val->ok;
6285// bool cond_bool_val = cond_is_const ? (var_const_val->data.x_maybe != nullptr) : false;
6286//
6287//
6288// AstNode **then_node = &node->data.if_var_expr.then_block;
6289// AstNode **else_node = &node->data.if_var_expr.else_node;
6290//
6291// return analyze_if(g, import, child_context, expected_type,
6292// node, then_node, else_node, cond_is_const, cond_bool_val);
6293//}
6294//
62956469//static TypeTableEntry *bad_method_call(CodeGen *g, AstNode *node, TypeTableEntry *container_type,
62966470// TypeTableEntry *expected_param_type, FnTableEntry *fn_table_entry)
62976471//{
......@@ -7407,92 +7581,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) {
74077581// }
74087582//}
74097583//
7410//
7411//static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTableEntry *import,
7412// BlockContext *context, AstNode *source_node,
7413// AstNodeVariableDeclaration *variable_declaration,
7414// bool expr_is_maybe, AstNode *decl_node, bool var_is_ptr)
7415//{
7416// bool is_const = variable_declaration->is_const;
7417// bool is_export = (variable_declaration->top_level_decl.visib_mod == VisibModExport);
7418// bool is_extern = variable_declaration->is_extern;
7419//
7420// TypeTableEntry *explicit_type = nullptr;
7421// if (variable_declaration->type != nullptr) {
7422// explicit_type = analyze_type_expr(g, import, context, variable_declaration->type);
7423// if (explicit_type->id == TypeTableEntryIdUnreachable) {
7424// add_node_error(g, variable_declaration->type,
7425// buf_sprintf("variable of type 'unreachable' not allowed"));
7426// explicit_type = g->builtin_types.entry_invalid;
7427// }
7428// }
7429//
7430// TypeTableEntry *implicit_type = nullptr;
7431// if (explicit_type && explicit_type->id == TypeTableEntryIdInvalid) {
7432// implicit_type = explicit_type;
7433// } else if (variable_declaration->expr) {
7434// implicit_type = analyze_expression(g, import, context, explicit_type, variable_declaration->expr);
7435// if (implicit_type->id == TypeTableEntryIdInvalid) {
7436// // ignore the poison value
7437// } else if (expr_is_maybe) {
7438// if (implicit_type->id == TypeTableEntryIdMaybe) {
7439// if (var_is_ptr) {
7440// // TODO if the expression is constant, can't get pointer to it
7441// implicit_type = get_pointer_to_type(g, implicit_type->data.maybe.child_type, false);
7442// } else {
7443// implicit_type = implicit_type->data.maybe.child_type;
7444// }
7445// } else {
7446// add_node_error(g, variable_declaration->expr, buf_sprintf("expected maybe type"));
7447// implicit_type = g->builtin_types.entry_invalid;
7448// }
7449// } else if (implicit_type->id == TypeTableEntryIdUnreachable) {
7450// add_node_error(g, source_node,
7451// buf_sprintf("variable initialization is unreachable"));
7452// implicit_type = g->builtin_types.entry_invalid;
7453// } else if ((!is_const || is_export) &&
7454// (implicit_type->id == TypeTableEntryIdNumLitFloat ||
7455// implicit_type->id == TypeTableEntryIdNumLitInt))
7456// {
7457// add_node_error(g, source_node, buf_sprintf("unable to infer variable type"));
7458// implicit_type = g->builtin_types.entry_invalid;
7459// } else if (implicit_type->id == TypeTableEntryIdMetaType && !is_const) {
7460// add_node_error(g, source_node, buf_sprintf("variable of type 'type' must be constant"));
7461// implicit_type = g->builtin_types.entry_invalid;
7462// }
7463// if (implicit_type->id != TypeTableEntryIdInvalid && !context->fn_entry) {
7464// ConstExprValue *const_val = &get_resolved_expr(variable_declaration->expr)->const_val;
7465// if (!const_val->ok) {
7466// add_node_error(g, first_executing_node(variable_declaration->expr),
7467// buf_sprintf("global variable initializer requires constant expression"));
7468// }
7469// }
7470// } else if (!is_extern) {
7471// add_node_error(g, source_node, buf_sprintf("variables must be initialized"));
7472// implicit_type = g->builtin_types.entry_invalid;
7473// }
7474//
7475// TypeTableEntry *type = explicit_type != nullptr ? explicit_type : implicit_type;
7476// assert(type != nullptr); // should have been caught by the parser
7477//
7478// VariableTableEntry *var = add_local_var(g, source_node, import, context,
7479// variable_declaration->symbol, type, is_const,
7480// expr_is_maybe ? nullptr : variable_declaration->expr);
7481//
7482// variable_declaration->variable = var;
7483//
7484// return var;
7485//}
7486//
7487//static VariableTableEntry *analyze_variable_declaration(CodeGen *g, ImportTableEntry *import,
7488// BlockContext *context, TypeTableEntry *expected_type, AstNode *node)
7489//{
7490// AstNodeVariableDeclaration *variable_declaration = &node->data.variable_declaration;
7491// return analyze_variable_declaration_raw(g, import, context, node, variable_declaration,
7492// false, nullptr, false);
7493//}
7494//
7495//
74967584//static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
74977585// TypeTableEntry *expected_type, AstNode *node)
74987586//{
......@@ -8581,64 +8669,6 @@ static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *no
85818669// return nullptr;
85828670//}
85838671//
8584//static LLVMValueRef gen_unwrap_maybe_expr(CodeGen *g, AstNode *node) {
8585// assert(node->type == NodeTypeBinOpExpr);
8586// assert(node->data.bin_op_expr.bin_op == BinOpTypeUnwrapMaybe);
8587//
8588// AstNode *op1_node = node->data.bin_op_expr.op1;
8589// AstNode *op2_node = node->data.bin_op_expr.op2;
8590//
8591// LLVMValueRef maybe_struct_ref = gen_expr(g, op1_node);
8592//
8593// TypeTableEntry *maybe_type = get_expr_type(op1_node);
8594// assert(maybe_type->id == TypeTableEntryIdMaybe);
8595// TypeTableEntry *child_type = maybe_type->data.maybe.child_type;
8596//
8597// LLVMValueRef cond_value;
8598// if (child_type->id == TypeTableEntryIdPointer ||
8599// child_type->id == TypeTableEntryIdFn)
8600// {
8601// cond_value = LLVMBuildICmp(g->builder, LLVMIntNE, maybe_struct_ref,
8602// LLVMConstNull(child_type->type_ref), "");
8603// } else {
8604// LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, maybe_struct_ref, 1, "");
8605// cond_value = LLVMBuildLoad(g->builder, maybe_field_ptr, "");
8606// }
8607//
8608// LLVMBasicBlockRef non_null_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeNonNull");
8609// LLVMBasicBlockRef null_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeNull");
8610// LLVMBasicBlockRef end_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeEnd");
8611//
8612// bool null_reachable = get_expr_type(op2_node)->id != TypeTableEntryIdUnreachable;
8613//
8614// LLVMBuildCondBr(g->builder, cond_value, non_null_block, null_block);
8615//
8616// LLVMPositionBuilderAtEnd(g->builder, non_null_block);
8617// LLVMValueRef non_null_result = gen_unwrap_maybe(g, op1_node, maybe_struct_ref);
8618// LLVMBuildBr(g->builder, end_block);
8619// LLVMBasicBlockRef post_non_null_result_block = LLVMGetInsertBlock(g->builder);
8620//
8621// LLVMPositionBuilderAtEnd(g->builder, null_block);
8622// LLVMValueRef null_result = gen_expr(g, op2_node);
8623// if (null_reachable) {
8624// LLVMBuildBr(g->builder, end_block);
8625// }
8626// LLVMBasicBlockRef post_null_result_block = LLVMGetInsertBlock(g->builder);
8627//
8628// LLVMPositionBuilderAtEnd(g->builder, end_block);
8629// if (null_reachable) {
8630// LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMTypeOf(non_null_result), "");
8631// LLVMValueRef incoming_values[2] = {non_null_result, null_result};
8632// LLVMBasicBlockRef incoming_blocks[2] = {post_non_null_result_block, post_null_result_block};
8633// LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2);
8634// return phi;
8635// } else {
8636// return non_null_result;
8637// }
8638//
8639// return nullptr;
8640//}
8641//
86428672//static LLVMValueRef gen_unwrap_err_expr(CodeGen *g, AstNode *node) {
86438673// assert(node->type == NodeTypeUnwrapErrorExpr);
86448674//
......@@ -8914,120 +8944,6 @@ static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *no
89148944// }
89158945//}
89168946//
8917//static LLVMValueRef gen_if_var_then_block(CodeGen *g, AstNode *node, VariableTableEntry *variable, bool maybe_is_ptr,
8918// LLVMValueRef init_val, TypeTableEntry *child_type, AstNode *then_node)
8919//{
8920// if (node->data.if_var_expr.var_is_ptr) {
8921// LLVMValueRef payload_ptr;
8922// if (maybe_is_ptr) {
8923// zig_panic("TODO");
8924// } else {
8925// payload_ptr = LLVMBuildStructGEP(g->builder, init_val, 0, "");
8926// }
8927// LLVMBuildStore(g->builder, payload_ptr, variable->value_ref);
8928// } else {
8929// LLVMValueRef payload_val;
8930// if (maybe_is_ptr) {
8931// payload_val = init_val;
8932// } else {
8933// LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, init_val, 0, "");
8934// payload_val = get_handle_value(g, payload_ptr, child_type);
8935// }
8936// gen_assign_raw(g, node, BinOpTypeAssign, variable->value_ref, payload_val,
8937// variable->type, child_type);
8938// }
8939// gen_var_debug_decl(g, variable);
8940//
8941// return gen_expr(g, then_node);
8942//}
8943//
8944//static LLVMValueRef gen_if_var_expr(CodeGen *g, AstNode *node) {
8945// assert(node->type == NodeTypeIfVarExpr);
8946// assert(node->data.if_var_expr.var_decl.expr);
8947//
8948// AstNodeVariableDeclaration *var_decl = &node->data.if_var_expr.var_decl;
8949// VariableTableEntry *variable = var_decl->variable;
8950//
8951// // test if value is the maybe state
8952// TypeTableEntry *expr_type = get_expr_type(var_decl->expr);
8953// TypeTableEntry *child_type = expr_type->data.maybe.child_type;
8954//
8955// LLVMValueRef init_val = gen_expr(g, var_decl->expr);
8956//
8957//
8958// AstNode *then_node = node->data.if_var_expr.then_block;
8959// AstNode *else_node = node->data.if_var_expr.else_node;
8960// bool maybe_is_ptr = child_type->id == TypeTableEntryIdPointer || child_type->id == TypeTableEntryIdFn;
8961//
8962// ConstExprValue *const_val = &get_resolved_expr(var_decl->expr)->const_val;
8963// if (const_val->ok) {
8964// if (const_val->data.x_maybe) {
8965// return gen_if_var_then_block(g, node, variable, maybe_is_ptr, init_val, child_type, then_node);
8966// } else {
8967// return gen_expr(g, else_node);
8968// }
8969// }
8970//
8971// LLVMValueRef cond_value;
8972// if (maybe_is_ptr) {
8973// cond_value = LLVMBuildICmp(g->builder, LLVMIntNE, init_val, LLVMConstNull(child_type->type_ref), "");
8974// } else {
8975// LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, init_val, 1, "");
8976// cond_value = LLVMBuildLoad(g->builder, maybe_field_ptr, "");
8977// }
8978//
8979// TypeTableEntry *then_type = get_expr_type(then_node);
8980// TypeTableEntry *else_type = get_expr_type(else_node);
8981//
8982// bool use_then_value = type_has_bits(then_type);
8983// bool use_else_value = type_has_bits(else_type);
8984//
8985// LLVMBasicBlockRef then_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeThen");
8986// LLVMBasicBlockRef else_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeElse");
8987//
8988// LLVMBasicBlockRef endif_block;
8989// bool then_endif_reachable = then_type->id != TypeTableEntryIdUnreachable;
8990// bool else_endif_reachable = else_type->id != TypeTableEntryIdUnreachable;
8991// if (then_endif_reachable || else_endif_reachable) {
8992// endif_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeEndIf");
8993// }
8994//
8995// LLVMBuildCondBr(g->builder, cond_value, then_block, else_block);
8996//
8997// LLVMPositionBuilderAtEnd(g->builder, then_block);
8998// LLVMValueRef then_expr_result = gen_if_var_then_block(g, node, variable, maybe_is_ptr, init_val, child_type, then_node);
8999//
9000// if (then_endif_reachable) {
9001// LLVMBuildBr(g->builder, endif_block);
9002// }
9003// LLVMBasicBlockRef after_then_block = LLVMGetInsertBlock(g->builder);
9004//
9005//
9006// LLVMPositionBuilderAtEnd(g->builder, else_block);
9007// LLVMValueRef else_expr_result = gen_expr(g, else_node);
9008// if (else_endif_reachable) {
9009// LLVMBuildBr(g->builder, endif_block);
9010// }
9011// LLVMBasicBlockRef after_else_block = LLVMGetInsertBlock(g->builder);
9012//
9013// if (then_endif_reachable || else_endif_reachable) {
9014// LLVMPositionBuilderAtEnd(g->builder, endif_block);
9015// if (use_then_value && use_else_value) {
9016// LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMTypeOf(then_expr_result), "");
9017// LLVMValueRef incoming_values[2] = {then_expr_result, else_expr_result};
9018// LLVMBasicBlockRef incoming_blocks[2] = {after_then_block, after_else_block};
9019// LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2);
9020// return phi;
9021// } else if (use_then_value) {
9022// return then_expr_result;
9023// } else if (use_else_value) {
9024// return else_expr_result;
9025// }
9026// }
9027//
9028// return nullptr;
9029//}
9030//
90318947//static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *implicit_return_type) {
90328948// assert(block_node->type == NodeTypeBlock);
90338949//
......@@ -9667,20 +9583,6 @@ static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *no
96679583// zig_unreachable();
96689584//}
96699585//
9670//static LLVMValueRef gen_unwrap_maybe(CodeGen *g, AstNode *node, LLVMValueRef maybe_struct_ref) {
9671// TypeTableEntry *type_entry = get_expr_type(node);
9672// assert(type_entry->id == TypeTableEntryIdMaybe);
9673// TypeTableEntry *child_type = type_entry->data.maybe.child_type;
9674// if (child_type->id == TypeTableEntryIdPointer ||
9675// child_type->id == TypeTableEntryIdFn)
9676// {
9677// return maybe_struct_ref;
9678// } else {
9679// LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, maybe_struct_ref, 0, "");
9680// return get_handle_value(g, maybe_field_ptr, child_type);
9681// }
9682//}
9683//
96849586//static size_t get_conditional_defer_count(BlockContext *inner_block, BlockContext *outer_block) {
96859587// size_t result = 0;
96869588// while (inner_block != outer_block) {
src/ir_print.cpp+20
......@@ -497,6 +497,20 @@ static void ir_print_size_of(IrPrint *irp, IrInstructionSizeOf *instruction) {
497497 fprintf(irp->f, ")");
498498}
499499
500static void ir_print_test_null(IrPrint *irp, IrInstructionTestNull *instruction) {
501 fprintf(irp->f, "*");
502 ir_print_other_instruction(irp, instruction->value);
503 fprintf(irp->f, " == null");
504}
505
506static void ir_print_unwrap_maybe(IrPrint *irp, IrInstructionUnwrapMaybe *instruction) {
507 fprintf(irp->f, "&??*");
508 ir_print_other_instruction(irp, instruction->value);
509 if (!instruction->safety_check_on) {
510 fprintf(irp->f, " // no safety");
511 }
512}
513
500514static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
501515 ir_print_prefix(irp, instruction);
502516 switch (instruction->id) {
......@@ -592,6 +606,12 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
592606 case IrInstructionIdSizeOf:
593607 ir_print_size_of(irp, (IrInstructionSizeOf *)instruction);
594608 break;
609 case IrInstructionIdTestNull:
610 ir_print_test_null(irp, (IrInstructionTestNull *)instruction);
611 break;
612 case IrInstructionIdUnwrapMaybe:
613 ir_print_unwrap_maybe(irp, (IrInstructionUnwrapMaybe *)instruction);
614 break;
595615 case IrInstructionIdSwitchBr:
596616 zig_panic("TODO print more IR instructions");
597617 }