| ... | @@ -184,6 +184,15 @@ static LLVMValueRef get_int_overflow_fn(CodeGen *g, TypeTableEntry *type_entry, | ... | @@ -184,6 +184,15 @@ static LLVMValueRef get_int_overflow_fn(CodeGen *g, TypeTableEntry *type_entry, |
| 184 | return *fn; | 184 | return *fn; |
| 185 | } | 185 | } |
| 186 | | 186 | |
| | 187 | static LLVMValueRef get_handle_value(CodeGen *g, AstNode *source_node, LLVMValueRef ptr, TypeTableEntry *type) { |
| | 188 | if (handle_is_ptr(type)) { |
| | 189 | return ptr; |
| | 190 | } else { |
| | 191 | add_debug_source_node(g, source_node); |
| | 192 | return LLVMBuildLoad(g->builder, ptr, ""); |
| | 193 | } |
| | 194 | } |
| | 195 | |
| 187 | static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) { | 196 | static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) { |
| 188 | assert(node->type == NodeTypeFnCallExpr); | 197 | assert(node->type == NodeTypeFnCallExpr); |
| 189 | AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr; | 198 | 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) { | ... | @@ -1024,11 +1033,7 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) { |
| 1024 | | 1033 | |
| 1025 | if (type_has_bits(child_type)) { | 1034 | if (type_has_bits(child_type)) { |
| 1026 | LLVMValueRef child_val_ptr = LLVMBuildStructGEP(g->builder, expr_val, 1, ""); | 1035 | LLVMValueRef child_val_ptr = LLVMBuildStructGEP(g->builder, expr_val, 1, ""); |
| 1027 | if (handle_is_ptr(child_type)) { | 1036 | return get_handle_value(g, expr_node, child_val_ptr, child_type); |
| 1028 | return child_val_ptr; | | |
| 1029 | } else { | | |
| 1030 | return LLVMBuildLoad(g->builder, child_val_ptr, ""); | | |
| 1031 | } | | |
| 1032 | } else { | 1037 | } else { |
| 1033 | return nullptr; | 1038 | return nullptr; |
| 1034 | } | 1039 | } |
| ... | @@ -1073,11 +1078,7 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) { | ... | @@ -1073,11 +1078,7 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) { |
| 1073 | } else { | 1078 | } else { |
| 1074 | add_debug_source_node(g, node); | 1079 | add_debug_source_node(g, node); |
| 1075 | LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, expr_val, 0, ""); | 1080 | LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, expr_val, 0, ""); |
| 1076 | if (handle_is_ptr(child_type)) { | 1081 | return get_handle_value(g, node, maybe_field_ptr, child_type); |
| 1077 | return maybe_field_ptr; | | |
| 1078 | } else { | | |
| 1079 | return LLVMBuildLoad(g->builder, maybe_field_ptr, ""); | | |
| 1080 | } | | |
| 1081 | } | 1082 | } |
| 1082 | } | 1083 | } |
| 1083 | } | 1084 | } |
| ... | @@ -1412,11 +1413,7 @@ static LLVMValueRef gen_unwrap_maybe(CodeGen *g, AstNode *node, LLVMValueRef may | ... | @@ -1412,11 +1413,7 @@ static LLVMValueRef gen_unwrap_maybe(CodeGen *g, AstNode *node, LLVMValueRef may |
| 1412 | } else { | 1413 | } else { |
| 1413 | add_debug_source_node(g, node); | 1414 | add_debug_source_node(g, node); |
| 1414 | LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, maybe_struct_ref, 0, ""); | 1415 | LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, maybe_struct_ref, 0, ""); |
| 1415 | if (handle_is_ptr(child_type)) { | 1416 | return get_handle_value(g, node, maybe_field_ptr, child_type); |
| 1416 | return maybe_field_ptr; | | |
| 1417 | } else { | | |
| 1418 | return LLVMBuildLoad(g->builder, maybe_field_ptr, ""); | | |
| 1419 | } | | |
| 1420 | } | 1417 | } |
| 1421 | } | 1418 | } |
| 1422 | | 1419 | |
| ... | @@ -1580,12 +1577,7 @@ static LLVMValueRef gen_unwrap_err_expr(CodeGen *g, AstNode *node) { | ... | @@ -1580,12 +1577,7 @@ static LLVMValueRef gen_unwrap_err_expr(CodeGen *g, AstNode *node) { |
| 1580 | return nullptr; | 1577 | return nullptr; |
| 1581 | } | 1578 | } |
| 1582 | LLVMValueRef child_val_ptr = LLVMBuildStructGEP(g->builder, expr_val, 1, ""); | 1579 | LLVMValueRef child_val_ptr = LLVMBuildStructGEP(g->builder, expr_val, 1, ""); |
| 1583 | LLVMValueRef child_val; | 1580 | LLVMValueRef child_val = get_handle_value(g, node, child_val_ptr, child_type); |
| 1584 | if (handle_is_ptr(child_type)) { | | |
| 1585 | child_val = child_val_ptr; | | |
| 1586 | } else { | | |
| 1587 | child_val = LLVMBuildLoad(g->builder, child_val_ptr, ""); | | |
| 1588 | } | | |
| 1589 | | 1581 | |
| 1590 | if (!have_end_block) { | 1582 | if (!have_end_block) { |
| 1591 | return child_val; | 1583 | return child_val; |
| ... | @@ -1667,11 +1659,7 @@ static LLVMValueRef gen_return_expr(CodeGen *g, AstNode *node) { | ... | @@ -1667,11 +1659,7 @@ static LLVMValueRef gen_return_expr(CodeGen *g, AstNode *node) { |
| 1667 | if (type_has_bits(child_type)) { | 1659 | if (type_has_bits(child_type)) { |
| 1668 | add_debug_source_node(g, node); | 1660 | add_debug_source_node(g, node); |
| 1669 | LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, value, 1, ""); | 1661 | LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, value, 1, ""); |
| 1670 | if (handle_is_ptr(child_type)) { | 1662 | return get_handle_value(g, node, val_ptr, child_type); |
| 1671 | return val_ptr; | | |
| 1672 | } else { | | |
| 1673 | return LLVMBuildLoad(g->builder, val_ptr, ""); | | |
| 1674 | } | | |
| 1675 | } else { | 1663 | } else { |
| 1676 | return nullptr; | 1664 | return nullptr; |
| 1677 | } | 1665 | } |
| ... | @@ -2294,12 +2282,7 @@ static LLVMValueRef gen_symbol(CodeGen *g, AstNode *node) { | ... | @@ -2294,12 +2282,7 @@ static LLVMValueRef gen_symbol(CodeGen *g, AstNode *node) { |
| 2294 | return nullptr; | 2282 | return nullptr; |
| 2295 | } else if (variable->is_ptr) { | 2283 | } else if (variable->is_ptr) { |
| 2296 | assert(variable->value_ref); | 2284 | assert(variable->value_ref); |
| 2297 | if (handle_is_ptr(variable->type)) { | 2285 | return get_handle_value(g, node, variable->value_ref, variable->type); |
| 2298 | return variable->value_ref; | | |
| 2299 | } else { | | |
| 2300 | add_debug_source_node(g, node); | | |
| 2301 | return LLVMBuildLoad(g->builder, variable->value_ref, ""); | | |
| 2302 | } | | |
| 2303 | } else { | 2286 | } else { |
| 2304 | return variable->value_ref; | 2287 | return variable->value_ref; |
| 2305 | } | 2288 | } |
| ... | @@ -2347,6 +2330,8 @@ static LLVMValueRef gen_switch_expr(CodeGen *g, AstNode *node) { | ... | @@ -2347,6 +2330,8 @@ static LLVMValueRef gen_switch_expr(CodeGen *g, AstNode *node) { |
| 2347 | AstNode *else_prong = nullptr; | 2330 | AstNode *else_prong = nullptr; |
| 2348 | for (int prong_i = 0; prong_i < prong_count; prong_i += 1) { | 2331 | for (int prong_i = 0; prong_i < prong_count; prong_i += 1) { |
| 2349 | AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i); | 2332 | AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i); |
| | 2333 | VariableTableEntry *prong_var = prong_node->data.switch_prong.var; |
| | 2334 | |
| 2350 | LLVMBasicBlockRef prong_block; | 2335 | LLVMBasicBlockRef prong_block; |
| 2351 | if (prong_node->data.switch_prong.items.length == 0) { | 2336 | if (prong_node->data.switch_prong.items.length == 0) { |
| 2352 | assert(!else_prong); | 2337 | assert(!else_prong); |
| ... | @@ -2354,8 +2339,12 @@ static LLVMValueRef gen_switch_expr(CodeGen *g, AstNode *node) { | ... | @@ -2354,8 +2339,12 @@ static LLVMValueRef gen_switch_expr(CodeGen *g, AstNode *node) { |
| 2354 | prong_block = else_block; | 2339 | prong_block = else_block; |
| 2355 | } else { | 2340 | } else { |
| 2356 | prong_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "SwitchProng"); | 2341 | prong_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "SwitchProng"); |
| 2357 | for (int item_i = 0; item_i < prong_node->data.switch_prong.items.length; item_i += 1) { | 2342 | int prong_item_count = prong_node->data.switch_prong.items.length; |
| | 2343 | bool make_item_blocks = prong_var && prong_item_count > 1; |
| | 2344 | |
| | 2345 | for (int item_i = 0; item_i < prong_item_count; item_i += 1) { |
| 2358 | AstNode *item_node = prong_node->data.switch_prong.items.at(item_i); | 2346 | AstNode *item_node = prong_node->data.switch_prong.items.at(item_i); |
| | 2347 | |
| 2359 | assert(item_node->type != NodeTypeSwitchRange); | 2348 | assert(item_node->type != NodeTypeSwitchRange); |
| 2360 | LLVMValueRef val; | 2349 | LLVMValueRef val; |
| 2361 | if (target_type->id == TypeTableEntryIdEnum) { | 2350 | if (target_type->id == TypeTableEntryIdEnum) { |
| ... | @@ -2364,14 +2353,50 @@ static LLVMValueRef gen_switch_expr(CodeGen *g, AstNode *node) { | ... | @@ -2364,14 +2353,50 @@ static LLVMValueRef gen_switch_expr(CodeGen *g, AstNode *node) { |
| 2364 | assert(enum_field); | 2353 | assert(enum_field); |
| 2365 | val = LLVMConstInt(target_type->data.enumeration.tag_type->type_ref, | 2354 | val = LLVMConstInt(target_type->data.enumeration.tag_type->type_ref, |
| 2366 | enum_field->value, false); | 2355 | enum_field->value, false); |
| | 2356 | |
| | 2357 | if (prong_var && type_has_bits(prong_var->type)) { |
| | 2358 | LLVMBasicBlockRef item_block; |
| | 2359 | |
| | 2360 | if (make_item_blocks) { |
| | 2361 | item_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "SwitchProngItem"); |
| | 2362 | LLVMAddCase(switch_instr, val, item_block); |
| | 2363 | LLVMPositionBuilderAtEnd(g->builder, item_block); |
| | 2364 | } else { |
| | 2365 | LLVMAddCase(switch_instr, val, prong_block); |
| | 2366 | LLVMPositionBuilderAtEnd(g->builder, prong_block); |
| | 2367 | } |
| | 2368 | |
| | 2369 | AstNode *var_node = prong_node->data.switch_prong.var_symbol; |
| | 2370 | add_debug_source_node(g, var_node); |
| | 2371 | if (prong_node->data.switch_prong.var_is_target_expr) { |
| | 2372 | gen_assign_raw(g, var_node, BinOpTypeAssign, |
| | 2373 | prong_var->value_ref, target_value, prong_var->type, target_type); |
| | 2374 | } else if (target_type->id == TypeTableEntryIdEnum) { |
| | 2375 | assert(type_has_bits(enum_field->type_entry)); |
| | 2376 | LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, target_value_handle, |
| | 2377 | 1, ""); |
| | 2378 | LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr, |
| | 2379 | LLVMPointerType(enum_field->type_entry->type_ref, 0), ""); |
| | 2380 | LLVMValueRef handle_val = get_handle_value(g, var_node, bitcasted_union_field_ptr, |
| | 2381 | enum_field->type_entry); |
| | 2382 | |
| | 2383 | gen_assign_raw(g, var_node, BinOpTypeAssign, |
| | 2384 | prong_var->value_ref, handle_val, prong_var->type, enum_field->type_entry); |
| | 2385 | } |
| | 2386 | if (make_item_blocks) { |
| | 2387 | LLVMBuildBr(g->builder, prong_block); |
| | 2388 | } |
| | 2389 | } else { |
| | 2390 | LLVMAddCase(switch_instr, val, prong_block); |
| | 2391 | } |
| 2367 | } else { | 2392 | } else { |
| 2368 | assert(get_resolved_expr(item_node)->const_val.ok); | 2393 | assert(get_resolved_expr(item_node)->const_val.ok); |
| 2369 | val = gen_expr(g, item_node); | 2394 | val = gen_expr(g, item_node); |
| | 2395 | LLVMAddCase(switch_instr, val, prong_block); |
| 2370 | } | 2396 | } |
| 2371 | LLVMAddCase(switch_instr, val, prong_block); | | |
| 2372 | } | 2397 | } |
| 2373 | } | 2398 | } |
| 2374 | assert(!prong_node->data.switch_prong.var_symbol); | 2399 | |
| 2375 | LLVMPositionBuilderAtEnd(g->builder, prong_block); | 2400 | LLVMPositionBuilderAtEnd(g->builder, prong_block); |
| 2376 | AstNode *prong_expr = prong_node->data.switch_prong.expr; | 2401 | AstNode *prong_expr = prong_node->data.switch_prong.expr; |
| 2377 | LLVMValueRef prong_val = gen_expr(g, prong_expr); | 2402 | LLVMValueRef prong_val = gen_expr(g, prong_expr); |