| ... | ... | @@ -184,6 +184,15 @@ static LLVMValueRef get_int_overflow_fn(CodeGen *g, TypeTableEntry *type_entry, |
| 184 | 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 | 196 | static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) { |
| 188 | 197 | assert(node->type == NodeTypeFnCallExpr); |
| 189 | 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 | 1033 | |
| 1025 | 1034 | if (type_has_bits(child_type)) { |
| 1026 | 1035 | LLVMValueRef child_val_ptr = LLVMBuildStructGEP(g->builder, expr_val, 1, ""); |
| 1027 | | if (handle_is_ptr(child_type)) { |
| 1028 | | return child_val_ptr; |
| 1029 | | } else { |
| 1030 | | return LLVMBuildLoad(g->builder, child_val_ptr, ""); |
| 1031 | | } |
| 1036 | return get_handle_value(g, expr_node, child_val_ptr, child_type); |
| 1032 | 1037 | } else { |
| 1033 | 1038 | return nullptr; |
| 1034 | 1039 | } |
| ... | ... | @@ -1073,11 +1078,7 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) { |
| 1073 | 1078 | } else { |
| 1074 | 1079 | add_debug_source_node(g, node); |
| 1075 | 1080 | LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, expr_val, 0, ""); |
| 1076 | | if (handle_is_ptr(child_type)) { |
| 1077 | | return maybe_field_ptr; |
| 1078 | | } else { |
| 1079 | | return LLVMBuildLoad(g->builder, maybe_field_ptr, ""); |
| 1080 | | } |
| 1081 | return get_handle_value(g, node, maybe_field_ptr, child_type); |
| 1081 | 1082 | } |
| 1082 | 1083 | } |
| 1083 | 1084 | } |
| ... | ... | @@ -1412,11 +1413,7 @@ static LLVMValueRef gen_unwrap_maybe(CodeGen *g, AstNode *node, LLVMValueRef may |
| 1412 | 1413 | } else { |
| 1413 | 1414 | add_debug_source_node(g, node); |
| 1414 | 1415 | LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, maybe_struct_ref, 0, ""); |
| 1415 | | if (handle_is_ptr(child_type)) { |
| 1416 | | return maybe_field_ptr; |
| 1417 | | } else { |
| 1418 | | return LLVMBuildLoad(g->builder, maybe_field_ptr, ""); |
| 1419 | | } |
| 1416 | return get_handle_value(g, node, maybe_field_ptr, child_type); |
| 1420 | 1417 | } |
| 1421 | 1418 | } |
| 1422 | 1419 | |
| ... | ... | @@ -1580,12 +1577,7 @@ static LLVMValueRef gen_unwrap_err_expr(CodeGen *g, AstNode *node) { |
| 1580 | 1577 | return nullptr; |
| 1581 | 1578 | } |
| 1582 | 1579 | LLVMValueRef child_val_ptr = LLVMBuildStructGEP(g->builder, expr_val, 1, ""); |
| 1583 | | LLVMValueRef child_val; |
| 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 | | } |
| 1580 | LLVMValueRef child_val = get_handle_value(g, node, child_val_ptr, child_type); |
| 1589 | 1581 | |
| 1590 | 1582 | if (!have_end_block) { |
| 1591 | 1583 | return child_val; |
| ... | ... | @@ -1667,11 +1659,7 @@ static LLVMValueRef gen_return_expr(CodeGen *g, AstNode *node) { |
| 1667 | 1659 | if (type_has_bits(child_type)) { |
| 1668 | 1660 | add_debug_source_node(g, node); |
| 1669 | 1661 | LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, value, 1, ""); |
| 1670 | | if (handle_is_ptr(child_type)) { |
| 1671 | | return val_ptr; |
| 1672 | | } else { |
| 1673 | | return LLVMBuildLoad(g->builder, val_ptr, ""); |
| 1674 | | } |
| 1662 | return get_handle_value(g, node, val_ptr, child_type); |
| 1675 | 1663 | } else { |
| 1676 | 1664 | return nullptr; |
| 1677 | 1665 | } |
| ... | ... | @@ -2294,12 +2282,7 @@ static LLVMValueRef gen_symbol(CodeGen *g, AstNode *node) { |
| 2294 | 2282 | return nullptr; |
| 2295 | 2283 | } else if (variable->is_ptr) { |
| 2296 | 2284 | assert(variable->value_ref); |
| 2297 | | if (handle_is_ptr(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 | | } |
| 2285 | return get_handle_value(g, node, variable->value_ref, variable->type); |
| 2303 | 2286 | } else { |
| 2304 | 2287 | return variable->value_ref; |
| 2305 | 2288 | } |
| ... | ... | @@ -2347,6 +2330,8 @@ static LLVMValueRef gen_switch_expr(CodeGen *g, AstNode *node) { |
| 2347 | 2330 | AstNode *else_prong = nullptr; |
| 2348 | 2331 | for (int prong_i = 0; prong_i < prong_count; prong_i += 1) { |
| 2349 | 2332 | AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i); |
| 2333 | VariableTableEntry *prong_var = prong_node->data.switch_prong.var; |
| 2334 | |
| 2350 | 2335 | LLVMBasicBlockRef prong_block; |
| 2351 | 2336 | if (prong_node->data.switch_prong.items.length == 0) { |
| 2352 | 2337 | assert(!else_prong); |
| ... | ... | @@ -2354,8 +2339,12 @@ static LLVMValueRef gen_switch_expr(CodeGen *g, AstNode *node) { |
| 2354 | 2339 | prong_block = else_block; |
| 2355 | 2340 | } else { |
| 2356 | 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 | 2346 | AstNode *item_node = prong_node->data.switch_prong.items.at(item_i); |
| 2347 | |
| 2359 | 2348 | assert(item_node->type != NodeTypeSwitchRange); |
| 2360 | 2349 | LLVMValueRef val; |
| 2361 | 2350 | if (target_type->id == TypeTableEntryIdEnum) { |
| ... | ... | @@ -2364,14 +2353,50 @@ static LLVMValueRef gen_switch_expr(CodeGen *g, AstNode *node) { |
| 2364 | 2353 | assert(enum_field); |
| 2365 | 2354 | val = LLVMConstInt(target_type->data.enumeration.tag_type->type_ref, |
| 2366 | 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 | 2392 | } else { |
| 2368 | 2393 | assert(get_resolved_expr(item_node)->const_val.ok); |
| 2369 | 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 | 2400 | LLVMPositionBuilderAtEnd(g->builder, prong_block); |
| 2376 | 2401 | AstNode *prong_expr = prong_node->data.switch_prong.expr; |
| 2377 | 2402 | LLVMValueRef prong_val = gen_expr(g, prong_expr); |