IR: support unwrap maybe operation

This commit is contained in:
Andrew Kelley 2016-11-21 03:08:24 -05:00
parent b47e2fa060
commit 71d95c6597
5 changed files with 317 additions and 302 deletions

View File

@ -1453,6 +1453,8 @@ enum IrInstructionId {
IrInstructionIdAsm,
IrInstructionIdCompileVar,
IrInstructionIdSizeOf,
IrInstructionIdTestNull,
IrInstructionIdUnwrapMaybe,
};
struct IrInstruction {
@ -1749,6 +1751,21 @@ struct IrInstructionSizeOf {
IrInstruction *type_value;
};
// returns true if nonnull, returns false if null
// this is so that `zeroes` sets maybe values to null
struct IrInstructionTestNull {
IrInstruction base;
IrInstruction *value;
};
struct IrInstructionUnwrapMaybe {
IrInstruction base;
IrInstruction *value;
bool safety_check_on;
};
enum LValPurpose {
LValPurposeNone,
LValPurposeAssign,
@ -1758,4 +1775,7 @@ enum LValPurpose {
static const size_t slice_ptr_index = 0;
static const size_t slice_len_index = 1;
static const size_t maybe_child_index = 0;
static const size_t maybe_null_index = 1;
#endif

View File

@ -706,6 +706,27 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
fprintf(ar->f, "null");
break;
}
case NodeTypeIfVarExpr:
{
AstNodeVariableDeclaration *var_decl = &node->data.if_var_expr.var_decl;
const char *var_str = var_decl->is_const ? "const" : "var";
const char *var_name = buf_ptr(var_decl->symbol);
const char *ptr_str = node->data.if_var_expr.var_is_ptr ? "*" : "";
fprintf(ar->f, "if (%s %s%s", var_str, ptr_str, var_name);
if (var_decl->type) {
fprintf(ar->f, ": ");
render_node_ungrouped(ar, var_decl->type);
}
fprintf(ar->f, " = ");
render_node_grouped(ar, var_decl->expr);
fprintf(ar->f, ") ");
render_node_grouped(ar, node->data.if_var_expr.then_block);
if (node->data.if_var_expr.else_node) {
fprintf(ar->f, " else ");
render_node_grouped(ar, node->data.if_var_expr.else_node);
}
break;
}
case NodeTypeFnDecl:
case NodeTypeParamDecl:
case NodeTypeErrorValueDecl:
@ -715,7 +736,6 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
case NodeTypeStructValueField:
case NodeTypeUse:
case NodeTypeZeroesLiteral:
case NodeTypeIfVarExpr:
case NodeTypeForExpr:
case NodeTypeSwitchExpr:
case NodeTypeSwitchProng:

View File

@ -1427,7 +1427,56 @@ static LLVMValueRef ir_render_asm(CodeGen *g, IrExecutable *executable, IrInstru
return LLVMBuildCall(g->builder, asm_fn, param_values, input_and_output_count, "");
}
// 0 - null, 1 - non null
static LLVMValueRef gen_null_bit(CodeGen *g, TypeTableEntry *ptr_type, LLVMValueRef maybe_ptr) {
assert(ptr_type->id == TypeTableEntryIdPointer);
TypeTableEntry *maybe_type = ptr_type->data.pointer.child_type;
assert(maybe_type->id == TypeTableEntryIdMaybe);
TypeTableEntry *child_type = maybe_type->data.maybe.child_type;
LLVMValueRef maybe_struct_ref = get_handle_value(g, maybe_ptr, maybe_type);
bool maybe_is_ptr = (child_type->id == TypeTableEntryIdPointer || child_type->id == TypeTableEntryIdFn);
if (maybe_is_ptr) {
return LLVMBuildICmp(g->builder, LLVMIntNE, maybe_struct_ref, LLVMConstNull(child_type->type_ref), "");
} else {
LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, maybe_struct_ref, maybe_null_index, "");
return LLVMBuildLoad(g->builder, maybe_field_ptr, "");
}
}
static LLVMValueRef ir_render_test_null(CodeGen *g, IrExecutable *executable, IrInstructionTestNull *instruction) {
TypeTableEntry *ptr_type = instruction->value->type_entry;
assert(ptr_type->id == TypeTableEntryIdPointer);
return gen_null_bit(g, ptr_type, ir_llvm_value(g, instruction->value));
}
static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable,
IrInstructionUnwrapMaybe *instruction)
{
TypeTableEntry *ptr_type = instruction->value->type_entry;
assert(ptr_type->id == TypeTableEntryIdPointer);
TypeTableEntry *maybe_type = ptr_type->data.pointer.child_type;
assert(maybe_type->id == TypeTableEntryIdMaybe);
TypeTableEntry *child_type = maybe_type->data.maybe.child_type;
bool maybe_is_ptr = (child_type->id == TypeTableEntryIdPointer || child_type->id == TypeTableEntryIdFn);
LLVMValueRef maybe_ptr = ir_llvm_value(g, instruction->value);
if (ir_want_debug_safety(g, &instruction->base) && instruction->safety_check_on) {
LLVMValueRef nonnull_bit = gen_null_bit(g, ptr_type, maybe_ptr);
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "UnwrapMaybeOk");
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "UnwrapMaybeFail");
LLVMBuildCondBr(g->builder, nonnull_bit, ok_block, fail_block);
LLVMPositionBuilderAtEnd(g->builder, fail_block);
gen_debug_safety_crash(g);
LLVMPositionBuilderAtEnd(g->builder, ok_block);
}
if (maybe_is_ptr) {
return maybe_ptr;
} else {
LLVMValueRef maybe_struct_ref = get_handle_value(g, maybe_ptr, maybe_type);
return LLVMBuildStructGEP(g->builder, maybe_struct_ref, maybe_child_index, "");
}
}
static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, IrInstruction *instruction) {
set_debug_source_node(g, instruction->source_node);
@ -1476,6 +1525,10 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_struct_field_ptr(g, executable, (IrInstructionStructFieldPtr *)instruction);
case IrInstructionIdAsm:
return ir_render_asm(g, executable, (IrInstructionAsm *)instruction);
case IrInstructionIdTestNull:
return ir_render_test_null(g, executable, (IrInstructionTestNull *)instruction);
case IrInstructionIdUnwrapMaybe:
return ir_render_unwrap_maybe(g, executable, (IrInstructionUnwrapMaybe *)instruction);
case IrInstructionIdSwitchBr:
case IrInstructionIdPhi:
case IrInstructionIdContainerInitList:

View File

@ -226,6 +226,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSizeOf *) {
return IrInstructionIdSizeOf;
}
static constexpr IrInstructionId ir_instruction_id(IrInstructionTestNull *) {
return IrInstructionIdTestNull;
}
static constexpr IrInstructionId ir_instruction_id(IrInstructionUnwrapMaybe *) {
return IrInstructionIdUnwrapMaybe;
}
template<typename T>
static T *ir_create_instruction(IrExecutable *exec, AstNode *source_node) {
T *special_instruction = allocate<T>(1);
@ -878,6 +886,44 @@ static IrInstruction *ir_build_size_of(IrBuilder *irb, AstNode *source_node, IrI
return &instruction->base;
}
static IrInstruction *ir_build_test_null(IrBuilder *irb, AstNode *source_node, IrInstruction *value) {
IrInstructionTestNull *instruction = ir_build_instruction<IrInstructionTestNull>(irb, source_node);
instruction->value = value;
ir_ref_instruction(value);
return &instruction->base;
}
static IrInstruction *ir_build_test_null_from(IrBuilder *irb, IrInstruction *old_instruction,
IrInstruction *value)
{
IrInstruction *new_instruction = ir_build_test_null(irb, old_instruction->source_node, value);
ir_link_new_instruction(new_instruction, old_instruction);
return new_instruction;
}
static IrInstruction *ir_build_unwrap_maybe(IrBuilder *irb, AstNode *source_node, IrInstruction *value,
bool safety_check_on)
{
IrInstructionUnwrapMaybe *instruction = ir_build_instruction<IrInstructionUnwrapMaybe>(irb, source_node);
instruction->value = value;
instruction->safety_check_on = safety_check_on;
ir_ref_instruction(value);
return &instruction->base;
}
static IrInstruction *ir_build_unwrap_maybe_from(IrBuilder *irb, IrInstruction *old_instruction,
IrInstruction *value, bool safety_check_on)
{
IrInstruction *new_instruction = ir_build_unwrap_maybe(irb, old_instruction->source_node,
value, safety_check_on);
ir_link_new_instruction(new_instruction, old_instruction);
return new_instruction;
}
static void ir_gen_defers_for_block(IrBuilder *irb, BlockContext *inner_block, BlockContext *outer_block,
bool gen_error_defers, bool gen_maybe_defers)
{
@ -1164,7 +1210,6 @@ static IrInstruction *ir_gen_null_literal(IrBuilder *irb, AstNode *node) {
return ir_build_const_null(irb, node);
}
static IrInstruction *ir_gen_decl_ref(IrBuilder *irb, AstNode *source_node, AstNode *decl_node,
LValPurpose lval, BlockContext *scope)
{
@ -1502,6 +1547,15 @@ static IrInstruction *ir_gen_prefix_op_id(IrBuilder *irb, AstNode *node, IrUnOp
return ir_gen_prefix_op_id_lval(irb, node, op_id, LValPurposeNone);
}
static IrInstruction *ir_gen_prefix_op_unwrap_maybe(IrBuilder *irb, AstNode *node) {
AstNode *expr = node->data.prefix_op_expr.primary_expr;
IrInstruction *value = ir_gen_node(irb, expr, node->block_context);
if (value == irb->codegen->invalid_instruction)
return value;
return ir_build_unwrap_maybe(irb, node, value, true);
}
static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, AstNode *node, LValPurpose lval) {
assert(node->type == NodeTypePrefixOpExpr);
@ -1531,7 +1585,7 @@ static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, AstNode *node, LValP
case PrefixOpUnwrapError:
return ir_gen_prefix_op_id(irb, node, IrUnOpUnwrapError);
case PrefixOpUnwrapMaybe:
return ir_gen_prefix_op_id(irb, node, IrUnOpUnwrapMaybe);
return ir_gen_prefix_op_unwrap_maybe(irb, node);
}
zig_unreachable();
}
@ -1883,6 +1937,69 @@ static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, AstNode *node) {
return ir_build_asm(irb, node, input_list, output_types, return_count, is_volatile);
}
static IrInstruction *ir_gen_if_var_expr(IrBuilder *irb, AstNode *node) {
assert(node->type == NodeTypeIfVarExpr);
AstNodeVariableDeclaration *var_decl = &node->data.if_var_expr.var_decl;
AstNode *expr_node = var_decl->expr;
AstNode *then_node = node->data.if_var_expr.then_block;
AstNode *else_node = node->data.if_var_expr.else_node;
bool var_is_ptr = node->data.if_var_expr.var_is_ptr;
IrInstruction *expr_value = ir_gen_node_extra(irb, expr_node, node->block_context, LValPurposeAddressOf);
if (expr_value == irb->codegen->invalid_instruction)
return expr_value;
IrInstruction *is_nonnull_value = ir_build_test_null(irb, node, expr_value);
IrBasicBlock *then_block = ir_build_basic_block(irb, "MaybeThen");
IrBasicBlock *else_block = ir_build_basic_block(irb, "MaybeElse");
IrBasicBlock *endif_block = ir_build_basic_block(irb, "MaybeEndIf");
bool is_inline = (node->block_context->fn_entry == nullptr);
ir_build_cond_br(irb, node, is_nonnull_value, then_block, else_block, is_inline);
ir_set_cursor_at_end(irb, then_block);
IrInstruction *var_type = nullptr;
if (var_decl->type)
var_type = ir_gen_node(irb, var_decl->type, node->block_context);
BlockContext *child_scope = new_block_context(node, node->block_context);
bool is_shadowable = false;
bool is_const = var_decl->is_const;
VariableTableEntry *var = ir_add_local_var(irb, node, child_scope,
var_decl->symbol, is_const, is_const, is_shadowable, is_inline);
IrInstruction *var_ptr_value = ir_build_unwrap_maybe(irb, node, expr_value, false);
IrInstruction *var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, node, var_ptr_value);
ir_build_var_decl(irb, node, var, var_type, var_value);
IrInstruction *then_expr_result = ir_gen_node(irb, then_node, child_scope);
if (then_expr_result == irb->codegen->invalid_instruction)
return then_expr_result;
IrBasicBlock *after_then_block = irb->current_basic_block;
ir_build_br(irb, node, endif_block, is_inline);
ir_set_cursor_at_end(irb, else_block);
IrInstruction *else_expr_result;
if (else_node) {
else_expr_result = ir_gen_node(irb, else_node, node->block_context);
if (else_expr_result == irb->codegen->invalid_instruction)
return else_expr_result;
} else {
else_expr_result = ir_build_const_void(irb, node);
}
IrBasicBlock *after_else_block = irb->current_basic_block;
ir_build_br(irb, node, endif_block, is_inline);
ir_set_cursor_at_end(irb, endif_block);
IrInstruction **incoming_values = allocate<IrInstruction *>(2);
incoming_values[0] = then_expr_result;
incoming_values[1] = else_expr_result;
IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2);
incoming_blocks[0] = after_then_block;
incoming_blocks[1] = after_else_block;
return ir_build_phi(irb, node, 2, incoming_blocks, incoming_values);
}
static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockContext *block_context,
LValPurpose lval)
{
@ -1932,10 +2049,11 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockCont
return ir_gen_asm_expr(irb, node);
case NodeTypeNullLiteral:
return ir_gen_null_literal(irb, node);
case NodeTypeIfVarExpr:
return ir_gen_if_var_expr(irb, node);
case NodeTypeUnwrapErrorExpr:
case NodeTypeDefer:
case NodeTypeSliceExpr:
case NodeTypeIfVarExpr:
case NodeTypeGoto:
case NodeTypeBreak:
case NodeTypeContinue:
@ -4488,6 +4606,82 @@ static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira,
zig_unreachable();
}
static TypeTableEntry *ir_analyze_instruction_test_null(IrAnalyze *ira,
IrInstructionTestNull *test_null_instruction)
{
IrInstruction *value = test_null_instruction->value->other;
if (value->type_entry->id == TypeTableEntryIdInvalid)
return ira->codegen->builtin_types.entry_invalid;
// This will be a pointer type because test null IR instruction operates on a pointer to a thing.
TypeTableEntry *ptr_type = value->type_entry;
assert(ptr_type->id == TypeTableEntryIdPointer);
TypeTableEntry *type_entry = ptr_type->data.pointer.child_type;
if (type_entry->id != TypeTableEntryIdMaybe) {
add_node_error(ira->codegen, test_null_instruction->base.source_node,
buf_sprintf("expected nullable type, found '%s'", buf_ptr(&type_entry->name)));
return ira->codegen->builtin_types.entry_invalid;
}
if (value->static_value.special != ConstValSpecialRuntime) {
ConstExprValue *maybe_val = value->static_value.data.x_ptr.base_ptr;
assert(value->static_value.data.x_ptr.index == SIZE_MAX);
if (maybe_val->special != ConstValSpecialRuntime) {
bool depends_on_compile_var = maybe_val->depends_on_compile_var;
ConstExprValue *out_val = ir_build_const_from(ira, &test_null_instruction->base,
depends_on_compile_var);
out_val->data.x_bool = (maybe_val->data.x_maybe == nullptr);
return ira->codegen->builtin_types.entry_bool;
}
}
ir_build_test_null_from(&ira->new_irb, &test_null_instruction->base, value);
return ira->codegen->builtin_types.entry_bool;
}
static TypeTableEntry *ir_analyze_instruction_unwrap_maybe(IrAnalyze *ira,
IrInstructionUnwrapMaybe *unwrap_maybe_instruction)
{
IrInstruction *value = unwrap_maybe_instruction->value->other;
if (value->type_entry->id == TypeTableEntryIdInvalid)
return ira->codegen->builtin_types.entry_invalid;
// This will be a pointer type because test null IR instruction operates on a pointer to a thing.
TypeTableEntry *ptr_type = value->type_entry;
assert(ptr_type->id == TypeTableEntryIdPointer);
TypeTableEntry *type_entry = ptr_type->data.pointer.child_type;
if (type_entry->id == TypeTableEntryIdInvalid) {
return ira->codegen->builtin_types.entry_invalid;
} else if (type_entry->id != TypeTableEntryIdMaybe) {
add_node_error(ira->codegen, unwrap_maybe_instruction->base.source_node,
buf_sprintf("expected nullable type, found '%s'", buf_ptr(&type_entry->name)));
return ira->codegen->builtin_types.entry_invalid;
}
TypeTableEntry *child_type = type_entry->data.maybe.child_type;
TypeTableEntry *result_type = get_pointer_to_type(ira->codegen, child_type, false);
if (value->static_value.special != ConstValSpecialRuntime) {
ConstExprValue *maybe_val = value->static_value.data.x_ptr.base_ptr;
assert(value->static_value.data.x_ptr.index == SIZE_MAX);
if (maybe_val->special != ConstValSpecialRuntime) {
bool depends_on_compile_var = maybe_val->depends_on_compile_var;
ConstExprValue *out_val = ir_build_const_from(ira, &unwrap_maybe_instruction->base,
depends_on_compile_var);
out_val->data.x_ptr.base_ptr = maybe_val;
out_val->data.x_ptr.index = SIZE_MAX;
return result_type;
}
}
ir_build_unwrap_maybe_from(&ira->new_irb, &unwrap_maybe_instruction->base, value,
unwrap_maybe_instruction->safety_check_on);
return result_type;
}
static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
switch (instruction->id) {
case IrInstructionIdInvalid:
@ -4544,6 +4738,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
return ir_analyze_instruction_compile_var(ira, (IrInstructionCompileVar *)instruction);
case IrInstructionIdSizeOf:
return ir_analyze_instruction_size_of(ira, (IrInstructionSizeOf *)instruction);
case IrInstructionIdTestNull:
return ir_analyze_instruction_test_null(ira, (IrInstructionTestNull *)instruction);
case IrInstructionIdUnwrapMaybe:
return ir_analyze_instruction_unwrap_maybe(ira, (IrInstructionUnwrapMaybe *)instruction);
case IrInstructionIdSwitchBr:
case IrInstructionIdCast:
case IrInstructionIdContainerInitList:
@ -4654,6 +4852,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdSliceType:
case IrInstructionIdCompileVar:
case IrInstructionIdSizeOf:
case IrInstructionIdTestNull:
case IrInstructionIdUnwrapMaybe:
return false;
case IrInstructionIdAsm:
{
@ -6266,32 +6466,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) {
// return result_type;
//}
//
//static TypeTableEntry *analyze_if_var_expr(CodeGen *g, ImportTableEntry *import, BlockContext *parent_context,
// TypeTableEntry *expected_type, AstNode *node)
//{
// assert(node->type == NodeTypeIfVarExpr);
//
// BlockContext *child_context = new_block_context(node, parent_context);
//
// analyze_variable_declaration_raw(g, import, child_context, node, &node->data.if_var_expr.var_decl, true,
// nullptr, node->data.if_var_expr.var_is_ptr);
// VariableTableEntry *var = node->data.if_var_expr.var_decl.variable;
// if (var->type->id == TypeTableEntryIdInvalid) {
// return g->builtin_types.entry_invalid;
// }
// AstNode *var_expr_node = node->data.if_var_expr.var_decl.expr;
// ConstExprValue *var_const_val = &get_resolved_expr(var_expr_node)->const_val;
// bool cond_is_const = var_const_val->ok;
// bool cond_bool_val = cond_is_const ? (var_const_val->data.x_maybe != nullptr) : false;
//
//
// AstNode **then_node = &node->data.if_var_expr.then_block;
// AstNode **else_node = &node->data.if_var_expr.else_node;
//
// return analyze_if(g, import, child_context, expected_type,
// node, then_node, else_node, cond_is_const, cond_bool_val);
//}
//
//static TypeTableEntry *bad_method_call(CodeGen *g, AstNode *node, TypeTableEntry *container_type,
// TypeTableEntry *expected_param_type, FnTableEntry *fn_table_entry)
//{
@ -7407,92 +7581,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) {
// }
//}
//
//
//static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTableEntry *import,
// BlockContext *context, AstNode *source_node,
// AstNodeVariableDeclaration *variable_declaration,
// bool expr_is_maybe, AstNode *decl_node, bool var_is_ptr)
//{
// bool is_const = variable_declaration->is_const;
// bool is_export = (variable_declaration->top_level_decl.visib_mod == VisibModExport);
// bool is_extern = variable_declaration->is_extern;
//
// TypeTableEntry *explicit_type = nullptr;
// if (variable_declaration->type != nullptr) {
// explicit_type = analyze_type_expr(g, import, context, variable_declaration->type);
// if (explicit_type->id == TypeTableEntryIdUnreachable) {
// add_node_error(g, variable_declaration->type,
// buf_sprintf("variable of type 'unreachable' not allowed"));
// explicit_type = g->builtin_types.entry_invalid;
// }
// }
//
// TypeTableEntry *implicit_type = nullptr;
// if (explicit_type && explicit_type->id == TypeTableEntryIdInvalid) {
// implicit_type = explicit_type;
// } else if (variable_declaration->expr) {
// implicit_type = analyze_expression(g, import, context, explicit_type, variable_declaration->expr);
// if (implicit_type->id == TypeTableEntryIdInvalid) {
// // ignore the poison value
// } else if (expr_is_maybe) {
// if (implicit_type->id == TypeTableEntryIdMaybe) {
// if (var_is_ptr) {
// // TODO if the expression is constant, can't get pointer to it
// implicit_type = get_pointer_to_type(g, implicit_type->data.maybe.child_type, false);
// } else {
// implicit_type = implicit_type->data.maybe.child_type;
// }
// } else {
// add_node_error(g, variable_declaration->expr, buf_sprintf("expected maybe type"));
// implicit_type = g->builtin_types.entry_invalid;
// }
// } else if (implicit_type->id == TypeTableEntryIdUnreachable) {
// add_node_error(g, source_node,
// buf_sprintf("variable initialization is unreachable"));
// implicit_type = g->builtin_types.entry_invalid;
// } else if ((!is_const || is_export) &&
// (implicit_type->id == TypeTableEntryIdNumLitFloat ||
// implicit_type->id == TypeTableEntryIdNumLitInt))
// {
// add_node_error(g, source_node, buf_sprintf("unable to infer variable type"));
// implicit_type = g->builtin_types.entry_invalid;
// } else if (implicit_type->id == TypeTableEntryIdMetaType && !is_const) {
// add_node_error(g, source_node, buf_sprintf("variable of type 'type' must be constant"));
// implicit_type = g->builtin_types.entry_invalid;
// }
// if (implicit_type->id != TypeTableEntryIdInvalid && !context->fn_entry) {
// ConstExprValue *const_val = &get_resolved_expr(variable_declaration->expr)->const_val;
// if (!const_val->ok) {
// add_node_error(g, first_executing_node(variable_declaration->expr),
// buf_sprintf("global variable initializer requires constant expression"));
// }
// }
// } else if (!is_extern) {
// add_node_error(g, source_node, buf_sprintf("variables must be initialized"));
// implicit_type = g->builtin_types.entry_invalid;
// }
//
// TypeTableEntry *type = explicit_type != nullptr ? explicit_type : implicit_type;
// assert(type != nullptr); // should have been caught by the parser
//
// VariableTableEntry *var = add_local_var(g, source_node, import, context,
// variable_declaration->symbol, type, is_const,
// expr_is_maybe ? nullptr : variable_declaration->expr);
//
// variable_declaration->variable = var;
//
// return var;
//}
//
//static VariableTableEntry *analyze_variable_declaration(CodeGen *g, ImportTableEntry *import,
// BlockContext *context, TypeTableEntry *expected_type, AstNode *node)
//{
// AstNodeVariableDeclaration *variable_declaration = &node->data.variable_declaration;
// return analyze_variable_declaration_raw(g, import, context, node, variable_declaration,
// false, nullptr, false);
//}
//
//
//static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
// TypeTableEntry *expected_type, AstNode *node)
//{
@ -8581,64 +8669,6 @@ static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *no
// return nullptr;
//}
//
//static LLVMValueRef gen_unwrap_maybe_expr(CodeGen *g, AstNode *node) {
// assert(node->type == NodeTypeBinOpExpr);
// assert(node->data.bin_op_expr.bin_op == BinOpTypeUnwrapMaybe);
//
// AstNode *op1_node = node->data.bin_op_expr.op1;
// AstNode *op2_node = node->data.bin_op_expr.op2;
//
// LLVMValueRef maybe_struct_ref = gen_expr(g, op1_node);
//
// TypeTableEntry *maybe_type = get_expr_type(op1_node);
// assert(maybe_type->id == TypeTableEntryIdMaybe);
// TypeTableEntry *child_type = maybe_type->data.maybe.child_type;
//
// LLVMValueRef cond_value;
// if (child_type->id == TypeTableEntryIdPointer ||
// child_type->id == TypeTableEntryIdFn)
// {
// cond_value = LLVMBuildICmp(g->builder, LLVMIntNE, maybe_struct_ref,
// LLVMConstNull(child_type->type_ref), "");
// } else {
// LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, maybe_struct_ref, 1, "");
// cond_value = LLVMBuildLoad(g->builder, maybe_field_ptr, "");
// }
//
// LLVMBasicBlockRef non_null_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeNonNull");
// LLVMBasicBlockRef null_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeNull");
// LLVMBasicBlockRef end_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeEnd");
//
// bool null_reachable = get_expr_type(op2_node)->id != TypeTableEntryIdUnreachable;
//
// LLVMBuildCondBr(g->builder, cond_value, non_null_block, null_block);
//
// LLVMPositionBuilderAtEnd(g->builder, non_null_block);
// LLVMValueRef non_null_result = gen_unwrap_maybe(g, op1_node, maybe_struct_ref);
// LLVMBuildBr(g->builder, end_block);
// LLVMBasicBlockRef post_non_null_result_block = LLVMGetInsertBlock(g->builder);
//
// LLVMPositionBuilderAtEnd(g->builder, null_block);
// LLVMValueRef null_result = gen_expr(g, op2_node);
// if (null_reachable) {
// LLVMBuildBr(g->builder, end_block);
// }
// LLVMBasicBlockRef post_null_result_block = LLVMGetInsertBlock(g->builder);
//
// LLVMPositionBuilderAtEnd(g->builder, end_block);
// if (null_reachable) {
// LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMTypeOf(non_null_result), "");
// LLVMValueRef incoming_values[2] = {non_null_result, null_result};
// LLVMBasicBlockRef incoming_blocks[2] = {post_non_null_result_block, post_null_result_block};
// LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2);
// return phi;
// } else {
// return non_null_result;
// }
//
// return nullptr;
//}
//
//static LLVMValueRef gen_unwrap_err_expr(CodeGen *g, AstNode *node) {
// assert(node->type == NodeTypeUnwrapErrorExpr);
//
@ -8914,120 +8944,6 @@ static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *no
// }
//}
//
//static LLVMValueRef gen_if_var_then_block(CodeGen *g, AstNode *node, VariableTableEntry *variable, bool maybe_is_ptr,
// LLVMValueRef init_val, TypeTableEntry *child_type, AstNode *then_node)
//{
// if (node->data.if_var_expr.var_is_ptr) {
// LLVMValueRef payload_ptr;
// if (maybe_is_ptr) {
// zig_panic("TODO");
// } else {
// payload_ptr = LLVMBuildStructGEP(g->builder, init_val, 0, "");
// }
// LLVMBuildStore(g->builder, payload_ptr, variable->value_ref);
// } else {
// LLVMValueRef payload_val;
// if (maybe_is_ptr) {
// payload_val = init_val;
// } else {
// LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, init_val, 0, "");
// payload_val = get_handle_value(g, payload_ptr, child_type);
// }
// gen_assign_raw(g, node, BinOpTypeAssign, variable->value_ref, payload_val,
// variable->type, child_type);
// }
// gen_var_debug_decl(g, variable);
//
// return gen_expr(g, then_node);
//}
//
//static LLVMValueRef gen_if_var_expr(CodeGen *g, AstNode *node) {
// assert(node->type == NodeTypeIfVarExpr);
// assert(node->data.if_var_expr.var_decl.expr);
//
// AstNodeVariableDeclaration *var_decl = &node->data.if_var_expr.var_decl;
// VariableTableEntry *variable = var_decl->variable;
//
// // test if value is the maybe state
// TypeTableEntry *expr_type = get_expr_type(var_decl->expr);
// TypeTableEntry *child_type = expr_type->data.maybe.child_type;
//
// LLVMValueRef init_val = gen_expr(g, var_decl->expr);
//
//
// AstNode *then_node = node->data.if_var_expr.then_block;
// AstNode *else_node = node->data.if_var_expr.else_node;
// bool maybe_is_ptr = child_type->id == TypeTableEntryIdPointer || child_type->id == TypeTableEntryIdFn;
//
// ConstExprValue *const_val = &get_resolved_expr(var_decl->expr)->const_val;
// if (const_val->ok) {
// if (const_val->data.x_maybe) {
// return gen_if_var_then_block(g, node, variable, maybe_is_ptr, init_val, child_type, then_node);
// } else {
// return gen_expr(g, else_node);
// }
// }
//
// LLVMValueRef cond_value;
// if (maybe_is_ptr) {
// cond_value = LLVMBuildICmp(g->builder, LLVMIntNE, init_val, LLVMConstNull(child_type->type_ref), "");
// } else {
// LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, init_val, 1, "");
// cond_value = LLVMBuildLoad(g->builder, maybe_field_ptr, "");
// }
//
// TypeTableEntry *then_type = get_expr_type(then_node);
// TypeTableEntry *else_type = get_expr_type(else_node);
//
// bool use_then_value = type_has_bits(then_type);
// bool use_else_value = type_has_bits(else_type);
//
// LLVMBasicBlockRef then_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeThen");
// LLVMBasicBlockRef else_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeElse");
//
// LLVMBasicBlockRef endif_block;
// bool then_endif_reachable = then_type->id != TypeTableEntryIdUnreachable;
// bool else_endif_reachable = else_type->id != TypeTableEntryIdUnreachable;
// if (then_endif_reachable || else_endif_reachable) {
// endif_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeEndIf");
// }
//
// LLVMBuildCondBr(g->builder, cond_value, then_block, else_block);
//
// LLVMPositionBuilderAtEnd(g->builder, then_block);
// LLVMValueRef then_expr_result = gen_if_var_then_block(g, node, variable, maybe_is_ptr, init_val, child_type, then_node);
//
// if (then_endif_reachable) {
// LLVMBuildBr(g->builder, endif_block);
// }
// LLVMBasicBlockRef after_then_block = LLVMGetInsertBlock(g->builder);
//
//
// LLVMPositionBuilderAtEnd(g->builder, else_block);
// LLVMValueRef else_expr_result = gen_expr(g, else_node);
// if (else_endif_reachable) {
// LLVMBuildBr(g->builder, endif_block);
// }
// LLVMBasicBlockRef after_else_block = LLVMGetInsertBlock(g->builder);
//
// if (then_endif_reachable || else_endif_reachable) {
// LLVMPositionBuilderAtEnd(g->builder, endif_block);
// if (use_then_value && use_else_value) {
// LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMTypeOf(then_expr_result), "");
// LLVMValueRef incoming_values[2] = {then_expr_result, else_expr_result};
// LLVMBasicBlockRef incoming_blocks[2] = {after_then_block, after_else_block};
// LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2);
// return phi;
// } else if (use_then_value) {
// return then_expr_result;
// } else if (use_else_value) {
// return else_expr_result;
// }
// }
//
// return nullptr;
//}
//
//static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *implicit_return_type) {
// assert(block_node->type == NodeTypeBlock);
//
@ -9667,20 +9583,6 @@ static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *no
// zig_unreachable();
//}
//
//static LLVMValueRef gen_unwrap_maybe(CodeGen *g, AstNode *node, LLVMValueRef maybe_struct_ref) {
// TypeTableEntry *type_entry = get_expr_type(node);
// assert(type_entry->id == TypeTableEntryIdMaybe);
// TypeTableEntry *child_type = type_entry->data.maybe.child_type;
// if (child_type->id == TypeTableEntryIdPointer ||
// child_type->id == TypeTableEntryIdFn)
// {
// return maybe_struct_ref;
// } else {
// LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, maybe_struct_ref, 0, "");
// return get_handle_value(g, maybe_field_ptr, child_type);
// }
//}
//
//static size_t get_conditional_defer_count(BlockContext *inner_block, BlockContext *outer_block) {
// size_t result = 0;
// while (inner_block != outer_block) {

View File

@ -497,6 +497,20 @@ static void ir_print_size_of(IrPrint *irp, IrInstructionSizeOf *instruction) {
fprintf(irp->f, ")");
}
static void ir_print_test_null(IrPrint *irp, IrInstructionTestNull *instruction) {
fprintf(irp->f, "*");
ir_print_other_instruction(irp, instruction->value);
fprintf(irp->f, " == null");
}
static void ir_print_unwrap_maybe(IrPrint *irp, IrInstructionUnwrapMaybe *instruction) {
fprintf(irp->f, "&??*");
ir_print_other_instruction(irp, instruction->value);
if (!instruction->safety_check_on) {
fprintf(irp->f, " // no safety");
}
}
static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
ir_print_prefix(irp, instruction);
switch (instruction->id) {
@ -592,6 +606,12 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdSizeOf:
ir_print_size_of(irp, (IrInstructionSizeOf *)instruction);
break;
case IrInstructionIdTestNull:
ir_print_test_null(irp, (IrInstructionTestNull *)instruction);
break;
case IrInstructionIdUnwrapMaybe:
ir_print_unwrap_maybe(irp, (IrInstructionUnwrapMaybe *)instruction);
break;
case IrInstructionIdSwitchBr:
zig_panic("TODO print more IR instructions");
}