Shortcircuiting
This commit is contained in:
parent
81fd0aebfd
commit
b24b5f29f7
173
src/compiler.bbb
173
src/compiler.bbb
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user