[core] codegen/expr: Fix and use gen_unaryop_expr for boolean not ops

While refactoring, I ran into the issue where `!true == true`, which was
caused by the same upper 7-bit of booleans being undefined issue that
was encountered before. It turns out the implementation in
`gen_unaryop_expr` is also inadequate, as `(~v & (i1) 0x1)`` will still
leave upper 7 bits undefined (for whatever reason).

This commit fixes this issue once and for all by using a combination of
`icmp` + `zext` to ensure that the resulting value must be `0 | 1`, and
refactor to use that whenever we need to invert boolean values.
This commit is contained in:
David Mak 2025-02-07 10:38:19 +08:00
parent 529fa67855
commit 0d8cb909dd

View File

@ -1704,11 +1704,12 @@ pub fn gen_unaryop_expr_with_values<'ctx, G: CodeGenerator>(
Ok(Some(if ty == ctx.primitives.bool {
let val = val.into_int_value();
if op == ast::Unaryop::Not {
let not = ctx.builder.build_not(val, "not").unwrap();
let not_bool =
ctx.builder.build_and(not, not.get_type().const_int(1, false), "").unwrap();
let not = ctx
.builder
.build_int_compare(IntPredicate::EQ, val, val.get_type().const_zero(), "not")
.unwrap();
not_bool.into()
generator.bool_to_int_type(ctx, not, val.get_type()).into()
} else {
let llvm_i32 = ctx.ctx.i32_type();
@ -2001,7 +2002,18 @@ pub fn gen_cmpop_expr_with_values<'ctx, G: CodeGenerator>(
).into_int_value();
let result = call_string_eq(ctx, lhs_ptr, lhs_len, rhs_ptr, rhs_len);
if *op == Cmpop::NotEq {
ctx.builder.build_not(result, "").unwrap()
gen_unaryop_expr_with_values(
generator,
ctx,
Unaryop::Not,
(&Some(ctx.primitives.bool), result.into()),
)
.transpose()
.unwrap()
.and_then(|res| {
res.to_basic_value_enum(ctx, generator, ctx.primitives.bool)
})?
.into_int_value()
} else {
result
}
@ -2248,8 +2260,8 @@ pub fn gen_cmpop_expr_with_values<'ctx, G: CodeGenerator>(
.unwrap()
.and_then(|v| {
v.to_basic_value_enum(ctx, generator, ctx.primitives.bool)
})
.map(BasicValueEnum::into_int_value)?;
})?
.into_int_value();
Ok(ctx.builder.build_not(
generator.bool_to_i1(ctx, cmp),
@ -2285,7 +2297,18 @@ pub fn gen_cmpop_expr_with_values<'ctx, G: CodeGenerator>(
// Invert the final value if __ne__
if *op == Cmpop::NotEq {
ctx.builder.build_not(cmp_phi, "").unwrap()
gen_unaryop_expr_with_values(
generator,
ctx,
Unaryop::Not,
(&Some(ctx.primitives.bool), cmp_phi.into())
)
.transpose()
.unwrap()
.and_then(|res| {
res.to_basic_value_enum(ctx, generator, ctx.primitives.bool)
})?
.into_int_value()
} else {
cmp_phi
}