mirror of
https://github.com/ziglang/zig.git
synced 2026-01-25 16:55:22 +00:00
IR: implement short circuit bool or, and
This commit is contained in:
parent
24048b2af6
commit
bed83bc5a1
136
src/ir.cpp
136
src/ir.cpp
@ -1424,6 +1424,80 @@ static IrInstruction *ir_gen_assign_op(IrBuilder *irb, Scope *scope, AstNode *no
|
||||
return ir_build_const_void(irb, scope, node);
|
||||
}
|
||||
|
||||
static IrInstruction *ir_gen_bool_or(IrBuilder *irb, Scope *scope, AstNode *node) {
|
||||
assert(node->type == NodeTypeBinOpExpr);
|
||||
|
||||
bool is_inline = ir_should_inline(irb);
|
||||
|
||||
IrInstruction *val1 = ir_gen_node(irb, node->data.bin_op_expr.op1, scope);
|
||||
if (val1 == irb->codegen->invalid_instruction)
|
||||
return irb->codegen->invalid_instruction;
|
||||
IrBasicBlock *post_val1_block = irb->current_basic_block;
|
||||
|
||||
// block for when val1 == false
|
||||
IrBasicBlock *false_block = ir_build_basic_block(irb, "BoolOrFalse");
|
||||
// block for when val1 == true (don't even evaluate the second part)
|
||||
IrBasicBlock *true_block = ir_build_basic_block(irb, "BoolOrTrue");
|
||||
|
||||
ir_build_cond_br(irb, scope, node, val1, true_block, false_block, is_inline);
|
||||
|
||||
ir_set_cursor_at_end(irb, false_block);
|
||||
IrInstruction *val2 = ir_gen_node(irb, node->data.bin_op_expr.op2, scope);
|
||||
if (val2 == irb->codegen->invalid_instruction)
|
||||
return irb->codegen->invalid_instruction;
|
||||
IrBasicBlock *post_val2_block = irb->current_basic_block;
|
||||
|
||||
ir_build_br(irb, scope, node, true_block, is_inline);
|
||||
|
||||
ir_set_cursor_at_end(irb, true_block);
|
||||
|
||||
IrInstruction **incoming_values = allocate<IrInstruction *>(2);
|
||||
incoming_values[0] = val1;
|
||||
incoming_values[1] = val2;
|
||||
IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2);
|
||||
incoming_blocks[0] = post_val1_block;
|
||||
incoming_blocks[1] = post_val2_block;
|
||||
|
||||
return ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values);
|
||||
}
|
||||
|
||||
static IrInstruction *ir_gen_bool_and(IrBuilder *irb, Scope *scope, AstNode *node) {
|
||||
assert(node->type == NodeTypeBinOpExpr);
|
||||
|
||||
bool is_inline = ir_should_inline(irb);
|
||||
|
||||
IrInstruction *val1 = ir_gen_node(irb, node->data.bin_op_expr.op1, scope);
|
||||
if (val1 == irb->codegen->invalid_instruction)
|
||||
return irb->codegen->invalid_instruction;
|
||||
IrBasicBlock *post_val1_block = irb->current_basic_block;
|
||||
|
||||
// block for when val1 == true
|
||||
IrBasicBlock *true_block = ir_build_basic_block(irb, "BoolAndTrue");
|
||||
// block for when val1 == false (don't even evaluate the second part)
|
||||
IrBasicBlock *false_block = ir_build_basic_block(irb, "BoolAndFalse");
|
||||
|
||||
ir_build_cond_br(irb, scope, node, val1, true_block, false_block, is_inline);
|
||||
|
||||
ir_set_cursor_at_end(irb, true_block);
|
||||
IrInstruction *val2 = ir_gen_node(irb, node->data.bin_op_expr.op2, scope);
|
||||
if (val2 == irb->codegen->invalid_instruction)
|
||||
return irb->codegen->invalid_instruction;
|
||||
IrBasicBlock *post_val2_block = irb->current_basic_block;
|
||||
|
||||
ir_build_br(irb, scope, node, false_block, is_inline);
|
||||
|
||||
ir_set_cursor_at_end(irb, false_block);
|
||||
|
||||
IrInstruction **incoming_values = allocate<IrInstruction *>(2);
|
||||
incoming_values[0] = val1;
|
||||
incoming_values[1] = val2;
|
||||
IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2);
|
||||
incoming_blocks[0] = post_val1_block;
|
||||
incoming_blocks[1] = post_val2_block;
|
||||
|
||||
return ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values);
|
||||
}
|
||||
|
||||
static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node) {
|
||||
assert(node->type == NodeTypeBinOpExpr);
|
||||
|
||||
@ -1466,10 +1540,9 @@ static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node)
|
||||
case BinOpTypeAssignBoolOr:
|
||||
return ir_gen_assign_op(irb, scope, node, IrBinOpBoolOr);
|
||||
case BinOpTypeBoolOr:
|
||||
return ir_gen_bool_or(irb, scope, node);
|
||||
case BinOpTypeBoolAnd:
|
||||
// note: this is not a direct mapping to IrBinOpBoolOr/And
|
||||
// because of the control flow
|
||||
zig_panic("TODO gen IR for bool or/and");
|
||||
return ir_gen_bool_and(irb, scope, node);
|
||||
case BinOpTypeCmpEq:
|
||||
return ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpEq);
|
||||
case BinOpTypeCmpNotEq:
|
||||
@ -8263,63 +8336,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
|
||||
//
|
||||
//
|
||||
//
|
||||
//static LLVMValueRef gen_bool_and_expr(CodeGen *g, AstNode *node) {
|
||||
// assert(node->type == NodeTypeBinOpExpr);
|
||||
//
|
||||
// LLVMValueRef val1 = gen_expr(g, node->data.bin_op_expr.op1);
|
||||
// LLVMBasicBlockRef post_val1_block = LLVMGetInsertBlock(g->builder);
|
||||
//
|
||||
// // block for when val1 == true
|
||||
// LLVMBasicBlockRef true_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "BoolAndTrue");
|
||||
// // block for when val1 == false (don't even evaluate the second part)
|
||||
// LLVMBasicBlockRef false_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "BoolAndFalse");
|
||||
//
|
||||
// LLVMBuildCondBr(g->builder, val1, true_block, false_block);
|
||||
//
|
||||
// LLVMPositionBuilderAtEnd(g->builder, true_block);
|
||||
// LLVMValueRef val2 = gen_expr(g, node->data.bin_op_expr.op2);
|
||||
// LLVMBasicBlockRef post_val2_block = LLVMGetInsertBlock(g->builder);
|
||||
//
|
||||
// LLVMBuildBr(g->builder, false_block);
|
||||
//
|
||||
// LLVMPositionBuilderAtEnd(g->builder, false_block);
|
||||
// LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMInt1Type(), "");
|
||||
// LLVMValueRef incoming_values[2] = {val1, val2};
|
||||
// LLVMBasicBlockRef incoming_blocks[2] = {post_val1_block, post_val2_block};
|
||||
// LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2);
|
||||
//
|
||||
// return phi;
|
||||
//}
|
||||
//
|
||||
//static LLVMValueRef gen_bool_or_expr(CodeGen *g, AstNode *expr_node) {
|
||||
// assert(expr_node->type == NodeTypeBinOpExpr);
|
||||
//
|
||||
// LLVMValueRef val1 = gen_expr(g, expr_node->data.bin_op_expr.op1);
|
||||
// LLVMBasicBlockRef post_val1_block = LLVMGetInsertBlock(g->builder);
|
||||
//
|
||||
// // block for when val1 == false
|
||||
// LLVMBasicBlockRef false_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "BoolOrFalse");
|
||||
// // block for when val1 == true (don't even evaluate the second part)
|
||||
// LLVMBasicBlockRef true_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "BoolOrTrue");
|
||||
//
|
||||
// LLVMBuildCondBr(g->builder, val1, true_block, false_block);
|
||||
//
|
||||
// LLVMPositionBuilderAtEnd(g->builder, false_block);
|
||||
// LLVMValueRef val2 = gen_expr(g, expr_node->data.bin_op_expr.op2);
|
||||
//
|
||||
// LLVMBasicBlockRef post_val2_block = LLVMGetInsertBlock(g->builder);
|
||||
//
|
||||
// LLVMBuildBr(g->builder, true_block);
|
||||
//
|
||||
// LLVMPositionBuilderAtEnd(g->builder, true_block);
|
||||
// LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMInt1Type(), "");
|
||||
// LLVMValueRef incoming_values[2] = {val1, val2};
|
||||
// LLVMBasicBlockRef incoming_blocks[2] = {post_val1_block, post_val2_block};
|
||||
// LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2);
|
||||
//
|
||||
// return phi;
|
||||
//}
|
||||
//
|
||||
//static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) {
|
||||
// assert(node->type == NodeTypeBinOpExpr);
|
||||
//
|
||||
|
||||
@ -152,6 +152,33 @@ fn testContinueInForLoop() {
|
||||
assert(sum == 6);
|
||||
}
|
||||
|
||||
fn shortCircuit() {
|
||||
var hit_1 = false;
|
||||
var hit_2 = false;
|
||||
var hit_3 = false;
|
||||
var hit_4 = false;
|
||||
|
||||
if (true || {assert(false); false}) {
|
||||
hit_1 = true;
|
||||
}
|
||||
if (false || { hit_2 = true; false }) {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
if (true && { hit_3 = true; false }) {
|
||||
assert(false);
|
||||
}
|
||||
if (false && {assert(false); false}) {
|
||||
assert(false);
|
||||
} else {
|
||||
hit_4 = true;
|
||||
}
|
||||
assert(hit_1);
|
||||
assert(hit_2);
|
||||
assert(hit_3);
|
||||
assert(hit_4);
|
||||
}
|
||||
|
||||
|
||||
fn assert(ok: bool) {
|
||||
if (!ok)
|
||||
@ -173,6 +200,7 @@ fn runAllTests() {
|
||||
testCompileTimeGenericEval();
|
||||
testFnWithInlineArgs();
|
||||
testContinueInForLoop();
|
||||
shortCircuit();
|
||||
}
|
||||
|
||||
export nakedcc fn _start() -> unreachable {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user