Use i8 for stack boolean variable allocation #321

Merged
sb10q merged 1 commits from issue-315 into master 2024-08-17 17:37:20 +08:00
5 changed files with 68 additions and 9 deletions

View File

@ -59,6 +59,8 @@ pub fn get_subst_key(
} }
impl<'ctx, 'a> CodeGenContext<'ctx, 'a> { impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
/// Builds a sequence of `getelementptr` and `load` instructions which stores the value of a
/// struct field into an LLVM value.
pub fn build_gep_and_load( pub fn build_gep_and_load(
&mut self, &mut self,
ptr: PointerValue<'ctx>, ptr: PointerValue<'ctx>,
@ -197,6 +199,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
) )
} }
/// Generates an LLVM variable for a [constant value][value] with a given [type][ty].
pub fn gen_const( pub fn gen_const(
&mut self, &mut self,
generator: &mut dyn CodeGenerator, generator: &mut dyn CodeGenerator,
@ -258,6 +261,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
} }
} }
/// Generates a binary operation `op` between two integral operands `lhs` and `rhs`.
pub fn gen_int_ops( pub fn gen_int_ops(
&mut self, &mut self,
generator: &mut dyn CodeGenerator, generator: &mut dyn CodeGenerator,
@ -302,6 +306,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
} }
} }
/// Generates a binary operation `op` between two floating-point operands `lhs` and `rhs`.
pub fn gen_float_ops( pub fn gen_float_ops(
&mut self, &mut self,
op: &Operator, op: &Operator,
@ -424,6 +429,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
} }
} }
/// Helper function for generating a LLVM variable storing a [String].
pub fn gen_string<S: Into<String>>( pub fn gen_string<S: Into<String>>(
&mut self, &mut self,
generator: &mut dyn CodeGenerator, generator: &mut dyn CodeGenerator,
@ -523,6 +529,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
} }
} }
/// See [CodeGenerator::gen_constructor].
pub fn gen_constructor<'ctx, 'a, G: CodeGenerator>( pub fn gen_constructor<'ctx, 'a, G: CodeGenerator>(
generator: &mut G, generator: &mut G,
ctx: &mut CodeGenContext<'ctx, 'a>, ctx: &mut CodeGenContext<'ctx, 'a>,
@ -554,6 +561,7 @@ pub fn gen_constructor<'ctx, 'a, G: CodeGenerator>(
} }
} }
/// See [CodeGenerator::gen_func_instance].
pub fn gen_func_instance<'ctx, 'a>( pub fn gen_func_instance<'ctx, 'a>(
ctx: &mut CodeGenContext<'ctx, 'a>, ctx: &mut CodeGenContext<'ctx, 'a>,
obj: Option<(Type, ValueEnum<'ctx>)>, obj: Option<(Type, ValueEnum<'ctx>)>,
@ -630,6 +638,7 @@ pub fn gen_func_instance<'ctx, 'a>(
} }
} }
/// See [CodeGenerator::gen_call].
pub fn gen_call<'ctx, 'a, G: CodeGenerator>( pub fn gen_call<'ctx, 'a, G: CodeGenerator>(
generator: &mut G, generator: &mut G,
ctx: &mut CodeGenContext<'ctx, 'a>, ctx: &mut CodeGenContext<'ctx, 'a>,
@ -789,6 +798,8 @@ pub fn gen_call<'ctx, 'a, G: CodeGenerator>(
Ok(ctx.build_call_or_invoke(fun_val, &param_vals, "call")) Ok(ctx.build_call_or_invoke(fun_val, &param_vals, "call"))
} }
/// Generates three LLVM variables representing the start, stop, and step values of a [range] class
/// respectively.
pub fn destructure_range<'ctx, 'a>( pub fn destructure_range<'ctx, 'a>(
ctx: &mut CodeGenContext<'ctx, 'a>, ctx: &mut CodeGenContext<'ctx, 'a>,
range: PointerValue<'ctx>, range: PointerValue<'ctx>,
@ -857,6 +868,7 @@ pub fn allocate_list<'ctx, 'a, G: CodeGenerator>(
arr_str_ptr arr_str_ptr
} }
/// Generates LLVM IR for a [list comprehension expression][expr].
pub fn gen_comprehension<'ctx, 'a, G: CodeGenerator>( pub fn gen_comprehension<'ctx, 'a, G: CodeGenerator>(
generator: &mut G, generator: &mut G,
ctx: &mut CodeGenContext<'ctx, 'a>, ctx: &mut CodeGenContext<'ctx, 'a>,
@ -1026,6 +1038,13 @@ pub fn gen_comprehension<'ctx, 'a, G: CodeGenerator>(
} }
} }
/// Generates LLVM IR for a [binary operator expression][expr].
///
/// * `left` - The left-hand side of the binary operator.
/// * `op` - The operator applied on the operands.
/// * `right` - The right-hand side of the binary operator.
/// * `loc` - The location of the full expression.
/// * `is_aug_assign` - Whether the binary operator expression is also an assignment operator.
pub fn gen_binop_expr<'ctx, 'a, G: CodeGenerator>( pub fn gen_binop_expr<'ctx, 'a, G: CodeGenerator>(
generator: &mut G, generator: &mut G,
ctx: &mut CodeGenContext<'ctx, 'a>, ctx: &mut CodeGenContext<'ctx, 'a>,
@ -1122,6 +1141,7 @@ pub fn gen_binop_expr<'ctx, 'a, G: CodeGenerator>(
} }
} }
/// See [CodeGenerator::gen_expr].
pub fn gen_expr<'ctx, 'a, G: CodeGenerator>( pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
generator: &mut G, generator: &mut G,
ctx: &mut CodeGenContext<'ctx, 'a>, ctx: &mut CodeGenContext<'ctx, 'a>,

View File

@ -181,7 +181,7 @@ pub trait CodeGenerator {
gen_stmt(self, ctx, stmt) gen_stmt(self, ctx, stmt)
} }
/// Converts the value of [a boolean-like value][bool_value] into an `i1`. /// See [bool_to_i1].
fn bool_to_i1<'ctx, 'a>( fn bool_to_i1<'ctx, 'a>(
&self, &self,
ctx: &CodeGenContext<'ctx, 'a>, ctx: &CodeGenContext<'ctx, 'a>,
@ -190,7 +190,7 @@ pub trait CodeGenerator {
bool_to_i1(&ctx.builder, bool_value) bool_to_i1(&ctx.builder, bool_value)
} }
/// Converts the value of [a boolean-like value][bool_value] into an `i8`. /// See [bool_to_i8].
fn bool_to_i8<'ctx, 'a>( fn bool_to_i8<'ctx, 'a>(
&self, &self,
ctx: &CodeGenContext<'ctx, 'a>, ctx: &CodeGenContext<'ctx, 'a>,

View File

@ -357,7 +357,7 @@ pub struct CodeGenTask {
/// Retrieves the [LLVM type][BasicTypeEnum] corresponding to the [Type]. /// Retrieves the [LLVM type][BasicTypeEnum] corresponding to the [Type].
/// ///
/// This function is used to obtain the in-memory representation of [ty], e.g. a `bool` variable /// This function is used to obtain the in-memory representation of `ty`, e.g. a `bool` variable
/// would be represented by an `i8`. /// would be represented by an `i8`.
fn get_llvm_type<'ctx>( fn get_llvm_type<'ctx>(
ctx: &'ctx Context, ctx: &'ctx Context,
@ -472,7 +472,7 @@ fn get_llvm_type<'ctx>(
/// Retrieves the [LLVM type][BasicTypeEnum] corresponding to the [Type]. /// Retrieves the [LLVM type][BasicTypeEnum] corresponding to the [Type].
/// ///
/// This function is used mainly to obtain the ABI representation of [ty], e.g. a `bool` is /// This function is used mainly to obtain the ABI representation of `ty`, e.g. a `bool` is
/// would be represented by an `i1`. /// would be represented by an `i1`.
/// ///
/// The difference between the in-memory representation (as returned by [get_llvm_type]) and the /// The difference between the in-memory representation (as returned by [get_llvm_type]) and the
@ -511,6 +511,7 @@ fn need_sret<'ctx>(ctx: &'ctx Context, ty: BasicTypeEnum<'ctx>) -> bool {
need_sret_impl(ctx, ty, true) need_sret_impl(ctx, ty, true)
} }
/// Implementation for generating LLVM IR for a function.
pub fn gen_func_impl<'ctx, G: CodeGenerator, F: FnOnce(&mut G, &mut CodeGenContext) -> Result<(), String>> ( pub fn gen_func_impl<'ctx, G: CodeGenerator, F: FnOnce(&mut G, &mut CodeGenContext) -> Result<(), String>> (
context: &'ctx Context, context: &'ctx Context,
generator: &mut G, generator: &mut G,
@ -835,6 +836,15 @@ pub fn gen_func_impl<'ctx, G: CodeGenerator, F: FnOnce(&mut G, &mut CodeGenConte
Ok((builder, module, fn_val)) Ok((builder, module, fn_val))
} }
/// Generates LLVM IR for a function.
///
/// * `context` - The [LLVM Context][Context] used in generating the function body.
/// * `generator` - The [CodeGenerator] for generating various program constructs.
/// * `registry` - The [WorkerRegistry] responsible for monitoring this function generation task.
/// * `builder` - The [Builder] used for generating LLVM IR.
/// * `module` - The [Module] of which the generated LLVM function will be inserted into.
/// * `task` - The [CodeGenTask] associated with this function generation task.
///
pub fn gen_func<'ctx, G: CodeGenerator>( pub fn gen_func<'ctx, G: CodeGenerator>(
context: &'ctx Context, context: &'ctx Context,
generator: &mut G, generator: &mut G,
@ -852,7 +862,7 @@ pub fn gen_func<'ctx, G: CodeGenerator>(
}) })
} }
/// Converts the value of [a boolean-like value][bool_value] into an `i1`. /// 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> { fn bool_to_i1<'ctx>(builder: &Builder<'ctx>, bool_value: IntValue<'ctx>) -> IntValue<'ctx> {
if bool_value.get_type().get_bit_width() != 1 { if bool_value.get_type().get_bit_width() != 1 {
builder.build_int_compare( builder.build_int_compare(
@ -866,7 +876,7 @@ fn bool_to_i1<'ctx>(builder: &Builder<'ctx>, bool_value: IntValue<'ctx>) -> IntV
} }
} }
/// Converts the value of [a boolean-like value][bool_value] into an `i8`. /// Converts the value of a boolean-like value `bool_value` into an `i8`.
fn bool_to_i8<'ctx>( fn bool_to_i8<'ctx>(
builder: &Builder<'ctx>, builder: &Builder<'ctx>,
ctx: &'ctx Context, ctx: &'ctx Context,

View File

@ -21,6 +21,7 @@ use nac3parser::ast::{
}; };
use std::convert::TryFrom; use std::convert::TryFrom;
/// See [CodeGenerator::gen_var_alloc].
pub fn gen_var<'ctx, 'a>( pub fn gen_var<'ctx, 'a>(
ctx: &mut CodeGenContext<'ctx, 'a>, ctx: &mut CodeGenContext<'ctx, 'a>,
ty: BasicTypeEnum<'ctx>, ty: BasicTypeEnum<'ctx>,
@ -35,6 +36,7 @@ pub fn gen_var<'ctx, 'a>(
Ok(ptr) Ok(ptr)
} }
/// See [CodeGenerator::gen_store_target].
pub fn gen_store_target<'ctx, 'a, G: CodeGenerator>( pub fn gen_store_target<'ctx, 'a, G: CodeGenerator>(
generator: &mut G, generator: &mut G,
ctx: &mut CodeGenContext<'ctx, 'a>, ctx: &mut CodeGenContext<'ctx, 'a>,
@ -144,6 +146,7 @@ pub fn gen_store_target<'ctx, 'a, G: CodeGenerator>(
}) })
} }
/// See [CodeGenerator::gen_assign].
pub fn gen_assign<'ctx, 'a, G: CodeGenerator>( pub fn gen_assign<'ctx, 'a, G: CodeGenerator>(
generator: &mut G, generator: &mut G,
ctx: &mut CodeGenContext<'ctx, 'a>, ctx: &mut CodeGenContext<'ctx, 'a>,
@ -214,13 +217,21 @@ pub fn gen_assign<'ctx, 'a, G: CodeGenerator>(
Ok(()) Ok(())
} }
/// Generates a sequence of IR which checks whether [value] does not exceed the upper bound of the /// Generates a sequence of IR which checks whether `value` does not exceed the upper bound of the
/// range as defined by [stop] and [step]. /// range as defined by `stop` and `step`.
/// ///
/// Note that the generated IR will **not** check whether value is part of the range or whether /// Note that the generated IR will **not** check whether value is part of the range or whether
/// value exceeds the lower bound of the range (as evident by the missing `start` argument). /// value exceeds the lower bound of the range (as evident by the missing `start` argument).
/// ///
/// Returns an [IntValue] representing the result of whether the [value] is in the range. /// The generated IR is equivalent to the following Rust code:
///
/// ```rust,ignore
/// let sign = step > 0;
/// let (lo, hi) = if sign { (value, stop) } else { (stop, value) };
/// let cmp = lo < hi;
/// ```
///
/// Returns an `i1` [IntValue] representing the result of whether the `value` is in the range.
fn gen_in_range_check<'ctx, 'a>( fn gen_in_range_check<'ctx, 'a>(
ctx: &CodeGenContext<'ctx, 'a>, ctx: &CodeGenContext<'ctx, 'a>,
value: IntValue<'ctx>, value: IntValue<'ctx>,
@ -234,6 +245,7 @@ fn gen_in_range_check<'ctx, 'a>(
ctx.builder.build_int_compare(IntPredicate::SLT, lo, hi, "cmp") ctx.builder.build_int_compare(IntPredicate::SLT, lo, hi, "cmp")
} }
/// See [CodeGenerator::gen_for].
pub fn gen_for<'ctx, 'a, G: CodeGenerator>( pub fn gen_for<'ctx, 'a, G: CodeGenerator>(
generator: &mut G, generator: &mut G,
ctx: &mut CodeGenContext<'ctx, 'a>, ctx: &mut CodeGenContext<'ctx, 'a>,
@ -384,6 +396,7 @@ pub fn gen_for<'ctx, 'a, G: CodeGenerator>(
Ok(()) Ok(())
} }
/// See [CodeGenerator::gen_while].
pub fn gen_while<'ctx, 'a, G: CodeGenerator>( pub fn gen_while<'ctx, 'a, G: CodeGenerator>(
generator: &mut G, generator: &mut G,
ctx: &mut CodeGenContext<'ctx, 'a>, ctx: &mut CodeGenContext<'ctx, 'a>,
@ -447,6 +460,7 @@ pub fn gen_while<'ctx, 'a, G: CodeGenerator>(
Ok(()) Ok(())
} }
/// See [CodeGenerator::gen_if].
pub fn gen_if<'ctx, 'a, G: CodeGenerator>( pub fn gen_if<'ctx, 'a, G: CodeGenerator>(
generator: &mut G, generator: &mut G,
ctx: &mut CodeGenContext<'ctx, 'a>, ctx: &mut CodeGenContext<'ctx, 'a>,
@ -535,6 +549,8 @@ pub fn final_proxy<'ctx, 'a>(
final_paths.push(block); final_paths.push(block);
} }
/// Inserts the declaration of the builtin function with the specified `symbol` name, and returns
/// the function.
pub fn get_builtins<'ctx, 'a>( pub fn get_builtins<'ctx, 'a>(
generator: &mut dyn CodeGenerator, generator: &mut dyn CodeGenerator,
ctx: &mut CodeGenContext<'ctx, 'a>, ctx: &mut CodeGenContext<'ctx, 'a>,
@ -632,6 +648,10 @@ pub fn exn_constructor<'ctx, 'a>(
Ok(Some(zelf.into())) Ok(Some(zelf.into()))
} }
/// Generates IR for a `raise` statement.
///
/// * `exception` - The exception thrown by the `raise` statement.
/// * `loc` - The location where the exception is raised from.
pub fn gen_raise<'ctx, 'a>( pub fn gen_raise<'ctx, 'a>(
generator: &mut dyn CodeGenerator, generator: &mut dyn CodeGenerator,
ctx: &mut CodeGenContext<'ctx, 'a>, ctx: &mut CodeGenContext<'ctx, 'a>,
@ -683,6 +703,7 @@ pub fn gen_raise<'ctx, 'a>(
ctx.builder.build_unreachable(); ctx.builder.build_unreachable();
} }
/// Generates IR for a `try` statement.
pub fn gen_try<'ctx, 'a, G: CodeGenerator>( pub fn gen_try<'ctx, 'a, G: CodeGenerator>(
generator: &mut G, generator: &mut G,
ctx: &mut CodeGenContext<'ctx, 'a>, ctx: &mut CodeGenContext<'ctx, 'a>,
@ -1005,6 +1026,7 @@ pub fn gen_try<'ctx, 'a, G: CodeGenerator>(
} }
} }
/// See [CodeGenerator::gen_with].
pub fn gen_with<'ctx, 'a, G: CodeGenerator>( pub fn gen_with<'ctx, 'a, G: CodeGenerator>(
_: &mut G, _: &mut G,
_: &mut CodeGenContext<'ctx, 'a>, _: &mut CodeGenContext<'ctx, 'a>,
@ -1014,6 +1036,7 @@ pub fn gen_with<'ctx, 'a, G: CodeGenerator>(
Err(format!("With statement with custom types is not yet supported (at {})", stmt.location)) Err(format!("With statement with custom types is not yet supported (at {})", stmt.location))
} }
/// Generates IR for a `return` statement.
pub fn gen_return<'ctx, 'a, G: CodeGenerator>( pub fn gen_return<'ctx, 'a, G: CodeGenerator>(
generator: &mut G, generator: &mut G,
ctx: &mut CodeGenContext<'ctx, 'a>, ctx: &mut CodeGenContext<'ctx, 'a>,
@ -1062,6 +1085,7 @@ pub fn gen_return<'ctx, 'a, G: CodeGenerator>(
Ok(()) Ok(())
} }
/// See [CodeGenerator::gen_stmt].
pub fn gen_stmt<'ctx, 'a, G: CodeGenerator>( pub fn gen_stmt<'ctx, 'a, G: CodeGenerator>(
generator: &mut G, generator: &mut G,
ctx: &mut CodeGenContext<'ctx, 'a>, ctx: &mut CodeGenContext<'ctx, 'a>,
@ -1153,6 +1177,7 @@ pub fn gen_stmt<'ctx, 'a, G: CodeGenerator>(
Ok(()) Ok(())
} }
/// Generates IR for a block statement contains `stmts`.
pub fn gen_block<'ctx, 'a, 'b, G: CodeGenerator, I: Iterator<Item = &'b Stmt<Option<Type>>>>( pub fn gen_block<'ctx, 'a, 'b, G: CodeGenerator, I: Iterator<Item = &'b Stmt<Option<Type>>>>(
generator: &mut G, generator: &mut G,
ctx: &mut CodeGenContext<'ctx, 'a>, ctx: &mut CodeGenContext<'ctx, 'a>,

View File

@ -59,6 +59,7 @@ impl Display for SymbolValue {
} }
pub trait StaticValue { pub trait StaticValue {
/// Returns a unique identifier for this value.
fn get_unique_identifier(&self) -> u64; fn get_unique_identifier(&self) -> u64;
fn get_const_obj<'ctx, 'a>( fn get_const_obj<'ctx, 'a>(
@ -67,6 +68,7 @@ pub trait StaticValue {
generator: &mut dyn CodeGenerator, generator: &mut dyn CodeGenerator,
) -> BasicValueEnum<'ctx>; ) -> BasicValueEnum<'ctx>;
/// Converts this value to a LLVM [BasicValueEnum].
fn to_basic_value_enum<'ctx, 'a>( fn to_basic_value_enum<'ctx, 'a>(
&self, &self,
ctx: &mut CodeGenContext<'ctx, 'a>, ctx: &mut CodeGenContext<'ctx, 'a>,
@ -74,12 +76,14 @@ pub trait StaticValue {
expected_ty: Type, expected_ty: Type,
) -> Result<BasicValueEnum<'ctx>, String>; ) -> Result<BasicValueEnum<'ctx>, String>;
/// Returns a field within this value.
fn get_field<'ctx, 'a>( fn get_field<'ctx, 'a>(
&self, &self,
name: StrRef, name: StrRef,
ctx: &mut CodeGenContext<'ctx, 'a>, ctx: &mut CodeGenContext<'ctx, 'a>,
) -> Option<ValueEnum<'ctx>>; ) -> Option<ValueEnum<'ctx>>;
/// Returns a single element of this tuple.
fn get_tuple_element<'ctx>(&self, index: u32) -> Option<ValueEnum<'ctx>>; fn get_tuple_element<'ctx>(&self, index: u32) -> Option<ValueEnum<'ctx>>;
} }