From 0d8cb909dda0f3082e3279390e7d6ac27756a0fa Mon Sep 17 00:00:00 2001 From: David Mak Date: Fri, 7 Feb 2025 10:38:19 +0800 Subject: [PATCH] [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. --- nac3core/src/codegen/expr.rs | 39 ++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/nac3core/src/codegen/expr.rs b/nac3core/src/codegen/expr.rs index f4e03d04..53aa5f14 100644 --- a/nac3core/src/codegen/expr.rs +++ b/nac3core/src/codegen/expr.rs @@ -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 }