mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-03 14:18:47 +00:00
Enforce an icmp when casting to i1 to correct behaviour for booleans which are not 0 or 1
This commit is contained in:
+33
-46
@@ -1,20 +1,18 @@
|
|||||||
gb_internal lbValue lb_emit_arith_matrix(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type, bool component_wise);
|
gb_internal lbValue lb_emit_arith_matrix(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type, bool component_wise);
|
||||||
|
|
||||||
gb_internal lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, Ast *left, Ast *right, Type *type) {
|
gb_internal lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, Ast *left, Ast *right, Type *final_type) {
|
||||||
lbModule *m = p->module;
|
lbModule *m = p->module;
|
||||||
|
|
||||||
lbBlock *rhs = lb_create_block(p, "logical.cmp.rhs");
|
lbBlock *rhs = lb_create_block(p, "logical.cmp.rhs");
|
||||||
lbBlock *done = lb_create_block(p, "logical.cmp.done");
|
lbBlock *done = lb_create_block(p, "logical.cmp.done");
|
||||||
|
|
||||||
type = default_type(type);
|
|
||||||
|
|
||||||
lbValue short_circuit = {};
|
lbValue short_circuit = {};
|
||||||
if (op == Token_CmpAnd) {
|
if (op == Token_CmpAnd) {
|
||||||
lb_build_cond(p, left, rhs, done);
|
lb_build_cond(p, left, rhs, done);
|
||||||
short_circuit = lb_const_bool(m, type, false);
|
short_circuit = lb_const_bool(m, t_llvm_bool, false);
|
||||||
} else if (op == Token_CmpOr) {
|
} else if (op == Token_CmpOr) {
|
||||||
lb_build_cond(p, left, done, rhs);
|
lb_build_cond(p, left, done, rhs);
|
||||||
short_circuit = lb_const_bool(m, type, true);
|
short_circuit = lb_const_bool(m, t_llvm_bool, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rhs->preds.count == 0) {
|
if (rhs->preds.count == 0) {
|
||||||
@@ -25,7 +23,7 @@ gb_internal lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, As
|
|||||||
if (done->preds.count == 0) {
|
if (done->preds.count == 0) {
|
||||||
lb_start_block(p, rhs);
|
lb_start_block(p, rhs);
|
||||||
if (lb_is_expr_untyped_const(right)) {
|
if (lb_is_expr_untyped_const(right)) {
|
||||||
return lb_expr_untyped_const_to_typed(m, right, type);
|
return lb_expr_untyped_const_to_typed(m, right, default_type(final_type));
|
||||||
}
|
}
|
||||||
return lb_build_expr(p, right);
|
return lb_build_expr(p, right);
|
||||||
}
|
}
|
||||||
@@ -43,10 +41,11 @@ gb_internal lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, As
|
|||||||
lb_start_block(p, rhs);
|
lb_start_block(p, rhs);
|
||||||
lbValue edge = {};
|
lbValue edge = {};
|
||||||
if (lb_is_expr_untyped_const(right)) {
|
if (lb_is_expr_untyped_const(right)) {
|
||||||
edge = lb_expr_untyped_const_to_typed(m, right, type);
|
edge = lb_expr_untyped_const_to_typed(m, right, t_llvm_bool);
|
||||||
} else {
|
} else {
|
||||||
edge = lb_build_expr(p, right);
|
edge = lb_emit_conv(p, lb_build_expr(p, right), t_llvm_bool);
|
||||||
}
|
}
|
||||||
|
GB_ASSERT(edge.type == t_llvm_bool);
|
||||||
|
|
||||||
incoming_values[done->preds.count] = edge.value;
|
incoming_values[done->preds.count] = edge.value;
|
||||||
incoming_blocks[done->preds.count] = p->curr_block->block;
|
incoming_blocks[done->preds.count] = p->curr_block->block;
|
||||||
@@ -54,7 +53,7 @@ gb_internal lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, As
|
|||||||
lb_emit_jump(p, done);
|
lb_emit_jump(p, done);
|
||||||
lb_start_block(p, done);
|
lb_start_block(p, done);
|
||||||
|
|
||||||
LLVMTypeRef dst_type = lb_type(m, type);
|
LLVMTypeRef dst_type = lb_type(m, t_llvm_bool);
|
||||||
LLVMValueRef phi = nullptr;
|
LLVMValueRef phi = nullptr;
|
||||||
|
|
||||||
GB_ASSERT(incoming_values.count == incoming_blocks.count);
|
GB_ASSERT(incoming_values.count == incoming_blocks.count);
|
||||||
@@ -67,48 +66,36 @@ gb_internal lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, As
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lbValue res = {};
|
||||||
|
|
||||||
if (phi_type == nullptr) {
|
if (phi_type == nullptr) {
|
||||||
phi = LLVMBuildPhi(p->builder, dst_type, "");
|
phi = LLVMBuildPhi(p->builder, dst_type, "");
|
||||||
LLVMAddIncoming(phi, incoming_values.data, incoming_blocks.data, cast(unsigned)incoming_values.count);
|
LLVMAddIncoming(phi, incoming_values.data, incoming_blocks.data, cast(unsigned)incoming_values.count);
|
||||||
lbValue res = {};
|
|
||||||
res.type = type;
|
|
||||||
res.value = phi;
|
res.value = phi;
|
||||||
return res;
|
res.type = t_llvm_bool;
|
||||||
}
|
|
||||||
|
|
||||||
for_array(i, incoming_values) {
|
|
||||||
LLVMValueRef incoming_value = incoming_values[i];
|
|
||||||
LLVMTypeRef incoming_type = LLVMTypeOf(incoming_value);
|
|
||||||
|
|
||||||
if (phi_type != incoming_type) {
|
|
||||||
GB_ASSERT_MSG(LLVMIsConstant(incoming_value), "%s vs %s", LLVMPrintTypeToString(phi_type), LLVMPrintTypeToString(incoming_type));
|
|
||||||
bool ok = !!LLVMConstIntGetZExtValue(incoming_value);
|
|
||||||
incoming_values[i] = LLVMConstInt(phi_type, ok, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
phi = LLVMBuildPhi(p->builder, phi_type, "");
|
|
||||||
LLVMAddIncoming(phi, incoming_values.data, incoming_blocks.data, cast(unsigned)incoming_values.count);
|
|
||||||
|
|
||||||
LLVMTypeRef i1 = LLVMInt1TypeInContext(m->ctx);
|
|
||||||
if ((phi_type == i1) ^ (dst_type == i1)) {
|
|
||||||
if (phi_type == i1) {
|
|
||||||
phi = LLVMBuildZExt(p->builder, phi, dst_type, "");
|
|
||||||
} else {
|
|
||||||
phi = LLVMBuildTruncOrBitCast(p->builder, phi, dst_type, "");
|
|
||||||
}
|
|
||||||
} else if (lb_sizeof(phi_type) < lb_sizeof(dst_type)) {
|
|
||||||
phi = LLVMBuildZExt(p->builder, phi, dst_type, "");
|
|
||||||
} else {
|
} else {
|
||||||
phi = LLVMBuildTruncOrBitCast(p->builder, phi, dst_type, "");
|
for_array(i, incoming_values) {
|
||||||
}
|
LLVMValueRef incoming_value = incoming_values[i];
|
||||||
|
LLVMTypeRef incoming_type = LLVMTypeOf(incoming_value);
|
||||||
lbValue res = {};
|
|
||||||
res.type = type;
|
if (phi_type != incoming_type) {
|
||||||
res.value = phi;
|
GB_ASSERT_MSG(LLVMIsConstant(incoming_value), "%s vs %s", LLVMPrintTypeToString(phi_type), LLVMPrintTypeToString(incoming_type));
|
||||||
return res;
|
bool ok = !!LLVMConstIntGetZExtValue(incoming_value);
|
||||||
|
incoming_values[i] = LLVMConstInt(phi_type, ok, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE(bill): this now only uses i1 for the logic to prevent issues with corrupted booleans which are not of value 0 or 1 (e.g. 2)
|
||||||
|
// Doing this may produce slightly worse code as a result but it will be correct behaviour
|
||||||
|
|
||||||
|
phi = LLVMBuildPhi(p->builder, phi_type, "");
|
||||||
|
LLVMAddIncoming(phi, incoming_values.data, incoming_blocks.data, cast(unsigned)incoming_values.count);
|
||||||
|
res.value = phi;
|
||||||
|
res.type = t_llvm_bool;
|
||||||
|
}
|
||||||
|
return lb_emit_conv(p, res, default_type(final_type));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1566,7 +1553,7 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
|
|||||||
// bool <-> llvm bool
|
// bool <-> llvm bool
|
||||||
if (is_type_boolean(src) && dst == t_llvm_bool) {
|
if (is_type_boolean(src) && dst == t_llvm_bool) {
|
||||||
lbValue res = {};
|
lbValue res = {};
|
||||||
res.value = LLVMBuildTrunc(p->builder, value.value, lb_type(m, dst), "");
|
res.value = LLVMBuildICmp(p->builder, LLVMIntNE, value.value, LLVMConstNull(lb_type(m, src)), "");
|
||||||
res.type = t;
|
res.type = t;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user