| ... | @@ -74,7 +74,7 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *expr_node); | ... | @@ -74,7 +74,7 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *expr_node); |
| 74 | static LLVMValueRef gen_lvalue(CodeGen *g, AstNode *expr_node, AstNode *node, TypeTableEntry **out_type_entry); | 74 | static LLVMValueRef gen_lvalue(CodeGen *g, AstNode *expr_node, AstNode *node, TypeTableEntry **out_type_entry); |
| 75 | static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node, bool is_lvalue); | 75 | static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node, bool is_lvalue); |
| 76 | static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVariableDeclaration *var_decl, | 76 | static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVariableDeclaration *var_decl, |
| 77 | bool unwrap_maybe, LLVMValueRef *init_val); | 77 | bool unwrap_maybe, LLVMValueRef *init_val, TypeTableEntry **init_val_type); |
| 78 | static LLVMValueRef gen_assign_raw(CodeGen *g, AstNode *source_node, BinOpType bin_op, | 78 | static LLVMValueRef gen_assign_raw(CodeGen *g, AstNode *source_node, BinOpType bin_op, |
| 79 | LLVMValueRef target_ref, LLVMValueRef value, | 79 | LLVMValueRef target_ref, LLVMValueRef value, |
| 80 | TypeTableEntry *op1_type, TypeTableEntry *op2_type); | 80 | TypeTableEntry *op1_type, TypeTableEntry *op2_type); |
| ... | @@ -389,14 +389,20 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) { | ... | @@ -389,14 +389,20 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) { |
| 389 | assert(wanted_type->id == TypeTableEntryIdMaybe); | 389 | assert(wanted_type->id == TypeTableEntryIdMaybe); |
| 390 | assert(actual_type); | 390 | assert(actual_type); |
| 391 | | 391 | |
| 392 | add_debug_source_node(g, node); | 392 | TypeTableEntry *child_type = wanted_type->data.maybe.child_type; |
| 393 | LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr, 0, ""); | | |
| 394 | gen_assign_raw(g, node, BinOpTypeAssign, | | |
| 395 | val_ptr, expr_val, wanted_type->data.maybe.child_type, actual_type); | | |
| 396 | | 393 | |
| 397 | add_debug_source_node(g, node); | 394 | if (child_type->id == TypeTableEntryIdPointer) { |
| 398 | LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr, 1, ""); | 395 | return expr_val; |
| 399 | LLVMBuildStore(g->builder, LLVMConstAllOnes(LLVMInt1Type()), maybe_ptr); | 396 | } else { |
| | 397 | add_debug_source_node(g, node); |
| | 398 | LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr, 0, ""); |
| | 399 | gen_assign_raw(g, node, BinOpTypeAssign, |
| | 400 | val_ptr, expr_val, child_type, actual_type); |
| | 401 | |
| | 402 | add_debug_source_node(g, node); |
| | 403 | LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr, 1, ""); |
| | 404 | LLVMBuildStore(g->builder, LLVMConstAllOnes(LLVMInt1Type()), maybe_ptr); |
| | 405 | } |
| 400 | | 406 | |
| 401 | return cast_expr->tmp_ptr; | 407 | return cast_expr->tmp_ptr; |
| 402 | } | 408 | } |
| ... | @@ -1245,10 +1251,20 @@ static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) { | ... | @@ -1245,10 +1251,20 @@ static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) { |
| 1245 | } | 1251 | } |
| 1246 | | 1252 | |
| 1247 | static LLVMValueRef gen_unwrap_maybe(CodeGen *g, AstNode *node, LLVMValueRef maybe_struct_ref) { | 1253 | static LLVMValueRef gen_unwrap_maybe(CodeGen *g, AstNode *node, LLVMValueRef maybe_struct_ref) { |
| 1248 | add_debug_source_node(g, node); | 1254 | TypeTableEntry *type_entry = get_expr_type(node); |
| 1249 | LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, maybe_struct_ref, 0, ""); | 1255 | assert(type_entry->id == TypeTableEntryIdMaybe); |
| 1250 | // TODO if it's a struct we might not want to load the pointer | 1256 | TypeTableEntry *child_type = type_entry->data.maybe.child_type; |
| 1251 | return LLVMBuildLoad(g->builder, maybe_field_ptr, ""); | 1257 | if (child_type->id == TypeTableEntryIdPointer) { |
| | 1258 | return maybe_struct_ref; |
| | 1259 | } else { |
| | 1260 | add_debug_source_node(g, node); |
| | 1261 | LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, maybe_struct_ref, 0, ""); |
| | 1262 | if (handle_is_ptr(child_type)) { |
| | 1263 | return maybe_field_ptr; |
| | 1264 | } else { |
| | 1265 | return LLVMBuildLoad(g->builder, maybe_field_ptr, ""); |
| | 1266 | } |
| | 1267 | } |
| 1252 | } | 1268 | } |
| 1253 | | 1269 | |
| 1254 | static LLVMValueRef gen_unwrap_maybe_expr(CodeGen *g, AstNode *node) { | 1270 | static LLVMValueRef gen_unwrap_maybe_expr(CodeGen *g, AstNode *node) { |
| ... | @@ -1260,29 +1276,32 @@ static LLVMValueRef gen_unwrap_maybe_expr(CodeGen *g, AstNode *node) { | ... | @@ -1260,29 +1276,32 @@ static LLVMValueRef gen_unwrap_maybe_expr(CodeGen *g, AstNode *node) { |
| 1260 | | 1276 | |
| 1261 | LLVMValueRef maybe_struct_ref = gen_expr(g, op1_node); | 1277 | LLVMValueRef maybe_struct_ref = gen_expr(g, op1_node); |
| 1262 | | 1278 | |
| 1263 | add_debug_source_node(g, node); | 1279 | TypeTableEntry *maybe_type = get_expr_type(op1_node); |
| 1264 | LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, maybe_struct_ref, 1, ""); | 1280 | assert(maybe_type->id == TypeTableEntryIdMaybe); |
| 1265 | LLVMValueRef cond_value = LLVMBuildLoad(g->builder, maybe_field_ptr, ""); | 1281 | TypeTableEntry *child_type = maybe_type->data.maybe.child_type; |
| | 1282 | |
| | 1283 | LLVMValueRef cond_value; |
| | 1284 | if (child_type->id == TypeTableEntryIdPointer) { |
| | 1285 | cond_value = LLVMBuildICmp(g->builder, LLVMIntNE, maybe_struct_ref, |
| | 1286 | LLVMConstNull(child_type->type_ref), ""); |
| | 1287 | } else { |
| | 1288 | add_debug_source_node(g, node); |
| | 1289 | LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, maybe_struct_ref, 1, ""); |
| | 1290 | cond_value = LLVMBuildLoad(g->builder, maybe_field_ptr, ""); |
| | 1291 | } |
| 1266 | | 1292 | |
| 1267 | LLVMBasicBlockRef non_null_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeNonNull"); | 1293 | LLVMBasicBlockRef non_null_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeNonNull"); |
| 1268 | LLVMBasicBlockRef null_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeNull"); | 1294 | LLVMBasicBlockRef null_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeNull"); |
| 1269 | LLVMBasicBlockRef end_block; | 1295 | LLVMBasicBlockRef end_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeEnd"); |
| 1270 | | 1296 | |
| 1271 | bool non_null_reachable = get_expr_type(op1_node)->id != TypeTableEntryIdUnreachable; | | |
| 1272 | bool null_reachable = get_expr_type(op2_node)->id != TypeTableEntryIdUnreachable; | 1297 | bool null_reachable = get_expr_type(op2_node)->id != TypeTableEntryIdUnreachable; |
| 1273 | bool end_reachable = non_null_reachable || null_reachable; | | |
| 1274 | if (end_reachable) { | | |
| 1275 | end_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeEnd"); | | |
| 1276 | } | | |
| 1277 | | 1298 | |
| 1278 | LLVMBuildCondBr(g->builder, cond_value, non_null_block, null_block); | 1299 | LLVMBuildCondBr(g->builder, cond_value, non_null_block, null_block); |
| 1279 | | 1300 | |
| 1280 | LLVMPositionBuilderAtEnd(g->builder, non_null_block); | 1301 | LLVMPositionBuilderAtEnd(g->builder, non_null_block); |
| 1281 | LLVMValueRef non_null_result = gen_unwrap_maybe(g, op1_node, maybe_struct_ref); | 1302 | LLVMValueRef non_null_result = gen_unwrap_maybe(g, op1_node, maybe_struct_ref); |
| 1282 | if (non_null_reachable) { | 1303 | add_debug_source_node(g, node); |
| 1283 | add_debug_source_node(g, node); | 1304 | LLVMBuildBr(g->builder, end_block); |
| 1284 | LLVMBuildBr(g->builder, end_block); | | |
| 1285 | } | | |
| 1286 | LLVMBasicBlockRef post_non_null_result_block = LLVMGetInsertBlock(g->builder); | 1305 | LLVMBasicBlockRef post_non_null_result_block = LLVMGetInsertBlock(g->builder); |
| 1287 | | 1306 | |
| 1288 | LLVMPositionBuilderAtEnd(g->builder, null_block); | 1307 | LLVMPositionBuilderAtEnd(g->builder, null_block); |
| ... | @@ -1293,18 +1312,16 @@ static LLVMValueRef gen_unwrap_maybe_expr(CodeGen *g, AstNode *node) { | ... | @@ -1293,18 +1312,16 @@ static LLVMValueRef gen_unwrap_maybe_expr(CodeGen *g, AstNode *node) { |
| 1293 | } | 1312 | } |
| 1294 | LLVMBasicBlockRef post_null_result_block = LLVMGetInsertBlock(g->builder); | 1313 | LLVMBasicBlockRef post_null_result_block = LLVMGetInsertBlock(g->builder); |
| 1295 | | 1314 | |
| 1296 | if (end_reachable) { | 1315 | LLVMPositionBuilderAtEnd(g->builder, end_block); |
| 1297 | LLVMPositionBuilderAtEnd(g->builder, end_block); | 1316 | if (null_reachable) { |
| 1298 | if (null_reachable) { | 1317 | add_debug_source_node(g, node); |
| 1299 | add_debug_source_node(g, node); | 1318 | LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMTypeOf(non_null_result), ""); |
| 1300 | LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMTypeOf(non_null_result), ""); | 1319 | LLVMValueRef incoming_values[2] = {non_null_result, null_result}; |
| 1301 | LLVMValueRef incoming_values[2] = {non_null_result, null_result}; | 1320 | LLVMBasicBlockRef incoming_blocks[2] = {post_non_null_result_block, post_null_result_block}; |
| 1302 | LLVMBasicBlockRef incoming_blocks[2] = {post_non_null_result_block, post_null_result_block}; | 1321 | LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2); |
| 1303 | LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2); | 1322 | return phi; |
| 1304 | return phi; | 1323 | } else { |
| 1305 | } else { | 1324 | return non_null_result; |
| 1306 | return non_null_result; | | |
| 1307 | } | | |
| 1308 | } | 1325 | } |
| 1309 | | 1326 | |
| 1310 | return nullptr; | 1327 | return nullptr; |
| ... | @@ -1607,12 +1624,20 @@ static LLVMValueRef gen_if_var_expr(CodeGen *g, AstNode *node) { | ... | @@ -1607,12 +1624,20 @@ static LLVMValueRef gen_if_var_expr(CodeGen *g, AstNode *node) { |
| 1607 | assert(node->data.if_var_expr.var_decl.expr); | 1624 | assert(node->data.if_var_expr.var_decl.expr); |
| 1608 | | 1625 | |
| 1609 | LLVMValueRef init_val; | 1626 | LLVMValueRef init_val; |
| 1610 | gen_var_decl_raw(g, node, &node->data.if_var_expr.var_decl, true, &init_val); | 1627 | TypeTableEntry *expr_type; |
| | 1628 | gen_var_decl_raw(g, node, &node->data.if_var_expr.var_decl, true, &init_val, &expr_type); |
| 1611 | | 1629 | |
| 1612 | // test if value is the maybe state | 1630 | // test if value is the maybe state |
| 1613 | add_debug_source_node(g, node); | 1631 | assert(expr_type->id == TypeTableEntryIdMaybe); |
| 1614 | LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, init_val, 1, ""); | 1632 | TypeTableEntry *child_type = expr_type->data.maybe.child_type; |
| 1615 | LLVMValueRef cond_value = LLVMBuildLoad(g->builder, maybe_field_ptr, ""); | 1633 | LLVMValueRef cond_value; |
| | 1634 | if (child_type->id == TypeTableEntryIdPointer) { |
| | 1635 | cond_value = LLVMBuildICmp(g->builder, LLVMIntNE, init_val, LLVMConstNull(child_type->type_ref), ""); |
| | 1636 | } else { |
| | 1637 | add_debug_source_node(g, node); |
| | 1638 | LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, init_val, 1, ""); |
| | 1639 | cond_value = LLVMBuildLoad(g->builder, maybe_field_ptr, ""); |
| | 1640 | } |
| 1616 | | 1641 | |
| 1617 | LLVMValueRef return_value = gen_if_bool_expr_raw(g, node, cond_value, | 1642 | LLVMValueRef return_value = gen_if_bool_expr_raw(g, node, cond_value, |
| 1618 | node->data.if_var_expr.then_block, | 1643 | node->data.if_var_expr.then_block, |
| ... | @@ -1978,7 +2003,7 @@ static LLVMValueRef gen_continue(CodeGen *g, AstNode *node) { | ... | @@ -1978,7 +2003,7 @@ static LLVMValueRef gen_continue(CodeGen *g, AstNode *node) { |
| 1978 | } | 2003 | } |
| 1979 | | 2004 | |
| 1980 | static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVariableDeclaration *var_decl, | 2005 | static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVariableDeclaration *var_decl, |
| 1981 | bool unwrap_maybe, LLVMValueRef *init_value) | 2006 | bool unwrap_maybe, LLVMValueRef *init_value, TypeTableEntry **expr_type) |
| 1982 | { | 2007 | { |
| 1983 | VariableTableEntry *variable = var_decl->variable; | 2008 | VariableTableEntry *variable = var_decl->variable; |
| 1984 | | 2009 | |
| ... | @@ -1987,6 +2012,7 @@ static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVa | ... | @@ -1987,6 +2012,7 @@ static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVa |
| 1987 | | 2012 | |
| 1988 | if (var_decl->expr) { | 2013 | if (var_decl->expr) { |
| 1989 | *init_value = gen_expr(g, var_decl->expr); | 2014 | *init_value = gen_expr(g, var_decl->expr); |
| | 2015 | *expr_type = get_expr_type(var_decl->expr); |
| 1990 | } | 2016 | } |
| 1991 | if (variable->type->size_in_bits == 0) { | 2017 | if (variable->type->size_in_bits == 0) { |
| 1992 | return nullptr; | 2018 | return nullptr; |
| ... | @@ -2005,7 +2031,7 @@ static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVa | ... | @@ -2005,7 +2031,7 @@ static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVa |
| 2005 | if (unwrap_maybe) { | 2031 | if (unwrap_maybe) { |
| 2006 | assert(var_decl->expr); | 2032 | assert(var_decl->expr); |
| 2007 | assert(expr_type->id == TypeTableEntryIdMaybe); | 2033 | assert(expr_type->id == TypeTableEntryIdMaybe); |
| 2008 | value = gen_unwrap_maybe(g, source_node, *init_value); | 2034 | value = gen_unwrap_maybe(g, var_decl->expr, *init_value); |
| 2009 | expr_type = expr_type->data.maybe.child_type; | 2035 | expr_type = expr_type->data.maybe.child_type; |
| 2010 | } else { | 2036 | } else { |
| 2011 | value = *init_value; | 2037 | value = *init_value; |
| ... | @@ -2089,7 +2115,8 @@ static LLVMValueRef gen_var_decl_expr(CodeGen *g, AstNode *node) { | ... | @@ -2089,7 +2115,8 @@ static LLVMValueRef gen_var_decl_expr(CodeGen *g, AstNode *node) { |
| 2089 | } | 2115 | } |
| 2090 | | 2116 | |
| 2091 | LLVMValueRef init_val; | 2117 | LLVMValueRef init_val; |
| 2092 | return gen_var_decl_raw(g, node, &node->data.variable_declaration, false, &init_val); | 2118 | TypeTableEntry *init_val_type; |
| | 2119 | return gen_var_decl_raw(g, node, &node->data.variable_declaration, false, &init_val, &init_val_type); |
| 2093 | } | 2120 | } |
| 2094 | | 2121 | |
| 2095 | static LLVMValueRef gen_symbol(CodeGen *g, AstNode *node) { | 2122 | static LLVMValueRef gen_symbol(CodeGen *g, AstNode *node) { |
| ... | @@ -2100,11 +2127,7 @@ static LLVMValueRef gen_symbol(CodeGen *g, AstNode *node) { | ... | @@ -2100,11 +2127,7 @@ static LLVMValueRef gen_symbol(CodeGen *g, AstNode *node) { |
| 2100 | return nullptr; | 2127 | return nullptr; |
| 2101 | } else if (variable->is_ptr) { | 2128 | } else if (variable->is_ptr) { |
| 2102 | assert(variable->value_ref); | 2129 | assert(variable->value_ref); |
| 2103 | if (variable->type->id == TypeTableEntryIdArray) { | 2130 | if (handle_is_ptr(variable->type)) { |
| 2104 | return variable->value_ref; | | |
| 2105 | } else if (variable->type->id == TypeTableEntryIdStruct || | | |
| 2106 | variable->type->id == TypeTableEntryIdMaybe) | | |
| 2107 | { | | |
| 2108 | return variable->value_ref; | 2131 | return variable->value_ref; |
| 2109 | } else { | 2132 | } else { |
| 2110 | add_debug_source_node(g, node); | 2133 | add_debug_source_node(g, node); |
| ... | @@ -2330,20 +2353,28 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE | ... | @@ -2330,20 +2353,28 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE |
| 2330 | case TypeTableEntryIdMaybe: | 2353 | case TypeTableEntryIdMaybe: |
| 2331 | { | 2354 | { |
| 2332 | TypeTableEntry *child_type = type_entry->data.maybe.child_type; | 2355 | TypeTableEntry *child_type = type_entry->data.maybe.child_type; |
| 2333 | LLVMValueRef child_val; | 2356 | if (child_type->id == TypeTableEntryIdPointer) { |
| 2334 | LLVMValueRef maybe_val; | 2357 | if (const_val->data.x_maybe) { |
| 2335 | if (const_val->data.x_maybe) { | 2358 | return gen_const_val(g, child_type, const_val->data.x_maybe); |
| 2336 | child_val = gen_const_val(g, child_type, const_val->data.x_maybe); | 2359 | } else { |
| 2337 | maybe_val = LLVMConstAllOnes(LLVMInt1Type()); | 2360 | return LLVMConstNull(child_type->type_ref); |
| | 2361 | } |
| 2338 | } else { | 2362 | } else { |
| 2339 | child_val = LLVMConstNull(child_type->type_ref); | 2363 | LLVMValueRef child_val; |
| 2340 | maybe_val = LLVMConstNull(LLVMInt1Type()); | 2364 | LLVMValueRef maybe_val; |
| | 2365 | if (const_val->data.x_maybe) { |
| | 2366 | child_val = gen_const_val(g, child_type, const_val->data.x_maybe); |
| | 2367 | maybe_val = LLVMConstAllOnes(LLVMInt1Type()); |
| | 2368 | } else { |
| | 2369 | child_val = LLVMConstNull(child_type->type_ref); |
| | 2370 | maybe_val = LLVMConstNull(LLVMInt1Type()); |
| | 2371 | } |
| | 2372 | LLVMValueRef fields[] = { |
| | 2373 | child_val, |
| | 2374 | maybe_val, |
| | 2375 | }; |
| | 2376 | return LLVMConstStruct(fields, 2, false); |
| 2341 | } | 2377 | } |
| 2342 | LLVMValueRef fields[] = { | | |
| 2343 | child_val, | | |
| 2344 | maybe_val, | | |
| 2345 | }; | | |
| 2346 | return LLVMConstStruct(fields, 2, false); | | |
| 2347 | } | 2378 | } |
| 2348 | case TypeTableEntryIdStruct: | 2379 | case TypeTableEntryIdStruct: |
| 2349 | { | 2380 | { |