authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-12-05 19:12:19-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-12-05 19:12:19-05:00
logbed83bc5a14aa6c0480dcfa842d97cce64427e1b
tree2bb49ff047be1ecc39683c208240845f80ca5e27
parent24048b2af62f1b36678aa08a20d0754cb712e485

IR: implement short circuit bool or, and


2 files changed, 104 insertions(+), 60 deletions(-)

src/ir.cpp+76-60
...@@ -1424,6 +1424,80 @@ static IrInstruction *ir_gen_assign_op(IrBuilder *irb, Scope *scope, AstNode *no...@@ -1424,6 +1424,80 @@ static IrInstruction *ir_gen_assign_op(IrBuilder *irb, Scope *scope, AstNode *no
1424 return ir_build_const_void(irb, scope, node);1424 return ir_build_const_void(irb, scope, node);
1425}1425}
14261426
1427static IrInstruction *ir_gen_bool_or(IrBuilder *irb, Scope *scope, AstNode *node) {
1428 assert(node->type == NodeTypeBinOpExpr);
1429
1430 bool is_inline = ir_should_inline(irb);
1431
1432 IrInstruction *val1 = ir_gen_node(irb, node->data.bin_op_expr.op1, scope);
1433 if (val1 == irb->codegen->invalid_instruction)
1434 return irb->codegen->invalid_instruction;
1435 IrBasicBlock *post_val1_block = irb->current_basic_block;
1436
1437 // block for when val1 == false
1438 IrBasicBlock *false_block = ir_build_basic_block(irb, "BoolOrFalse");
1439 // block for when val1 == true (don't even evaluate the second part)
1440 IrBasicBlock *true_block = ir_build_basic_block(irb, "BoolOrTrue");
1441
1442 ir_build_cond_br(irb, scope, node, val1, true_block, false_block, is_inline);
1443
1444 ir_set_cursor_at_end(irb, false_block);
1445 IrInstruction *val2 = ir_gen_node(irb, node->data.bin_op_expr.op2, scope);
1446 if (val2 == irb->codegen->invalid_instruction)
1447 return irb->codegen->invalid_instruction;
1448 IrBasicBlock *post_val2_block = irb->current_basic_block;
1449
1450 ir_build_br(irb, scope, node, true_block, is_inline);
1451
1452 ir_set_cursor_at_end(irb, true_block);
1453
1454 IrInstruction **incoming_values = allocate<IrInstruction *>(2);
1455 incoming_values[0] = val1;
1456 incoming_values[1] = val2;
1457 IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2);
1458 incoming_blocks[0] = post_val1_block;
1459 incoming_blocks[1] = post_val2_block;
1460
1461 return ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values);
1462}
1463
1464static IrInstruction *ir_gen_bool_and(IrBuilder *irb, Scope *scope, AstNode *node) {
1465 assert(node->type == NodeTypeBinOpExpr);
1466
1467 bool is_inline = ir_should_inline(irb);
1468
1469 IrInstruction *val1 = ir_gen_node(irb, node->data.bin_op_expr.op1, scope);
1470 if (val1 == irb->codegen->invalid_instruction)
1471 return irb->codegen->invalid_instruction;
1472 IrBasicBlock *post_val1_block = irb->current_basic_block;
1473
1474 // block for when val1 == true
1475 IrBasicBlock *true_block = ir_build_basic_block(irb, "BoolAndTrue");
1476 // block for when val1 == false (don't even evaluate the second part)
1477 IrBasicBlock *false_block = ir_build_basic_block(irb, "BoolAndFalse");
1478
1479 ir_build_cond_br(irb, scope, node, val1, true_block, false_block, is_inline);
1480
1481 ir_set_cursor_at_end(irb, true_block);
1482 IrInstruction *val2 = ir_gen_node(irb, node->data.bin_op_expr.op2, scope);
1483 if (val2 == irb->codegen->invalid_instruction)
1484 return irb->codegen->invalid_instruction;
1485 IrBasicBlock *post_val2_block = irb->current_basic_block;
1486
1487 ir_build_br(irb, scope, node, false_block, is_inline);
1488
1489 ir_set_cursor_at_end(irb, false_block);
1490
1491 IrInstruction **incoming_values = allocate<IrInstruction *>(2);
1492 incoming_values[0] = val1;
1493 incoming_values[1] = val2;
1494 IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2);
1495 incoming_blocks[0] = post_val1_block;
1496 incoming_blocks[1] = post_val2_block;
1497
1498 return ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values);
1499}
1500
1427static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node) {1501static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node) {
1428 assert(node->type == NodeTypeBinOpExpr);1502 assert(node->type == NodeTypeBinOpExpr);
14291503
...@@ -1466,10 +1540,9 @@ static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node)...@@ -1466,10 +1540,9 @@ static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node)
1466 case BinOpTypeAssignBoolOr:1540 case BinOpTypeAssignBoolOr:
1467 return ir_gen_assign_op(irb, scope, node, IrBinOpBoolOr);1541 return ir_gen_assign_op(irb, scope, node, IrBinOpBoolOr);
1468 case BinOpTypeBoolOr:1542 case BinOpTypeBoolOr:
1543 return ir_gen_bool_or(irb, scope, node);
1469 case BinOpTypeBoolAnd:1544 case BinOpTypeBoolAnd:
1470 // note: this is not a direct mapping to IrBinOpBoolOr/And1545 return ir_gen_bool_and(irb, scope, node);
1471 // because of the control flow
1472 zig_panic("TODO gen IR for bool or/and");
1473 case BinOpTypeCmpEq:1546 case BinOpTypeCmpEq:
1474 return ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpEq);1547 return ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpEq);
1475 case BinOpTypeCmpNotEq:1548 case BinOpTypeCmpNotEq:
...@@ -8263,63 +8336,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -8263,63 +8336,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
8263//8336//
8264//8337//
8265//8338//
8266//static LLVMValueRef gen_bool_and_expr(CodeGen *g, AstNode *node) {
8267// assert(node->type == NodeTypeBinOpExpr);
8268//
8269// LLVMValueRef val1 = gen_expr(g, node->data.bin_op_expr.op1);
8270// LLVMBasicBlockRef post_val1_block = LLVMGetInsertBlock(g->builder);
8271//
8272// // block for when val1 == true
8273// LLVMBasicBlockRef true_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "BoolAndTrue");
8274// // block for when val1 == false (don't even evaluate the second part)
8275// LLVMBasicBlockRef false_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "BoolAndFalse");
8276//
8277// LLVMBuildCondBr(g->builder, val1, true_block, false_block);
8278//
8279// LLVMPositionBuilderAtEnd(g->builder, true_block);
8280// LLVMValueRef val2 = gen_expr(g, node->data.bin_op_expr.op2);
8281// LLVMBasicBlockRef post_val2_block = LLVMGetInsertBlock(g->builder);
8282//
8283// LLVMBuildBr(g->builder, false_block);
8284//
8285// LLVMPositionBuilderAtEnd(g->builder, false_block);
8286// LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMInt1Type(), "");
8287// LLVMValueRef incoming_values[2] = {val1, val2};
8288// LLVMBasicBlockRef incoming_blocks[2] = {post_val1_block, post_val2_block};
8289// LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2);
8290//
8291// return phi;
8292//}
8293//
8294//static LLVMValueRef gen_bool_or_expr(CodeGen *g, AstNode *expr_node) {
8295// assert(expr_node->type == NodeTypeBinOpExpr);
8296//
8297// LLVMValueRef val1 = gen_expr(g, expr_node->data.bin_op_expr.op1);
8298// LLVMBasicBlockRef post_val1_block = LLVMGetInsertBlock(g->builder);
8299//
8300// // block for when val1 == false
8301// LLVMBasicBlockRef false_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "BoolOrFalse");
8302// // block for when val1 == true (don't even evaluate the second part)
8303// LLVMBasicBlockRef true_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "BoolOrTrue");
8304//
8305// LLVMBuildCondBr(g->builder, val1, true_block, false_block);
8306//
8307// LLVMPositionBuilderAtEnd(g->builder, false_block);
8308// LLVMValueRef val2 = gen_expr(g, expr_node->data.bin_op_expr.op2);
8309//
8310// LLVMBasicBlockRef post_val2_block = LLVMGetInsertBlock(g->builder);
8311//
8312// LLVMBuildBr(g->builder, true_block);
8313//
8314// LLVMPositionBuilderAtEnd(g->builder, true_block);
8315// LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMInt1Type(), "");
8316// LLVMValueRef incoming_values[2] = {val1, val2};
8317// LLVMBasicBlockRef incoming_blocks[2] = {post_val1_block, post_val2_block};
8318// LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2);
8319//
8320// return phi;
8321//}
8322//
8323//static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) {8339//static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) {
8324// assert(node->type == NodeTypeBinOpExpr);8340// assert(node->type == NodeTypeBinOpExpr);
8325//8341//
test/self_hosted2.zig+28
...@@ -152,6 +152,33 @@ fn testContinueInForLoop() {...@@ -152,6 +152,33 @@ fn testContinueInForLoop() {
152 assert(sum == 6);152 assert(sum == 6);
153}153}
154154
155fn shortCircuit() {
156 var hit_1 = false;
157 var hit_2 = false;
158 var hit_3 = false;
159 var hit_4 = false;
160
161 if (true || {assert(false); false}) {
162 hit_1 = true;
163 }
164 if (false || { hit_2 = true; false }) {
165 assert(false);
166 }
167
168 if (true && { hit_3 = true; false }) {
169 assert(false);
170 }
171 if (false && {assert(false); false}) {
172 assert(false);
173 } else {
174 hit_4 = true;
175 }
176 assert(hit_1);
177 assert(hit_2);
178 assert(hit_3);
179 assert(hit_4);
180}
181
155182
156fn assert(ok: bool) {183fn assert(ok: bool) {
157 if (!ok)184 if (!ok)
...@@ -173,6 +200,7 @@ fn runAllTests() {...@@ -173,6 +200,7 @@ fn runAllTests() {
173 testCompileTimeGenericEval();200 testCompileTimeGenericEval();
174 testFnWithInlineArgs();201 testFnWithInlineArgs();
175 testContinueInForLoop();202 testContinueInForLoop();
203 shortCircuit();
176}204}
177205
178export nakedcc fn _start() -> unreachable {206export nakedcc fn _start() -> unreachable {