diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 3b4e4cd..b4b3544 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -221,8 +221,10 @@ impl<'a, S: SyscallHandler> Interpreter<'a, S> { fields: ty.struct_fields(self.ir_module).unwrap(), }) } - ir::Instruction::IsZero(_) => todo!("Interpreter / ir::Instruction::IsZero"), - ir::Instruction::IsNonZero(value) => { + ir::Instruction::IsZero(_value, _) => { + todo!("Interpreter / ir::Instruction::IsZero") + } + ir::Instruction::IsNonZero(value, _) => { let value = self.eval(®isters, value); match value { diff --git a/src/ir/mod.rs b/src/ir/mod.rs index e04e056..0f9f66a 100644 --- a/src/ir/mod.rs +++ b/src/ir/mod.rs @@ -134,8 +134,8 @@ pub enum Instruction { index: Value, }, StructLiteral(Type, Vec), - IsZero(Value), - IsNonZero(Value), + IsZero(Value, FloatOrInteger), + IsNonZero(Value, FloatOrInteger), Negate(Value), NegateFloat(Value), BitComplement(Value), diff --git a/src/llvm_backend/functions/block.rs b/src/llvm_backend/functions/block.rs index 1dcc3e4..d3d5dae 100644 --- a/src/llvm_backend/functions/block.rs +++ b/src/llvm_backend/functions/block.rs @@ -44,7 +44,7 @@ use llvm_sys::{ core::*, prelude::{LLVMTypeRef, LLVMValueRef}, LLVMIntPredicate::*, - LLVMRealPredicate::*, + LLVMRealPredicate::{self, *}, }; use std::{borrow::Cow, ptr::null_mut, sync::atomic}; @@ -568,13 +568,37 @@ pub unsafe fn create_function_block( Some(literal) } - Instruction::IsZero(inner) => { + Instruction::IsZero(inner, floating) => { let value = build_value(ctx, value_catalog, builder, inner)?; - Some(LLVMBuildIsNull(builder.get(), value, cstr!("").as_ptr())) + + Some(match floating { + FloatOrInteger::Integer => { + LLVMBuildIsNull(builder.get(), value, cstr!("").as_ptr()) + } + FloatOrInteger::Float => LLVMBuildFCmp( + builder.get(), + LLVMRealPredicate::LLVMRealOEQ, + value, + LLVMConstNull(LLVMTypeOf(value)), + cstr!("").as_ptr(), + ), + }) } - Instruction::IsNonZero(inner) => { + Instruction::IsNonZero(inner, floating) => { let value = build_value(ctx, value_catalog, builder, inner)?; - Some(LLVMBuildIsNotNull(builder.get(), value, cstr!("").as_ptr())) + + Some(match floating { + FloatOrInteger::Integer => { + LLVMBuildIsNotNull(builder.get(), value, cstr!("").as_ptr()) + } + FloatOrInteger::Float => LLVMBuildFCmp( + builder.get(), + LLVMRealPredicate::LLVMRealONE, + value, + LLVMConstNull(LLVMTypeOf(value)), + cstr!("").as_ptr(), + ), + }) } Instruction::Negate(inner) => { let value = build_value(ctx, value_catalog, builder, inner)?; diff --git a/src/lower/mod.rs b/src/lower/mod.rs index 6b7fe3a..5a2bf10 100644 --- a/src/lower/mod.rs +++ b/src/lower/mod.rs @@ -816,11 +816,20 @@ fn lower_expr( let UnaryMathOperation { operator, inner } = &**operation; let value = lower_expr(builder, ir_module, &inner.expr, function, resolved_ast)?; + let float_or_int = inner + .resolved_type + .kind + .is_float_like() + .then_some(FloatOrInteger::Float) + .unwrap_or(FloatOrInteger::Integer); + let instruction = match operator { - resolved::UnaryMathOperator::Not => ir::Instruction::IsZero(value), + resolved::UnaryMathOperator::Not => ir::Instruction::IsZero(value, float_or_int), resolved::UnaryMathOperator::BitComplement => ir::Instruction::BitComplement(value), resolved::UnaryMathOperator::Negate => ir::Instruction::Negate(value), - resolved::UnaryMathOperator::IsNonZero => ir::Instruction::IsNonZero(value), + resolved::UnaryMathOperator::IsNonZero => { + ir::Instruction::IsNonZero(value, float_or_int) + } }; Ok(builder.push(instruction)) diff --git a/src/resolve/expr/call.rs b/src/resolve/expr/call.rs index 1134e42..79a9350 100644 --- a/src/resolve/expr/call.rs +++ b/src/resolve/expr/call.rs @@ -35,6 +35,7 @@ pub fn resolve_call_expr( let name = &call.function_name.basename; let target_type_kind = match name.as_ref() { + "bool" => Some(resolved::TypeKind::Boolean), "u8" => Some(resolved::TypeKind::u8()), "u16" => Some(resolved::TypeKind::u16()), "u32" => Some(resolved::TypeKind::u32()), @@ -87,8 +88,32 @@ pub fn resolve_call_expr( _ => None, }; + let argument_type_kind = &arguments[0].resolved_type.kind; + if let Some(target_type_kind) = target_type_kind { - if arguments[0].resolved_type.kind.is_floating() { + if target_type_kind.is_boolean() + && (argument_type_kind.is_integer_like() || argument_type_kind.is_float_like()) + { + let target_type = target_type_kind.at(source); + let argument = arguments.into_iter().next().unwrap(); + let is_initialized = argument.is_initialized; + + let expr = resolved::ExprKind::UnaryMathOperation(Box::new( + resolved::UnaryMathOperation { + operator: resolved::UnaryMathOperator::IsNonZero, + inner: argument, + }, + )) + .at(source); + + return Ok(TypedExpr { + resolved_type: target_type, + expr, + is_initialized, + }); + } + + if argument_type_kind.is_floating() { let target_type = target_type_kind.at(source); let argument = arguments.into_iter().next().unwrap(); @@ -104,16 +129,56 @@ pub fn resolve_call_expr( is_initialized: argument.is_initialized, }); } + + if argument_type_kind.is_integer_like() || argument_type_kind.is_boolean() { + let target_type = target_type_kind.at(source); + let argument = arguments.into_iter().next().unwrap(); + + let expr = resolved::ExprKind::IntegerCast(Box::new(CastFrom { + cast: Cast { + target_type: target_type.clone(), + value: argument.expr, + }, + from_type: argument.resolved_type, + })) + .at(source); + + return Ok(TypedExpr { + resolved_type: target_type, + expr, + is_initialized: argument.is_initialized, + }); + } } let target_type_kind = match name.as_ref() { - "f32" => Some(resolved::TypeKind::f32()), - "f64" => Some(resolved::TypeKind::f64()), + "f32" | "float" => Some(resolved::TypeKind::f32()), + "f64" | "double" => Some(resolved::TypeKind::f64()), _ => None, }; if let Some(target_type_kind) = target_type_kind { - if arguments[0].resolved_type.kind.is_integer_like() { + if argument_type_kind.is_boolean() { + let target_type = target_type_kind.at(source); + let argument = arguments.into_iter().next().unwrap(); + let is_initialized = argument.is_initialized; + + let expr = resolved::ExprKind::UnaryMathOperation(Box::new( + resolved::UnaryMathOperation { + operator: resolved::UnaryMathOperator::IsNonZero, + inner: argument, + }, + )) + .at(source); + + return Ok(TypedExpr { + resolved_type: target_type, + expr, + is_initialized, + }); + } + + if argument_type_kind.is_integer_like() { let target_type = target_type_kind.at(source); let argument = arguments.into_iter().next().unwrap(); diff --git a/src/resolved/mod.rs b/src/resolved/mod.rs index bfe84b9..1f594da 100644 --- a/src/resolved/mod.rs +++ b/src/resolved/mod.rs @@ -316,6 +316,10 @@ impl TypeKind { ) } + pub fn is_float_like(&self) -> bool { + matches!(self, Self::Floating(..) | Self::FloatLiteral(..)) + } + pub fn is_ambiguous(&self) -> bool { self.is_integer_literal() } @@ -354,7 +358,7 @@ impl TypeKind { pub fn sign(&self, target: Option<&Target>) -> Option { match self { - TypeKind::Boolean => None, + TypeKind::Boolean => Some(IntegerSign::Unsigned), TypeKind::Integer(_, sign) => Some(*sign), TypeKind::IntegerLiteral(value) => Some(if value >= &BigInt::zero() { IntegerSign::Unsigned