[core] codegen: Add bool_to_int_type to replace bool_to_{i1,i8}

Unifies the implementation for both functions.
This commit is contained in:
David Mak 2025-02-07 14:01:10 +08:00
parent f52ba9f151
commit 529fa67855
3 changed files with 35 additions and 39 deletions

View File

@ -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
}

View File

@ -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)
}
}

View File

@ -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<N> : zext i1 %value to i<N> ; guaranteed to be 0 or 1 - see docs
// i<M> -> i<N>: zext i1 (icmp eq i<M> %value, 0) to i<N> ; same as i<M> -> i1 -> i<N>
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,
),
}
}