From 529fa67855e8f44373d90d7e7b5c7a08b9745f56 Mon Sep 17 00:00:00 2001 From: David Mak Date: Fri, 7 Feb 2025 14:01:10 +0800 Subject: [PATCH] [core] codegen: Add bool_to_int_type to replace bool_to_{i1,i8} Unifies the implementation for both functions. --- nac3core/src/codegen/expr.rs | 2 +- nac3core/src/codegen/generator.rs | 20 +++++++++--- nac3core/src/codegen/mod.rs | 52 +++++++++++-------------------- 3 files changed, 35 insertions(+), 39 deletions(-) diff --git a/nac3core/src/codegen/expr.rs b/nac3core/src/codegen/expr.rs index 20d296e4..f4e03d04 100644 --- a/nac3core/src/codegen/expr.rs +++ b/nac3core/src/codegen/expr.rs @@ -2001,7 +2001,7 @@ 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() + ctx.builder.build_not(result, "").unwrap() } else { result } diff --git a/nac3core/src/codegen/generator.rs b/nac3core/src/codegen/generator.rs index 620ede0e..42c7c71b 100644 --- a/nac3core/src/codegen/generator.rs +++ b/nac3core/src/codegen/generator.rs @@ -7,7 +7,7 @@ use inkwell::{ use nac3parser::ast::{Expr, Stmt, StrRef}; -use super::{bool_to_i1, bool_to_i8, expr::*, stmt::*, values::ArraySliceValue, CodeGenContext}; +use super::{bool_to_int_type, expr::*, stmt::*, values::ArraySliceValue, CodeGenContext}; use crate::{ symbol_resolver::ValueEnum, toplevel::{DefinitionId, TopLevelDef}, @@ -248,22 +248,32 @@ pub trait CodeGenerator { gen_block(self, ctx, stmts) } - /// See [`bool_to_i1`]. + /// Converts the value of a boolean-like value `bool_value` into an `i1`. fn bool_to_i1<'ctx>( &self, ctx: &CodeGenContext<'ctx, '_>, bool_value: IntValue<'ctx>, ) -> IntValue<'ctx> { - bool_to_i1(&ctx.builder, bool_value) + self.bool_to_int_type(ctx, bool_value, ctx.ctx.bool_type()) } - /// See [`bool_to_i8`]. + /// Converts the value of a boolean-like value `bool_value` into an `i8`. fn bool_to_i8<'ctx>( &self, ctx: &CodeGenContext<'ctx, '_>, bool_value: IntValue<'ctx>, ) -> IntValue<'ctx> { - bool_to_i8(&ctx.builder, ctx.ctx, bool_value) + self.bool_to_int_type(ctx, bool_value, ctx.ctx.i8_type()) + } + + /// See [`bool_to_int_type`]. + fn bool_to_int_type<'ctx>( + &self, + ctx: &CodeGenContext<'ctx, '_>, + bool_value: IntValue<'ctx>, + ty: IntType<'ctx>, + ) -> IntValue<'ctx> { + bool_to_int_type(&ctx.builder, bool_value, ty) } } diff --git a/nac3core/src/codegen/mod.rs b/nac3core/src/codegen/mod.rs index a188d1c3..f1b9cfb9 100644 --- a/nac3core/src/codegen/mod.rs +++ b/nac3core/src/codegen/mod.rs @@ -933,7 +933,7 @@ pub fn gen_func_impl< let param_val = param.into_int_value(); if expected_ty.get_bit_width() == 8 && param_val.get_type().get_bit_width() == 1 { - bool_to_i8(&builder, context, param_val) + bool_to_int_type(&builder, param_val, context.i8_type()) } else { param_val } @@ -1103,43 +1103,29 @@ pub fn gen_func<'ctx, G: CodeGenerator>( }) } -/// Converts the value of a boolean-like value `bool_value` into an `i1`. -fn bool_to_i1<'ctx>(builder: &Builder<'ctx>, bool_value: IntValue<'ctx>) -> IntValue<'ctx> { - if bool_value.get_type().get_bit_width() == 1 { - bool_value - } else { - builder - .build_int_compare( - IntPredicate::NE, - bool_value, - bool_value.get_type().const_zero(), - "tobool", - ) - .unwrap() - } -} - -/// Converts the value of a boolean-like value `bool_value` into an `i8`. -fn bool_to_i8<'ctx>( +/// Converts the value of a boolean-like value `value` into an arbitrary [`IntType`]. +/// +/// This has the same semantics as `(ty)(value != 0)` in C. +/// +/// The returned value is guaranteed to either be `0` or `1`, except for `ty == i1` where only the +/// least-significant bit would be guaranteed to be `0` or `1`. +fn bool_to_int_type<'ctx>( builder: &Builder<'ctx>, - ctx: &'ctx Context, - bool_value: IntValue<'ctx>, + value: IntValue<'ctx>, + ty: IntType<'ctx>, ) -> IntValue<'ctx> { - let value_bits = bool_value.get_type().get_bit_width(); - match value_bits { - 8 => bool_value, - 1 => builder.build_int_z_extend(bool_value, ctx.i8_type(), "frombool").unwrap(), - _ => bool_to_i8( + // i1 -> i1 : %value ; no-op + // i1 -> i : zext i1 %value to i ; guaranteed to be 0 or 1 - see docs + // i -> i: zext i1 (icmp eq i %value, 0) to i ; same as i -> i1 -> i + match (value.get_type().get_bit_width(), ty.get_bit_width()) { + (1, 1) => value, + (1, _) => builder.build_int_z_extend(value, ty, "frombool").unwrap(), + _ => bool_to_int_type( builder, - ctx, builder - .build_int_compare( - IntPredicate::NE, - bool_value, - bool_value.get_type().const_zero(), - "", - ) + .build_int_compare(IntPredicate::NE, value, value.get_type().const_zero(), "tobool") .unwrap(), + ty, ), } }