Shortcircuiting

This commit is contained in:
David Gonzalez Martin 2025-06-14 06:55:27 -06:00
parent 81fd0aebfd
commit b24b5f29f7
2 changed files with 151 additions and 26 deletions

View File

@ -5478,7 +5478,22 @@ get_token_precedence = fn (token: Token) Precedence
},
.operator_keyword =>
{
#trap();
>operator_keyword = token.content.operator_keyword;
switch (operator_keyword)
{
.and,
."and?",
=>
{
return .boolean_and;
},
.or,
."or?",
=>
{
return .boolean_or;
},
}
},
.compare_equal,
.compare_not_equal,
@ -5603,7 +5618,14 @@ parse_right = fn (module: &Module, scope: &Scope, builder: ValueBuilder) &Value
{
.operator_keyword =>
{
#trap();
>operator_keyword = token.content.operator_keyword;
switch (operator_keyword)
{
.and => { id = .logical_and; },
.or => { id = .logical_or; },
."and?" => { id = .logical_and_shortcircuit; },
."or?" => { id = .logical_or_shortcircuit; },
}
},
.plus => { id = .add; },
.dash => { id = .sub; },
@ -11761,6 +11783,31 @@ emit_va_arg = fn (module: &Module, value: &Value, left_llvm: &LLVMValue, left_ty
}
}
emit_condition = fn (module: &Module, condition: &Value) &LLVMValue
{
>llvm_condition = condition.llvm;
>condition_type = condition.type;
assert(llvm_condition != zero);
assert(condition_type != zero);
assert(condition_type.id == .integer or condition_type.id == .pointer);
if (!(condition_type.id == .integer and condition_type.content.integer.bit_count == 1))
{
llvm_condition = LLVMBuildICmp(module.llvm.builder, .ne, llvm_condition, LLVMConstNull(condition_type.llvm.abi), "");
}
assert(llvm_condition != zero);
return llvm_condition;
}
ShortcircuitingOperation = enum
{
and,
or,
}
emit_value = fn (module: &Module, value: &Value, type_kind: TypeKind, expect_constant: u1) void
{
>must_be_constant = expect_constant or (!module.current_function and !module.current_macro_instantiation);
@ -11811,7 +11858,106 @@ emit_value = fn (module: &Module, value: &Value, type_kind: TypeKind, expect_con
if (is_shortcircuiting)
{
#trap();
if (must_be_constant)
{
report_error();
}
>op: ShortcircuitingOperation = undefined;
switch (binary_id)
{
.logical_and_shortcircuit => { op = .and; },
.logical_or_shortcircuit => { op = .or; },
else => { unreachable; },
}
>left = value.content.binary.left;
>right = value.content.binary.right;
>right_block = LLVMAppendBasicBlockInContext(module.llvm.context, llvm_function, "shorcircuit.right");
>end_block = LLVMAppendBasicBlockInContext(module.llvm.context, llvm_function, "shorcircuit.end");
>true_block: &LLVMBasicBlock = undefined;
>false_block: &LLVMBasicBlock = undefined;
switch (op)
{
.and =>
{
true_block = right_block;
false_block = end_block;
},
.or =>
{
true_block = end_block;
false_block = right_block;
},
}
emit_value(module, left, .abi, 0);
>llvm_condition = emit_condition(module, left);
>current_basic_block = LLVMGetInsertBlock(module.llvm.builder);
LLVMBuildCondBr(module.llvm.builder, llvm_condition, true_block, false_block);
LLVMPositionBuilderAtEnd(module.llvm.builder, right_block);
assert(!right.llvm);
emit_value(module, right, .abi, 0);
>right_llvm = right.llvm;
>right_condition: &LLVMValue = zero;
switch (right.type.id)
{
.integer =>
{
switch (right.type.content.integer.bit_count)
{
1 =>
{
right_condition = right_llvm;
},
else => { #trap(); },
}
},
else => { #trap(); },
}
assert(right_condition != zero);
LLVMBuildBr(module.llvm.builder, end_block);
LLVMPositionBuilderAtEnd(module.llvm.builder, end_block);
>boolean_type = uint1(module);
resolve_type_in_place(module, boolean_type);
>boolean = boolean_type.llvm.abi;
>incoming_left: &LLVMValue = zero;
switch (op)
{
.and => { incoming_left = LLVMConstNull(boolean); },
.or => { incoming_left = LLVMConstInt(boolean, 1, 0); },
}
>phi = LLVMBuildPhi(module.llvm.builder, boolean, "");
>values: [_]&LLVMValue = [
incoming_left,
right_condition,
];
>blocks: [_]&LLVMBasicBlock = [
current_basic_block,
right_block,
];
LLVMAddIncoming(phi, &values[0], &blocks[0], blocks.length);
llvm_value = phi;
if (type_kind == .memory)
{
#trap();
}
}
else
{
@ -12871,25 +13017,6 @@ emit_local = fn (module: &Module, local: &Local) void
}
}
emit_condition = fn (module: &Module, condition: &Value) &LLVMValue
{
>llvm_condition = condition.llvm;
>condition_type = condition.type;
assert(llvm_condition != zero);
assert(condition_type != zero);
assert(condition_type.id == .integer or condition_type.id == .pointer);
if (!(condition_type.id == .integer and condition_type.content.integer.bit_count == 1))
{
llvm_condition = LLVMBuildICmp(module.llvm.builder, .ne, llvm_condition, LLVMConstNull(condition_type.llvm.abi), "");
}
assert(llvm_condition != zero);
return llvm_condition;
}
analyze_block = fn (module: &Module, block: &Block) void;
analyze_statement = fn (module: &Module, scope: &Scope, statement: &Statement) void
@ -14789,6 +14916,8 @@ names: [_][]u8 =
"empty_if",
"else_if",
"else_if_complicated",
"basic_shortcircuiting_if",
"shortcircuiting_if",
];
[export] main = fn [cc(c)] (argument_count: u32, argv: &&u8, envp: &&u8) s32

View File

@ -7372,9 +7372,6 @@ fn void emit_value(Module* module, Value* value, TypeKind type_kind, bool expect
auto* left = value->binary.left;
auto llvm_function = module->current_function->variable.storage->llvm;
assert(llvm_function);
auto* right_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "shortcircuit.right");
auto* end_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "shortcircuit.end");
@ -7439,7 +7436,6 @@ fn void emit_value(Module* module, Value* value, TypeKind type_kind, bool expect
auto boolean_type = uint1(module);
resolve_type_in_place(module, boolean_type);
auto boolean = boolean_type->llvm.abi;
LLVMValueRef incoming_left = 0;