From 093e0d1bb020e6b7245d142b1fc75bdbd7868045 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 4 Feb 2016 17:21:08 -0700 Subject: support variable in switch expression prongs See #43 --- src/codegen.cpp | 95 ++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 60 insertions(+), 35 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index 17e781fd02..3d45413ec7 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -184,6 +184,15 @@ static LLVMValueRef get_int_overflow_fn(CodeGen *g, TypeTableEntry *type_entry, return *fn; } +static LLVMValueRef get_handle_value(CodeGen *g, AstNode *source_node, LLVMValueRef ptr, TypeTableEntry *type) { + if (handle_is_ptr(type)) { + return ptr; + } else { + add_debug_source_node(g, source_node); + return LLVMBuildLoad(g->builder, ptr, ""); + } +} + static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) { assert(node->type == NodeTypeFnCallExpr); AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr; @@ -1024,11 +1033,7 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) { if (type_has_bits(child_type)) { LLVMValueRef child_val_ptr = LLVMBuildStructGEP(g->builder, expr_val, 1, ""); - if (handle_is_ptr(child_type)) { - return child_val_ptr; - } else { - return LLVMBuildLoad(g->builder, child_val_ptr, ""); - } + return get_handle_value(g, expr_node, child_val_ptr, child_type); } else { return nullptr; } @@ -1073,11 +1078,7 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) { } else { add_debug_source_node(g, node); LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, expr_val, 0, ""); - if (handle_is_ptr(child_type)) { - return maybe_field_ptr; - } else { - return LLVMBuildLoad(g->builder, maybe_field_ptr, ""); - } + return get_handle_value(g, node, maybe_field_ptr, child_type); } } } @@ -1412,11 +1413,7 @@ static LLVMValueRef gen_unwrap_maybe(CodeGen *g, AstNode *node, LLVMValueRef may } else { add_debug_source_node(g, node); LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, maybe_struct_ref, 0, ""); - if (handle_is_ptr(child_type)) { - return maybe_field_ptr; - } else { - return LLVMBuildLoad(g->builder, maybe_field_ptr, ""); - } + return get_handle_value(g, node, maybe_field_ptr, child_type); } } @@ -1580,12 +1577,7 @@ static LLVMValueRef gen_unwrap_err_expr(CodeGen *g, AstNode *node) { return nullptr; } LLVMValueRef child_val_ptr = LLVMBuildStructGEP(g->builder, expr_val, 1, ""); - LLVMValueRef child_val; - if (handle_is_ptr(child_type)) { - child_val = child_val_ptr; - } else { - child_val = LLVMBuildLoad(g->builder, child_val_ptr, ""); - } + LLVMValueRef child_val = get_handle_value(g, node, child_val_ptr, child_type); if (!have_end_block) { return child_val; @@ -1667,11 +1659,7 @@ static LLVMValueRef gen_return_expr(CodeGen *g, AstNode *node) { if (type_has_bits(child_type)) { add_debug_source_node(g, node); LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, value, 1, ""); - if (handle_is_ptr(child_type)) { - return val_ptr; - } else { - return LLVMBuildLoad(g->builder, val_ptr, ""); - } + return get_handle_value(g, node, val_ptr, child_type); } else { return nullptr; } @@ -2294,12 +2282,7 @@ static LLVMValueRef gen_symbol(CodeGen *g, AstNode *node) { return nullptr; } else if (variable->is_ptr) { assert(variable->value_ref); - if (handle_is_ptr(variable->type)) { - return variable->value_ref; - } else { - add_debug_source_node(g, node); - return LLVMBuildLoad(g->builder, variable->value_ref, ""); - } + return get_handle_value(g, node, variable->value_ref, variable->type); } else { return variable->value_ref; } @@ -2347,6 +2330,8 @@ static LLVMValueRef gen_switch_expr(CodeGen *g, AstNode *node) { AstNode *else_prong = nullptr; for (int prong_i = 0; prong_i < prong_count; prong_i += 1) { AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i); + VariableTableEntry *prong_var = prong_node->data.switch_prong.var; + LLVMBasicBlockRef prong_block; if (prong_node->data.switch_prong.items.length == 0) { assert(!else_prong); @@ -2354,8 +2339,12 @@ static LLVMValueRef gen_switch_expr(CodeGen *g, AstNode *node) { prong_block = else_block; } else { prong_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "SwitchProng"); - for (int item_i = 0; item_i < prong_node->data.switch_prong.items.length; item_i += 1) { + int prong_item_count = prong_node->data.switch_prong.items.length; + bool make_item_blocks = prong_var && prong_item_count > 1; + + for (int item_i = 0; item_i < prong_item_count; item_i += 1) { AstNode *item_node = prong_node->data.switch_prong.items.at(item_i); + assert(item_node->type != NodeTypeSwitchRange); LLVMValueRef val; if (target_type->id == TypeTableEntryIdEnum) { @@ -2364,14 +2353,50 @@ static LLVMValueRef gen_switch_expr(CodeGen *g, AstNode *node) { assert(enum_field); val = LLVMConstInt(target_type->data.enumeration.tag_type->type_ref, enum_field->value, false); + + if (prong_var && type_has_bits(prong_var->type)) { + LLVMBasicBlockRef item_block; + + if (make_item_blocks) { + item_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "SwitchProngItem"); + LLVMAddCase(switch_instr, val, item_block); + LLVMPositionBuilderAtEnd(g->builder, item_block); + } else { + LLVMAddCase(switch_instr, val, prong_block); + LLVMPositionBuilderAtEnd(g->builder, prong_block); + } + + AstNode *var_node = prong_node->data.switch_prong.var_symbol; + add_debug_source_node(g, var_node); + if (prong_node->data.switch_prong.var_is_target_expr) { + gen_assign_raw(g, var_node, BinOpTypeAssign, + prong_var->value_ref, target_value, prong_var->type, target_type); + } else if (target_type->id == TypeTableEntryIdEnum) { + assert(type_has_bits(enum_field->type_entry)); + LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, target_value_handle, + 1, ""); + LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr, + LLVMPointerType(enum_field->type_entry->type_ref, 0), ""); + LLVMValueRef handle_val = get_handle_value(g, var_node, bitcasted_union_field_ptr, + enum_field->type_entry); + + gen_assign_raw(g, var_node, BinOpTypeAssign, + prong_var->value_ref, handle_val, prong_var->type, enum_field->type_entry); + } + if (make_item_blocks) { + LLVMBuildBr(g->builder, prong_block); + } + } else { + LLVMAddCase(switch_instr, val, prong_block); + } } else { assert(get_resolved_expr(item_node)->const_val.ok); val = gen_expr(g, item_node); + LLVMAddCase(switch_instr, val, prong_block); } - LLVMAddCase(switch_instr, val, prong_block); } } - assert(!prong_node->data.switch_prong.var_symbol); + LLVMPositionBuilderAtEnd(g->builder, prong_block); AstNode *prong_expr = prong_node->data.switch_prong.expr; LLVMValueRef prong_val = gen_expr(g, prong_expr); -- cgit v1.2.3