authorgravatar for topolarity@tapscott.meCody Tapscott <topolarity@tapscott.me> 2022-10-30 12:21:37-07:00
committergravatar for topolarity@tapscott.meCody Tapscott <topolarity@tapscott.me> 2022-10-30 12:21:37-07:00
log2f732deb3d15752d4977f04b38718e6896460e69
tree89debe4afe10b7d48a207ff07066218493dac53a
parent1696434063dd6b09af93fbab04727f91397e2e00

stage1: Make `x and false`/`x or true` comptime-known

We need to be careful to respect side-effects/branching in these cases, but otherwise this behaves very similarly to multiplication. `lhs and rhs == false` if either lhs or rhs is comptime-known `false`, just like `lhs * rhs == 0` if either lhs or rhs is comptime-known to be zero. Similar reasoning applies to `lhs or rhs`.

3 files changed, 54 insertions(+), 22 deletions(-)

src/stage1/all_types.hpp+1
......@@ -2922,6 +2922,7 @@ struct Stage1ZirInstPhi {
29222922 Stage1ZirInst base;
29232923
29242924 size_t incoming_count;
2925 bool merge_comptime;
29252926 Stage1ZirBasicBlock **incoming_blocks;
29262927 Stage1ZirInst **incoming_values;
29272928 ResultLocPeerParent *peer_parent;
src/stage1/astgen.cpp+22-17
......@@ -1304,7 +1304,7 @@ static Stage1ZirInst *ir_build_call_src(Stage1AstGen *ag, Scope *scope, AstNode
13041304 return &call_instruction->base;
13051305}
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,
13081308 size_t incoming_count, Stage1ZirBasicBlock **incoming_blocks, Stage1ZirInst **incoming_values,
13091309 ResultLocPeerParent *peer_parent)
13101310{
......@@ -1316,6 +1316,7 @@ static Stage1ZirInst *ir_build_phi(Stage1AstGen *ag, Scope *scope, AstNode *sour
13161316 phi_instruction->incoming_blocks = incoming_blocks;
13171317 phi_instruction->incoming_values = incoming_values;
13181318 phi_instruction->peer_parent = peer_parent;
1319 phi_instruction->merge_comptime = merge_comptime;
13191320
13201321 for (size_t i = 0; i < incoming_count; i += 1) {
13211322 ir_ref_bb(incoming_blocks[i]);
......@@ -3393,7 +3394,7 @@ static Stage1ZirInst *astgen_block(Stage1AstGen *ag, Scope *parent_scope, AstNod
33933394 scope_block->peer_parent->peers.last()->next_bb = scope_block->end_block;
33943395 }
33953396 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,
33973398 incoming_blocks.items, incoming_values.items, scope_block->peer_parent);
33983399 return ir_expr_wrap(ag, parent_scope, phi, result_loc);
33993400 } else {
......@@ -3423,7 +3424,7 @@ static Stage1ZirInst *astgen_block(Stage1AstGen *ag, Scope *parent_scope, AstNod
34233424 if (block_node->data.block.name != nullptr) {
34243425 ir_build_br(ag, parent_scope, block_node, scope_block->end_block, scope_block->is_comptime);
34253426 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,
34273428 incoming_blocks.items, incoming_values.items, scope_block->peer_parent);
34283429 result = ir_expr_wrap(ag, parent_scope, phi, result_loc);
34293430 } else {
......@@ -3527,6 +3528,7 @@ static Stage1ZirInst *astgen_bool_or(Stage1AstGen *ag, Scope *scope, AstNode *no
35273528 // block for when val1 == true (don't even evaluate the second part)
35283529 Stage1ZirBasicBlock *true_block = ir_create_basic_block(ag, scope, "BoolOrTrue");
35293530
3531 Stage1ZirInst *val1_true = ir_build_const_bool(ag, scope, node, true);
35303532 ir_build_cond_br(ag, scope, node, val1, true_block, false_block, is_comptime);
35313533
35323534 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
35403542 ir_set_cursor_at_end_and_append_block(ag, true_block);
35413543
35423544 Stage1ZirInst **incoming_values = heap::c_allocator.allocate<Stage1ZirInst *>(2);
3543 incoming_values[0] = val1;
3545 incoming_values[0] = val1_true;
35443546 incoming_values[1] = val2;
35453547 Stage1ZirBasicBlock **incoming_blocks = heap::c_allocator.allocate<Stage1ZirBasicBlock *>(2);
35463548 incoming_blocks[0] = post_val1_block;
35473549 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);
35503553}
35513554
35523555static 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
35693572 // block for when val1 == false (don't even evaluate the second part)
35703573 Stage1ZirBasicBlock *false_block = ir_create_basic_block(ag, scope, "BoolAndFalse");
35713574
3575 Stage1ZirInst *val1_false = ir_build_const_bool(ag, scope, node, false);
35723576 ir_build_cond_br(ag, scope, node, val1, true_block, false_block, is_comptime);
35733577
35743578 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
35823586 ir_set_cursor_at_end_and_append_block(ag, false_block);
35833587
35843588 Stage1ZirInst **incoming_values = heap::c_allocator.allocate<Stage1ZirInst *>(2);
3585 incoming_values[0] = val1;
3589 incoming_values[0] = val1_false;
35863590 incoming_values[1] = val2;
35873591 Stage1ZirBasicBlock **incoming_blocks = heap::c_allocator.allocate<Stage1ZirBasicBlock *>(2);
35883592 incoming_blocks[0] = post_val1_block;
35893593 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);
35923597}
35933598
35943599static 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
36783683 Stage1ZirBasicBlock **incoming_blocks = heap::c_allocator.allocate<Stage1ZirBasicBlock *>(2);
36793684 incoming_blocks[0] = after_null_block;
36803685 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);
36823687 return ir_lval_wrap(ag, parent_scope, phi, lval, result_loc);
36833688}
36843689
......@@ -5589,7 +5594,7 @@ static Stage1ZirInst *astgen_if_bool_expr(Stage1AstGen *ag, Scope *scope, AstNod
55895594 incoming_blocks[0] = after_then_block;
55905595 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);
55935598 return ir_expr_wrap(ag, scope, phi, result_loc);
55945599}
55955600
......@@ -6224,7 +6229,7 @@ static Stage1ZirInst *astgen_while_expr(Stage1AstGen *ag, Scope *scope, AstNode
62246229 peer_parent->peers.last()->next_bb = end_block;
62256230 }
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,
62286233 incoming_blocks.items, incoming_values.items, peer_parent);
62296234 return ir_expr_wrap(ag, scope, phi, result_loc);
62306235 } else if (var_symbol != nullptr) {
......@@ -6334,7 +6339,7 @@ static Stage1ZirInst *astgen_while_expr(Stage1AstGen *ag, Scope *scope, AstNode
63346339 peer_parent->peers.last()->next_bb = end_block;
63356340 }
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,
63386343 incoming_blocks.items, incoming_values.items, peer_parent);
63396344 return ir_expr_wrap(ag, scope, phi, result_loc);
63406345 } else {
......@@ -6430,7 +6435,7 @@ static Stage1ZirInst *astgen_while_expr(Stage1AstGen *ag, Scope *scope, AstNode
64306435 peer_parent->peers.last()->next_bb = end_block;
64316436 }
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,
64346439 incoming_blocks.items, incoming_values.items, peer_parent);
64356440 return ir_expr_wrap(ag, scope, phi, result_loc);
64366441 }
......@@ -6582,7 +6587,7 @@ static Stage1ZirInst *astgen_for_expr(Stage1AstGen *ag, Scope *parent_scope, Ast
65826587 peer_parent->peers.last()->next_bb = end_block;
65836588 }
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,
65866591 incoming_blocks.items, incoming_values.items, peer_parent);
65876592 return ir_lval_wrap(ag, parent_scope, phi, lval, result_loc);
65886593}
......@@ -6910,7 +6915,7 @@ static Stage1ZirInst *astgen_if_optional_expr(Stage1AstGen *ag, Scope *scope, As
69106915 incoming_blocks[0] = after_then_block;
69116916 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);
69146919 return ir_expr_wrap(ag, scope, phi, result_loc);
69156920}
69166921
......@@ -7008,7 +7013,7 @@ static Stage1ZirInst *astgen_if_err_expr(Stage1AstGen *ag, Scope *scope, AstNode
70087013 incoming_blocks[0] = after_then_block;
70097014 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);
70127017 return ir_expr_wrap(ag, scope, phi, result_loc);
70137018}
70147019
......@@ -7344,7 +7349,7 @@ static Stage1ZirInst *astgen_switch_expr(Stage1AstGen *ag, Scope *scope, AstNode
73447349 if (incoming_blocks.length == 0) {
73457350 result_instruction = ir_build_const_void(ag, scope, node);
73467351 } 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,
73487353 incoming_blocks.items, incoming_values.items, peer_parent);
73497354 }
73507355 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
76717676 Stage1ZirBasicBlock **incoming_blocks = heap::c_allocator.allocate<Stage1ZirBasicBlock *>(2);
76727677 incoming_blocks[0] = after_err_block;
76737678 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);
76757680 return ir_lval_wrap(ag, parent_scope, phi, lval, result_loc);
76767681}
76777682
src/stage1/ir.cpp+31-5
......@@ -1318,12 +1318,37 @@ static Stage1AirInstCall *ir_build_call_gen(IrAnalyze *ira, Scope *scope, AstNod
13181318 return call_instruction;
13191319}
13201320
1321static Stage1AirInst *ir_build_phi_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, size_t incoming_count,
1322 Stage1AirBasicBlock **incoming_blocks, Stage1AirInst **incoming_values, ZigType *result_type)
1321static Stage1AirInst *ir_build_phi_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, bool merge_comptime,
1322 size_t incoming_count, Stage1AirBasicBlock **incoming_blocks, Stage1AirInst **incoming_values, ZigType *result_type)
13231323{
13241324 assert(incoming_count != 0);
13251325 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
13271352 Stage1AirInstPhi *phi_instruction = ir_build_inst_gen<Stage1AirInstPhi>(&ira->new_irb,
13281353 scope, source_node);
13291354 phi_instruction->base.value->type = result_type;
......@@ -9592,7 +9617,8 @@ static Stage1AirInst *ir_evaluate_cmp_optional_non_optional(IrAnalyze *ira, Scop
95929617 incoming_values[0] = null_result;
95939618 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);
95969622}
95979623
95989624static 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
1475714783 ir_set_cursor_at_end_gen(&ira->new_irb, cur_bb);
1475814784
1475914785 Stage1AirInst *result = ir_build_phi_gen(ira, phi_instruction->base.scope,
14760 phi_instruction->base.source_node, new_incoming_blocks.length,
14761 new_incoming_blocks.items, new_incoming_values.items, resolved_type);
14786 phi_instruction->base.source_node, phi_instruction->merge_comptime,
14787 new_incoming_blocks.length, new_incoming_blocks.items, new_incoming_values.items, resolved_type);
1476214788
1476314789 if (all_stack_ptrs) {
1476414790 assert(result->value->special == ConstValSpecialRuntime);