core: Fix handling of float-to-int32 casts

Out-of-bound conversions should be wrapped around.
This commit is contained in:
David Mak 2023-11-03 15:05:40 +08:00
parent 447eb9c387
commit 7a5a2db842
1 changed files with 58 additions and 29 deletions

View File

@ -477,12 +477,16 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
resolver: None, resolver: None,
codegen_callback: Some(Arc::new(GenCall::new(Box::new( codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|ctx, _, fun, args, generator| { |ctx, _, fun, args, generator| {
let int32 = ctx.primitives.int32; let PrimitiveStore {
let int64 = ctx.primitives.int64; int32,
let uint32 = ctx.primitives.uint32; int64,
let uint64 = ctx.primitives.uint64; uint32,
let float = ctx.primitives.float; uint64,
let boolean = ctx.primitives.bool; float,
bool: boolean,
..
} = ctx.primitives;
let arg_ty = fun.0.args[0].ty; let arg_ty = fun.0.args[0].ty;
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator, arg_ty)?; let arg = args[0].1.clone().to_basic_value_enum(ctx, generator, arg_ty)?;
Ok(if ctx.unifier.unioned(arg_ty, boolean) { Ok(if ctx.unifier.unioned(arg_ty, boolean) {
@ -512,15 +516,21 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
.into(), .into(),
) )
} else if ctx.unifier.unioned(arg_ty, float) { } else if ctx.unifier.unioned(arg_ty, float) {
let val = ctx let to_int64 = ctx
.builder .builder
.build_float_to_signed_int( .build_float_to_signed_int(
arg.into_float_value(), arg.into_float_value(),
ctx.ctx.i64_type(),
"",
);
let val = ctx.builder
.build_int_truncate(
to_int64,
ctx.ctx.i32_type(), ctx.ctx.i32_type(),
"fptosi", "conv",
) );
.into();
Some(val) Some(val.into())
} else { } else {
unreachable!() unreachable!()
}) })
@ -542,12 +552,16 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
resolver: None, resolver: None,
codegen_callback: Some(Arc::new(GenCall::new(Box::new( codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|ctx, _, fun, args, generator| { |ctx, _, fun, args, generator| {
let int32 = ctx.primitives.int32; let PrimitiveStore {
let int64 = ctx.primitives.int64; int32,
let uint32 = ctx.primitives.uint32; int64,
let uint64 = ctx.primitives.uint64; uint32,
let float = ctx.primitives.float; uint64,
let boolean = ctx.primitives.bool; float,
bool: boolean,
..
} = ctx.primitives;
let arg_ty = fun.0.args[0].ty; let arg_ty = fun.0.args[0].ty;
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator, arg_ty)?; let arg = args[0].1.clone().to_basic_value_enum(ctx, generator, arg_ty)?;
Ok( Ok(
@ -609,12 +623,16 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
resolver: None, resolver: None,
codegen_callback: Some(Arc::new(GenCall::new(Box::new( codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|ctx, _, fun, args, generator| { |ctx, _, fun, args, generator| {
let int32 = ctx.primitives.int32; let PrimitiveStore {
let int64 = ctx.primitives.int64; int32,
let uint32 = ctx.primitives.uint32; int64,
let uint64 = ctx.primitives.uint64; uint32,
let float = ctx.primitives.float; uint64,
let boolean = ctx.primitives.bool; float,
bool: boolean,
..
} = ctx.primitives;
let arg_ty = fun.0.args[0].ty; let arg_ty = fun.0.args[0].ty;
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator, arg_ty)?; let arg = args[0].1.clone().to_basic_value_enum(ctx, generator, arg_ty)?;
let res = if ctx.unifier.unioned(arg_ty, boolean) { let res = if ctx.unifier.unioned(arg_ty, boolean) {
@ -661,12 +679,16 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
resolver: None, resolver: None,
codegen_callback: Some(Arc::new(GenCall::new(Box::new( codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|ctx, _, fun, args, generator| { |ctx, _, fun, args, generator| {
let int32 = ctx.primitives.int32; let PrimitiveStore {
let int64 = ctx.primitives.int64; int32,
let uint32 = ctx.primitives.uint32; int64,
let uint64 = ctx.primitives.uint64; uint32,
let float = ctx.primitives.float; uint64,
let boolean = ctx.primitives.bool; float,
bool: boolean,
..
} = ctx.primitives;
let arg_ty = fun.0.args[0].ty; let arg_ty = fun.0.args[0].ty;
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator, arg_ty)?; let arg = args[0].1.clone().to_basic_value_enum(ctx, generator, arg_ty)?;
let res = if ctx.unifier.unioned(arg_ty, int32) let res = if ctx.unifier.unioned(arg_ty, int32)
@ -727,6 +749,13 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
.build_signed_int_to_float(arg, ctx.ctx.f64_type(), "sitofp") .build_signed_int_to_float(arg, ctx.ctx.f64_type(), "sitofp")
.into(); .into();
Some(val) Some(val)
} else if [uint32, uint64].iter().any(|ty| ctx.unifier.unioned(arg_ty, *ty)) {
let arg = arg.into_int_value();
let val = ctx
.builder
.build_unsigned_int_to_float(arg, ctx.ctx.f64_type(), "uitofp")
.into();
Some(val)
} else if ctx.unifier.unioned(arg_ty, float) { } else if ctx.unifier.unioned(arg_ty, float) {
Some(arg) Some(arg)
} else { } else {