Readd most of the implicit conversion code

This commit is contained in:
Andrzej Janik 2024-10-10 22:58:50 +02:00
commit d7a435ff42

View file

@ -577,31 +577,75 @@ impl<'a> MethodEmitContext<'a> {
let builder = self.builder; let builder = self.builder;
match conversion.kind { match conversion.kind {
ConversionKind::Default => { ConversionKind::Default => {
match (conversion.from_type, conversion.to_type) {
(ast::Type::Scalar(from_type), ast::Type::Scalar(to_type)) => {
let from_layout = conversion.from_type.layout(); let from_layout = conversion.from_type.layout();
let to_layout = conversion.to_type.layout(); let to_layout = conversion.to_type.layout();
if from_layout.size() == to_layout.size() { if from_layout.size() == to_layout.size() {
let dst_type = get_type(self.context, &conversion.to_type)?;
if from_type.kind() != ast::ScalarKind::Float
&& to_type.kind() != ast::ScalarKind::Float
{
// It is noop, but another instruction expects result of this conversion
self.resolver
.register(conversion.dst, self.resolver.value(conversion.src)?);
} else {
let src = self.resolver.value(conversion.src)?; let src = self.resolver.value(conversion.src)?;
let type_ = get_type(self.context, &conversion.to_type)?;
self.resolver.with_result(conversion.dst, |dst| unsafe { self.resolver.with_result(conversion.dst, |dst| unsafe {
LLVMBuildBitCast(builder, src, type_, dst) LLVMBuildBitCast(builder, src, dst_type, dst)
}); });
}
Ok(()) Ok(())
} else if to_layout.size() > from_layout.size() { } else {
// TODO: not entirely correct
let src = self.resolver.value(conversion.src)?; let src = self.resolver.value(conversion.src)?;
let type_ = get_type(self.context, &conversion.to_type)?; // This block is safe because it's illegal to implictly convert between floating point values
let same_width_bit_type = unsafe {
LLVMIntTypeInContext(self.context, (from_layout.size() * 8) as u32)
};
let same_width_bit_value = unsafe {
LLVMBuildBitCast(
builder,
src,
same_width_bit_type,
LLVM_UNNAMED.as_ptr(),
)
};
let wide_bit_type = unsafe {
LLVMIntTypeInContext(self.context, (to_layout.size() * 8) as u32)
};
if to_type.kind() == ast::ScalarKind::Unsigned
|| to_type.kind() == ast::ScalarKind::Bit
{
let llvm_fn = if to_type.size_of() >= from_type.size_of() {
LLVMBuildZExtOrBitCast
} else {
LLVMBuildTrunc
};
self.resolver.with_result(conversion.dst, |dst| unsafe { self.resolver.with_result(conversion.dst, |dst| unsafe {
LLVMBuildZExt(builder, src, type_, dst) llvm_fn(builder, same_width_bit_value, wide_bit_type, dst)
}); });
Ok(()) Ok(())
} else { } else {
// TODO: not entirely correct let conversion_fn = if from_type.kind() == ast::ScalarKind::Signed
let src = self.resolver.value(conversion.src)?; && to_type.kind() == ast::ScalarKind::Signed
let type_ = get_type(self.context, &conversion.to_type)?; {
self.resolver.with_result(conversion.dst, |dst| unsafe { if to_type.size_of() >= from_type.size_of() {
LLVMBuildTrunc(builder, src, type_, dst) LLVMBuildSExtOrBitCast
}); } else {
Ok(()) LLVMBuildTrunc
}
} else {
if to_type.size_of() >= from_type.size_of() {
LLVMBuildZExtOrBitCast
} else {
LLVMBuildTrunc
}
};
todo!()
}
}
}
_ => todo!(),
} }
} }
ConversionKind::SignExtend => todo!(), ConversionKind::SignExtend => todo!(),