authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-10-30 22:11:44-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-10-30 22:11:44-04:00
logef761c2cbc5c9a06da5c09de389a1d778731d170
tree5a3916c4bad25344395cde1913548f800f79aa05
parent6d999abba0fc4470f9bb2dae8997fded9bff60c4
parentca332f57f712c3b4570ca42bc503824022115142
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #13360 from topolarity/comptime-bool-binops

Make `x and false` and `x or true` comptime-known

5 files changed, 120 insertions(+), 29 deletions(-)

src/Sema.zig+16-7
...@@ -15931,12 +15931,10 @@ fn zirBoolBr(...@@ -15931,12 +15931,10 @@ fn zirBoolBr(
15931 const gpa = sema.gpa;15931 const gpa = sema.gpa;
1593215932
15933 if (try sema.resolveDefinedValue(parent_block, lhs_src, lhs)) |lhs_val| {15933 if (try sema.resolveDefinedValue(parent_block, lhs_src, lhs)) |lhs_val| {
15934 if (lhs_val.toBool() == is_bool_or) {15934 if (is_bool_or and lhs_val.toBool()) {
15935 if (is_bool_or) {15935 return Air.Inst.Ref.bool_true;
15936 return Air.Inst.Ref.bool_true;15936 } else if (!is_bool_or and !lhs_val.toBool()) {
15937 } else {15937 return Air.Inst.Ref.bool_false;
15938 return Air.Inst.Ref.bool_false;
15939 }
15940 }15938 }
15941 // comptime-known left-hand side. No need for a block here; the result15939 // comptime-known left-hand side. No need for a block here; the result
15942 // is simply the rhs expression. Here we rely on there only being 115940 // is simply the rhs expression. Here we rely on there only being 1
...@@ -15976,7 +15974,18 @@ fn zirBoolBr(...@@ -15976,7 +15974,18 @@ fn zirBoolBr(
15976 _ = try rhs_block.addBr(block_inst, rhs_result);15974 _ = try rhs_block.addBr(block_inst, rhs_result);
15977 }15975 }
1597815976
15979 return finishCondBr(sema, parent_block, &child_block, &then_block, &else_block, lhs, block_inst);15977 const result = finishCondBr(sema, parent_block, &child_block, &then_block, &else_block, lhs, block_inst);
15978 if (!sema.typeOf(rhs_result).isNoReturn()) {
15979 if (try sema.resolveDefinedValue(rhs_block, sema.src, rhs_result)) |rhs_val| {
15980 if (is_bool_or and rhs_val.toBool()) {
15981 return Air.Inst.Ref.bool_true;
15982 } else if (!is_bool_or and !rhs_val.toBool()) {
15983 return Air.Inst.Ref.bool_false;
15984 }
15985 }
15986 }
15987
15988 return result;
15980}15989}
1598115990
15982fn finishCondBr(15991fn finishCondBr(
src/stage1/all_types.hpp+1
...@@ -2922,6 +2922,7 @@ struct Stage1ZirInstPhi {...@@ -2922,6 +2922,7 @@ struct Stage1ZirInstPhi {
2922 Stage1ZirInst base;2922 Stage1ZirInst base;
29232923
2924 size_t incoming_count;2924 size_t incoming_count;
2925 bool merge_comptime;
2925 Stage1ZirBasicBlock **incoming_blocks;2926 Stage1ZirBasicBlock **incoming_blocks;
2926 Stage1ZirInst **incoming_values;2927 Stage1ZirInst **incoming_values;
2927 ResultLocPeerParent *peer_parent;2928 ResultLocPeerParent *peer_parent;
src/stage1/astgen.cpp+22-17
...@@ -1304,7 +1304,7 @@ static Stage1ZirInst *ir_build_call_src(Stage1AstGen *ag, Scope *scope, AstNode...@@ -1304,7 +1304,7 @@ static Stage1ZirInst *ir_build_call_src(Stage1AstGen *ag, Scope *scope, AstNode
1304 return &call_instruction->base;1304 return &call_instruction->base;
1305}1305}
13061306
1307static Stage1ZirInst *ir_build_phi(Stage1AstGen *ag, Scope *scope, AstNode *source_node,1307static Stage1ZirInst *ir_build_phi(Stage1AstGen *ag, Scope *scope, AstNode *source_node, bool merge_comptime,
1308 size_t incoming_count, Stage1ZirBasicBlock **incoming_blocks, Stage1ZirInst **incoming_values,1308 size_t incoming_count, Stage1ZirBasicBlock **incoming_blocks, Stage1ZirInst **incoming_values,
1309 ResultLocPeerParent *peer_parent)1309 ResultLocPeerParent *peer_parent)
1310{1310{
...@@ -1316,6 +1316,7 @@ static Stage1ZirInst *ir_build_phi(Stage1AstGen *ag, Scope *scope, AstNode *sour...@@ -1316,6 +1316,7 @@ static Stage1ZirInst *ir_build_phi(Stage1AstGen *ag, Scope *scope, AstNode *sour
1316 phi_instruction->incoming_blocks = incoming_blocks;1316 phi_instruction->incoming_blocks = incoming_blocks;
1317 phi_instruction->incoming_values = incoming_values;1317 phi_instruction->incoming_values = incoming_values;
1318 phi_instruction->peer_parent = peer_parent;1318 phi_instruction->peer_parent = peer_parent;
1319 phi_instruction->merge_comptime = merge_comptime;
13191320
1320 for (size_t i = 0; i < incoming_count; i += 1) {1321 for (size_t i = 0; i < incoming_count; i += 1) {
1321 ir_ref_bb(incoming_blocks[i]);1322 ir_ref_bb(incoming_blocks[i]);
...@@ -3393,7 +3394,7 @@ static Stage1ZirInst *astgen_block(Stage1AstGen *ag, Scope *parent_scope, AstNod...@@ -3393,7 +3394,7 @@ static Stage1ZirInst *astgen_block(Stage1AstGen *ag, Scope *parent_scope, AstNod
3393 scope_block->peer_parent->peers.last()->next_bb = scope_block->end_block;3394 scope_block->peer_parent->peers.last()->next_bb = scope_block->end_block;
3394 }3395 }
3395 ir_set_cursor_at_end_and_append_block(ag, scope_block->end_block);3396 ir_set_cursor_at_end_and_append_block(ag, scope_block->end_block);
3396 Stage1ZirInst *phi = ir_build_phi(ag, parent_scope, block_node, incoming_blocks.length,3397 Stage1ZirInst *phi = ir_build_phi(ag, parent_scope, block_node, false, incoming_blocks.length,
3397 incoming_blocks.items, incoming_values.items, scope_block->peer_parent);3398 incoming_blocks.items, incoming_values.items, scope_block->peer_parent);
3398 return ir_expr_wrap(ag, parent_scope, phi, result_loc);3399 return ir_expr_wrap(ag, parent_scope, phi, result_loc);
3399 } else {3400 } else {
...@@ -3423,7 +3424,7 @@ static Stage1ZirInst *astgen_block(Stage1AstGen *ag, Scope *parent_scope, AstNod...@@ -3423,7 +3424,7 @@ static Stage1ZirInst *astgen_block(Stage1AstGen *ag, Scope *parent_scope, AstNod
3423 if (block_node->data.block.name != nullptr) {3424 if (block_node->data.block.name != nullptr) {
3424 ir_build_br(ag, parent_scope, block_node, scope_block->end_block, scope_block->is_comptime);3425 ir_build_br(ag, parent_scope, block_node, scope_block->end_block, scope_block->is_comptime);
3425 ir_set_cursor_at_end_and_append_block(ag, scope_block->end_block);3426 ir_set_cursor_at_end_and_append_block(ag, scope_block->end_block);
3426 Stage1ZirInst *phi = ir_build_phi(ag, parent_scope, block_node, incoming_blocks.length,3427 Stage1ZirInst *phi = ir_build_phi(ag, parent_scope, block_node, false, incoming_blocks.length,
3427 incoming_blocks.items, incoming_values.items, scope_block->peer_parent);3428 incoming_blocks.items, incoming_values.items, scope_block->peer_parent);
3428 result = ir_expr_wrap(ag, parent_scope, phi, result_loc);3429 result = ir_expr_wrap(ag, parent_scope, phi, result_loc);
3429 } else {3430 } else {
...@@ -3527,6 +3528,7 @@ static Stage1ZirInst *astgen_bool_or(Stage1AstGen *ag, Scope *scope, AstNode *no...@@ -3527,6 +3528,7 @@ static Stage1ZirInst *astgen_bool_or(Stage1AstGen *ag, Scope *scope, AstNode *no
3527 // block for when val1 == true (don't even evaluate the second part)3528 // block for when val1 == true (don't even evaluate the second part)
3528 Stage1ZirBasicBlock *true_block = ir_create_basic_block(ag, scope, "BoolOrTrue");3529 Stage1ZirBasicBlock *true_block = ir_create_basic_block(ag, scope, "BoolOrTrue");
35293530
3531 Stage1ZirInst *val1_true = ir_build_const_bool(ag, scope, node, true);
3530 ir_build_cond_br(ag, scope, node, val1, true_block, false_block, is_comptime);3532 ir_build_cond_br(ag, scope, node, val1, true_block, false_block, is_comptime);
35313533
3532 ir_set_cursor_at_end_and_append_block(ag, false_block);3534 ir_set_cursor_at_end_and_append_block(ag, false_block);
...@@ -3540,13 +3542,14 @@ static Stage1ZirInst *astgen_bool_or(Stage1AstGen *ag, Scope *scope, AstNode *no...@@ -3540,13 +3542,14 @@ static Stage1ZirInst *astgen_bool_or(Stage1AstGen *ag, Scope *scope, AstNode *no
3540 ir_set_cursor_at_end_and_append_block(ag, true_block);3542 ir_set_cursor_at_end_and_append_block(ag, true_block);
35413543
3542 Stage1ZirInst **incoming_values = heap::c_allocator.allocate<Stage1ZirInst *>(2);3544 Stage1ZirInst **incoming_values = heap::c_allocator.allocate<Stage1ZirInst *>(2);
3543 incoming_values[0] = val1;3545 incoming_values[0] = val1_true;
3544 incoming_values[1] = val2;3546 incoming_values[1] = val2;
3545 Stage1ZirBasicBlock **incoming_blocks = heap::c_allocator.allocate<Stage1ZirBasicBlock *>(2);3547 Stage1ZirBasicBlock **incoming_blocks = heap::c_allocator.allocate<Stage1ZirBasicBlock *>(2);
3546 incoming_blocks[0] = post_val1_block;3548 incoming_blocks[0] = post_val1_block;
3547 incoming_blocks[1] = post_val2_block;3549 incoming_blocks[1] = post_val2_block;
35483550
3549 return ir_build_phi(ag, scope, node, 2, incoming_blocks, incoming_values, nullptr);3551 const bool merge_comptime = true;
3552 return ir_build_phi(ag, scope, node, merge_comptime, 2, incoming_blocks, incoming_values, nullptr);
3550}3553}
35513554
3552static Stage1ZirInst *astgen_bool_and(Stage1AstGen *ag, Scope *scope, AstNode *node) {3555static Stage1ZirInst *astgen_bool_and(Stage1AstGen *ag, Scope *scope, AstNode *node) {
...@@ -3569,6 +3572,7 @@ static Stage1ZirInst *astgen_bool_and(Stage1AstGen *ag, Scope *scope, AstNode *n...@@ -3569,6 +3572,7 @@ static Stage1ZirInst *astgen_bool_and(Stage1AstGen *ag, Scope *scope, AstNode *n
3569 // block for when val1 == false (don't even evaluate the second part)3572 // block for when val1 == false (don't even evaluate the second part)
3570 Stage1ZirBasicBlock *false_block = ir_create_basic_block(ag, scope, "BoolAndFalse");3573 Stage1ZirBasicBlock *false_block = ir_create_basic_block(ag, scope, "BoolAndFalse");
35713574
3575 Stage1ZirInst *val1_false = ir_build_const_bool(ag, scope, node, false);
3572 ir_build_cond_br(ag, scope, node, val1, true_block, false_block, is_comptime);3576 ir_build_cond_br(ag, scope, node, val1, true_block, false_block, is_comptime);
35733577
3574 ir_set_cursor_at_end_and_append_block(ag, true_block);3578 ir_set_cursor_at_end_and_append_block(ag, true_block);
...@@ -3582,13 +3586,14 @@ static Stage1ZirInst *astgen_bool_and(Stage1AstGen *ag, Scope *scope, AstNode *n...@@ -3582,13 +3586,14 @@ static Stage1ZirInst *astgen_bool_and(Stage1AstGen *ag, Scope *scope, AstNode *n
3582 ir_set_cursor_at_end_and_append_block(ag, false_block);3586 ir_set_cursor_at_end_and_append_block(ag, false_block);
35833587
3584 Stage1ZirInst **incoming_values = heap::c_allocator.allocate<Stage1ZirInst *>(2);3588 Stage1ZirInst **incoming_values = heap::c_allocator.allocate<Stage1ZirInst *>(2);
3585 incoming_values[0] = val1;3589 incoming_values[0] = val1_false;
3586 incoming_values[1] = val2;3590 incoming_values[1] = val2;
3587 Stage1ZirBasicBlock **incoming_blocks = heap::c_allocator.allocate<Stage1ZirBasicBlock *>(2);3591 Stage1ZirBasicBlock **incoming_blocks = heap::c_allocator.allocate<Stage1ZirBasicBlock *>(2);
3588 incoming_blocks[0] = post_val1_block;3592 incoming_blocks[0] = post_val1_block;
3589 incoming_blocks[1] = post_val2_block;3593 incoming_blocks[1] = post_val2_block;
35903594
3591 return ir_build_phi(ag, scope, node, 2, incoming_blocks, incoming_values, nullptr);3595 const bool merge_comptime = true;
3596 return ir_build_phi(ag, scope, node, merge_comptime, 2, incoming_blocks, incoming_values, nullptr);
3592}3597}
35933598
3594static ResultLocPeerParent *ir_build_result_peers(Stage1AstGen *ag, Stage1ZirInst *cond_br_inst,3599static ResultLocPeerParent *ir_build_result_peers(Stage1AstGen *ag, Stage1ZirInst *cond_br_inst,
...@@ -3678,7 +3683,7 @@ static Stage1ZirInst *astgen_orelse(Stage1AstGen *ag, Scope *parent_scope, AstNo...@@ -3678,7 +3683,7 @@ static Stage1ZirInst *astgen_orelse(Stage1AstGen *ag, Scope *parent_scope, AstNo
3678 Stage1ZirBasicBlock **incoming_blocks = heap::c_allocator.allocate<Stage1ZirBasicBlock *>(2);3683 Stage1ZirBasicBlock **incoming_blocks = heap::c_allocator.allocate<Stage1ZirBasicBlock *>(2);
3679 incoming_blocks[0] = after_null_block;3684 incoming_blocks[0] = after_null_block;
3680 incoming_blocks[1] = after_ok_block;3685 incoming_blocks[1] = after_ok_block;
3681 Stage1ZirInst *phi = ir_build_phi(ag, parent_scope, node, 2, incoming_blocks, incoming_values, peer_parent);3686 Stage1ZirInst *phi = ir_build_phi(ag, parent_scope, node, false, 2, incoming_blocks, incoming_values, peer_parent);
3682 return ir_lval_wrap(ag, parent_scope, phi, lval, result_loc);3687 return ir_lval_wrap(ag, parent_scope, phi, lval, result_loc);
3683}3688}
36843689
...@@ -5589,7 +5594,7 @@ static Stage1ZirInst *astgen_if_bool_expr(Stage1AstGen *ag, Scope *scope, AstNod...@@ -5589,7 +5594,7 @@ static Stage1ZirInst *astgen_if_bool_expr(Stage1AstGen *ag, Scope *scope, AstNod
5589 incoming_blocks[0] = after_then_block;5594 incoming_blocks[0] = after_then_block;
5590 incoming_blocks[1] = after_else_block;5595 incoming_blocks[1] = after_else_block;
55915596
5592 Stage1ZirInst *phi = ir_build_phi(ag, scope, node, 2, incoming_blocks, incoming_values, peer_parent);5597 Stage1ZirInst *phi = ir_build_phi(ag, scope, node, false, 2, incoming_blocks, incoming_values, peer_parent);
5593 return ir_expr_wrap(ag, scope, phi, result_loc);5598 return ir_expr_wrap(ag, scope, phi, result_loc);
5594}5599}
55955600
...@@ -6224,7 +6229,7 @@ static Stage1ZirInst *astgen_while_expr(Stage1AstGen *ag, Scope *scope, AstNode...@@ -6224,7 +6229,7 @@ static Stage1ZirInst *astgen_while_expr(Stage1AstGen *ag, Scope *scope, AstNode
6224 peer_parent->peers.last()->next_bb = end_block;6229 peer_parent->peers.last()->next_bb = end_block;
6225 }6230 }
62266231
6227 Stage1ZirInst *phi = ir_build_phi(ag, scope, node, incoming_blocks.length,6232 Stage1ZirInst *phi = ir_build_phi(ag, scope, node, false, incoming_blocks.length,
6228 incoming_blocks.items, incoming_values.items, peer_parent);6233 incoming_blocks.items, incoming_values.items, peer_parent);
6229 return ir_expr_wrap(ag, scope, phi, result_loc);6234 return ir_expr_wrap(ag, scope, phi, result_loc);
6230 } else if (var_symbol != nullptr) {6235 } else if (var_symbol != nullptr) {
...@@ -6334,7 +6339,7 @@ static Stage1ZirInst *astgen_while_expr(Stage1AstGen *ag, Scope *scope, AstNode...@@ -6334,7 +6339,7 @@ static Stage1ZirInst *astgen_while_expr(Stage1AstGen *ag, Scope *scope, AstNode
6334 peer_parent->peers.last()->next_bb = end_block;6339 peer_parent->peers.last()->next_bb = end_block;
6335 }6340 }
63366341
6337 Stage1ZirInst *phi = ir_build_phi(ag, scope, node, incoming_blocks.length,6342 Stage1ZirInst *phi = ir_build_phi(ag, scope, node, false, incoming_blocks.length,
6338 incoming_blocks.items, incoming_values.items, peer_parent);6343 incoming_blocks.items, incoming_values.items, peer_parent);
6339 return ir_expr_wrap(ag, scope, phi, result_loc);6344 return ir_expr_wrap(ag, scope, phi, result_loc);
6340 } else {6345 } else {
...@@ -6430,7 +6435,7 @@ static Stage1ZirInst *astgen_while_expr(Stage1AstGen *ag, Scope *scope, AstNode...@@ -6430,7 +6435,7 @@ static Stage1ZirInst *astgen_while_expr(Stage1AstGen *ag, Scope *scope, AstNode
6430 peer_parent->peers.last()->next_bb = end_block;6435 peer_parent->peers.last()->next_bb = end_block;
6431 }6436 }
64326437
6433 Stage1ZirInst *phi = ir_build_phi(ag, scope, node, incoming_blocks.length,6438 Stage1ZirInst *phi = ir_build_phi(ag, scope, node, false, incoming_blocks.length,
6434 incoming_blocks.items, incoming_values.items, peer_parent);6439 incoming_blocks.items, incoming_values.items, peer_parent);
6435 return ir_expr_wrap(ag, scope, phi, result_loc);6440 return ir_expr_wrap(ag, scope, phi, result_loc);
6436 }6441 }
...@@ -6582,7 +6587,7 @@ static Stage1ZirInst *astgen_for_expr(Stage1AstGen *ag, Scope *parent_scope, Ast...@@ -6582,7 +6587,7 @@ static Stage1ZirInst *astgen_for_expr(Stage1AstGen *ag, Scope *parent_scope, Ast
6582 peer_parent->peers.last()->next_bb = end_block;6587 peer_parent->peers.last()->next_bb = end_block;
6583 }6588 }
65846589
6585 Stage1ZirInst *phi = ir_build_phi(ag, parent_scope, node, incoming_blocks.length,6590 Stage1ZirInst *phi = ir_build_phi(ag, parent_scope, node, false, incoming_blocks.length,
6586 incoming_blocks.items, incoming_values.items, peer_parent);6591 incoming_blocks.items, incoming_values.items, peer_parent);
6587 return ir_lval_wrap(ag, parent_scope, phi, lval, result_loc);6592 return ir_lval_wrap(ag, parent_scope, phi, lval, result_loc);
6588}6593}
...@@ -6910,7 +6915,7 @@ static Stage1ZirInst *astgen_if_optional_expr(Stage1AstGen *ag, Scope *scope, As...@@ -6910,7 +6915,7 @@ static Stage1ZirInst *astgen_if_optional_expr(Stage1AstGen *ag, Scope *scope, As
6910 incoming_blocks[0] = after_then_block;6915 incoming_blocks[0] = after_then_block;
6911 incoming_blocks[1] = after_else_block;6916 incoming_blocks[1] = after_else_block;
69126917
6913 Stage1ZirInst *phi = ir_build_phi(ag, scope, node, 2, incoming_blocks, incoming_values, peer_parent);6918 Stage1ZirInst *phi = ir_build_phi(ag, scope, node, false, 2, incoming_blocks, incoming_values, peer_parent);
6914 return ir_expr_wrap(ag, scope, phi, result_loc);6919 return ir_expr_wrap(ag, scope, phi, result_loc);
6915}6920}
69166921
...@@ -7008,7 +7013,7 @@ static Stage1ZirInst *astgen_if_err_expr(Stage1AstGen *ag, Scope *scope, AstNode...@@ -7008,7 +7013,7 @@ static Stage1ZirInst *astgen_if_err_expr(Stage1AstGen *ag, Scope *scope, AstNode
7008 incoming_blocks[0] = after_then_block;7013 incoming_blocks[0] = after_then_block;
7009 incoming_blocks[1] = after_else_block;7014 incoming_blocks[1] = after_else_block;
70107015
7011 Stage1ZirInst *phi = ir_build_phi(ag, scope, node, 2, incoming_blocks, incoming_values, peer_parent);7016 Stage1ZirInst *phi = ir_build_phi(ag, scope, node, false, 2, incoming_blocks, incoming_values, peer_parent);
7012 return ir_expr_wrap(ag, scope, phi, result_loc);7017 return ir_expr_wrap(ag, scope, phi, result_loc);
7013}7018}
70147019
...@@ -7344,7 +7349,7 @@ static Stage1ZirInst *astgen_switch_expr(Stage1AstGen *ag, Scope *scope, AstNode...@@ -7344,7 +7349,7 @@ static Stage1ZirInst *astgen_switch_expr(Stage1AstGen *ag, Scope *scope, AstNode
7344 if (incoming_blocks.length == 0) {7349 if (incoming_blocks.length == 0) {
7345 result_instruction = ir_build_const_void(ag, scope, node);7350 result_instruction = ir_build_const_void(ag, scope, node);
7346 } else {7351 } else {
7347 result_instruction = ir_build_phi(ag, scope, node, incoming_blocks.length,7352 result_instruction = ir_build_phi(ag, scope, node, false, incoming_blocks.length,
7348 incoming_blocks.items, incoming_values.items, peer_parent);7353 incoming_blocks.items, incoming_values.items, peer_parent);
7349 }7354 }
7350 return ir_lval_wrap(ag, scope, result_instruction, lval, result_loc);7355 return ir_lval_wrap(ag, scope, result_instruction, lval, result_loc);
...@@ -7671,7 +7676,7 @@ static Stage1ZirInst *astgen_catch(Stage1AstGen *ag, Scope *parent_scope, AstNod...@@ -7671,7 +7676,7 @@ static Stage1ZirInst *astgen_catch(Stage1AstGen *ag, Scope *parent_scope, AstNod
7671 Stage1ZirBasicBlock **incoming_blocks = heap::c_allocator.allocate<Stage1ZirBasicBlock *>(2);7676 Stage1ZirBasicBlock **incoming_blocks = heap::c_allocator.allocate<Stage1ZirBasicBlock *>(2);
7672 incoming_blocks[0] = after_err_block;7677 incoming_blocks[0] = after_err_block;
7673 incoming_blocks[1] = after_ok_block;7678 incoming_blocks[1] = after_ok_block;
7674 Stage1ZirInst *phi = ir_build_phi(ag, parent_scope, node, 2, incoming_blocks, incoming_values, peer_parent);7679 Stage1ZirInst *phi = ir_build_phi(ag, parent_scope, node, false, 2, incoming_blocks, incoming_values, peer_parent);
7675 return ir_lval_wrap(ag, parent_scope, phi, lval, result_loc);7680 return ir_lval_wrap(ag, parent_scope, phi, lval, result_loc);
7676}7681}
76777682
src/stage1/ir.cpp+31-5
...@@ -1318,12 +1318,37 @@ static Stage1AirInstCall *ir_build_call_gen(IrAnalyze *ira, Scope *scope, AstNod...@@ -1318,12 +1318,37 @@ static Stage1AirInstCall *ir_build_call_gen(IrAnalyze *ira, Scope *scope, AstNod
1318 return call_instruction;1318 return call_instruction;
1319}1319}
13201320
1321static Stage1AirInst *ir_build_phi_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, size_t incoming_count,1321static Stage1AirInst *ir_build_phi_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, bool merge_comptime,
1322 Stage1AirBasicBlock **incoming_blocks, Stage1AirInst **incoming_values, ZigType *result_type)1322 size_t incoming_count, Stage1AirBasicBlock **incoming_blocks, Stage1AirInst **incoming_values, ZigType *result_type)
1323{1323{
1324 assert(incoming_count != 0);1324 assert(incoming_count != 0);
1325 assert(incoming_count != SIZE_MAX);1325 assert(incoming_count != SIZE_MAX);
13261326
1327 if (merge_comptime && instr_is_comptime(incoming_values[incoming_count - 1])) {
1328 // We need to check whether all the merged values are comptime-known and equal.
1329 // If so, we elide the runtime phi and replace it with any of the identical comptime-known values.
1330 ZigValue *comptime_value = ir_resolve_const(ira, incoming_values[incoming_count - 1], UndefOk);
1331 if (comptime_value == nullptr)
1332 return ira->codegen->invalid_inst_gen;
1333
1334 for (size_t i = incoming_count - 1; i > 0;) {
1335 i -= 1;
1336 if (!instr_is_comptime(incoming_values[i])) {
1337 comptime_value = nullptr;
1338 break;
1339 }
1340 ZigValue *value = ir_resolve_const(ira, incoming_values[i], UndefOk);
1341 if (value == nullptr)
1342 return ira->codegen->invalid_inst_gen;
1343 if (!const_values_equal(ira->codegen, comptime_value, value)) {
1344 comptime_value = nullptr;
1345 break;
1346 }
1347 }
1348 if (comptime_value != nullptr)
1349 return incoming_values[0];
1350 }
1351
1327 Stage1AirInstPhi *phi_instruction = ir_build_inst_gen<Stage1AirInstPhi>(&ira->new_irb,1352 Stage1AirInstPhi *phi_instruction = ir_build_inst_gen<Stage1AirInstPhi>(&ira->new_irb,
1328 scope, source_node);1353 scope, source_node);
1329 phi_instruction->base.value->type = result_type;1354 phi_instruction->base.value->type = result_type;
...@@ -9592,7 +9617,8 @@ static Stage1AirInst *ir_evaluate_cmp_optional_non_optional(IrAnalyze *ira, Scop...@@ -9592,7 +9617,8 @@ static Stage1AirInst *ir_evaluate_cmp_optional_non_optional(IrAnalyze *ira, Scop
9592 incoming_values[0] = null_result;9617 incoming_values[0] = null_result;
9593 incoming_values[1] = non_null_cmp_result;9618 incoming_values[1] = non_null_cmp_result;
95949619
9595 return ir_build_phi_gen(ira, scope, source_node, incoming_count, incoming_blocks, incoming_values, result_type);9620 const bool merge_comptime = false;
9621 return ir_build_phi_gen(ira, scope, source_node, merge_comptime, incoming_count, incoming_blocks, incoming_values, result_type);
9596}9622}
95979623
9598static Stage1AirInst *ir_analyze_cmp_optional_non_optional(IrAnalyze *ira, Scope *scope, AstNode *source_node,9624static Stage1AirInst *ir_analyze_cmp_optional_non_optional(IrAnalyze *ira, Scope *scope, AstNode *source_node,
...@@ -14757,8 +14783,8 @@ static Stage1AirInst *ir_analyze_instruction_phi(IrAnalyze *ira, Stage1ZirInstPh...@@ -14757,8 +14783,8 @@ static Stage1AirInst *ir_analyze_instruction_phi(IrAnalyze *ira, Stage1ZirInstPh
14757 ir_set_cursor_at_end_gen(&ira->new_irb, cur_bb);14783 ir_set_cursor_at_end_gen(&ira->new_irb, cur_bb);
1475814784
14759 Stage1AirInst *result = ir_build_phi_gen(ira, phi_instruction->base.scope,14785 Stage1AirInst *result = ir_build_phi_gen(ira, phi_instruction->base.scope,
14760 phi_instruction->base.source_node, new_incoming_blocks.length,14786 phi_instruction->base.source_node, phi_instruction->merge_comptime,
14761 new_incoming_blocks.items, new_incoming_values.items, resolved_type);14787 new_incoming_blocks.length, new_incoming_blocks.items, new_incoming_values.items, resolved_type);
1476214788
14763 if (all_stack_ptrs) {14789 if (all_stack_ptrs) {
14764 assert(result->value->special == ConstValSpecialRuntime);14790 assert(result->value->special == ConstValSpecialRuntime);
test/behavior/eval.zig+50
...@@ -1438,3 +1438,53 @@ test "continue nested inline for loop in named block expr" {...@@ -1438,3 +1438,53 @@ test "continue nested inline for loop in named block expr" {
1438 }1438 }
1439 try expect(a == 2);1439 try expect(a == 2);
1440}1440}
1441
1442test "x and false is comptime-known false" {
1443 const T = struct {
1444 var x: u32 = 0;
1445
1446 fn foo() bool {
1447 x += 1; // Observable side-effect
1448 return true;
1449 }
1450 };
1451
1452 if (T.foo() and T.foo() and false and T.foo()) {
1453 @compileError("Condition should be comptime-known false");
1454 }
1455 try expect(T.x == 2);
1456
1457 T.x = 0;
1458 if (T.foo() and T.foo() and b: {
1459 _ = T.foo();
1460 break :b false;
1461 } and T.foo()) {
1462 @compileError("Condition should be comptime-known false");
1463 }
1464 try expect(T.x == 3);
1465}
1466
1467test "x or true is comptime-known true" {
1468 const T = struct {
1469 var x: u32 = 0;
1470
1471 fn foo() bool {
1472 x += 1; // Observable side-effect
1473 return false;
1474 }
1475 };
1476
1477 if (!(T.foo() or T.foo() or true or T.foo())) {
1478 @compileError("Condition should be comptime-known false");
1479 }
1480 try expect(T.x == 2);
1481
1482 T.x = 0;
1483 if (!(T.foo() or T.foo() or b: {
1484 _ = T.foo();
1485 break :b true;
1486 } or T.foo())) {
1487 @compileError("Condition should be comptime-known false");
1488 }
1489 try expect(T.x == 3);
1490}