Skip to content

Commit

Permalink
__transmute const evaluation
Browse files Browse the repository at this point in the history
  • Loading branch information
xunilrj committed Nov 12, 2024
1 parent 6c83607 commit a49593b
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 1 deletion.
95 changes: 94 additions & 1 deletion sway-core/src/ir_generation/const_eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1363,7 +1363,100 @@ fn const_eval_intrinsic(
}),
}
}
Intrinsic::Transmute => todo!(),
Intrinsic::Transmute => {
let src_type = &intrinsic.type_arguments[0];
let src_ir_type = convert_resolved_type_id(
lookup.engines.te(),
lookup.engines.de(),
lookup.context,
src_type.type_id,
&src_type.span,
)
.unwrap();

let dst_type = &intrinsic.type_arguments[1];
let dst_ir_type = convert_resolved_type_id(
lookup.engines.te(),
lookup.engines.de(),
lookup.context,
dst_type.type_id,
&dst_type.span,
)
.unwrap();

fn bytes_to_uint<'a, const N: usize>(
context: &mut Context<'_>,
items: impl Iterator<Item = &'a Constant>,
) -> [u8; N]
where
[u8; N]: TryFrom<Vec<u8>>,
<[u8; N] as TryFrom<Vec<u8>>>::Error: std::fmt::Debug,
{
let mut bytes = Vec::<u8>::with_capacity(N);

for item in items {
assert!(item.ty.is_uint8(context));
match item.value {
ConstantValue::Uint(v) => {
let v = v.try_into().unwrap();
bytes.push(v);
}
_ => unreachable!(),
};
}

bytes.try_into().unwrap()
}

fn check_is_zero<'a>(items: &mut impl Iterator<Item = &'a Constant>, n: usize) {
for item in items.by_ref().take(n) {
if item.as_uint().unwrap() != 0 {
todo!();
}
}
}

// TODO check sizes
match (
src_ir_type.get_content(lookup.context),
dst_ir_type.get_content(lookup.context),
&args[0].value,
) {
(
TypeContent::Array(item_type, 8),
TypeContent::Uint(64),
ConstantValue::Array(items),
) if item_type.is_uint8(lookup.context) => {
assert!(items.len() == 8);

let mut items = items.iter();
let value = match &*lookup.engines.te().get(intrinsic.type_arguments[1].type_id)
{
TypeInfo::UnsignedInteger(IntegerBits::Sixteen) => {
check_is_zero(&mut items, 6);
let bytes = bytes_to_uint::<2>(lookup.context, items);
ConstantValue::Uint(u16::from_be_bytes(bytes) as u64)
}
TypeInfo::UnsignedInteger(IntegerBits::ThirtyTwo) => {
check_is_zero(&mut items, 4);
let bytes = bytes_to_uint::<4>(lookup.context, items);
ConstantValue::Uint(u32::from_be_bytes(bytes) as u64)
}
TypeInfo::UnsignedInteger(IntegerBits::SixtyFour) => {
let bytes = bytes_to_uint::<8>(lookup.context, items);
ConstantValue::Uint(u64::from_be_bytes(bytes))
}
_ => todo!(),
};

Ok(Some(Constant {
ty: Type::get_uint64(lookup.context),
value,
}))
}
_ => todo!(),
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,22 @@ pub struct SomeStruct {
value: u64
}

fn const_transmute() {
// u16 needs 8 bytes as u64
const U8ARRAY_U16 = __transmute::<[u8; 8], u16>([0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 2u8]);
assert(U8ARRAY_U16 == 0x0102u16);

// u32 needs 8 bytes as u64
const U8ARRAY_U32 = __transmute::<[u8; 8], u32>([0u8, 0u8, 0u8, 0u8, 1u8, 2u8, 3u8, 4u8]);
assert(U8ARRAY_U32 == 0x01020304u32);

const U8ARRAY_U64 = __transmute::<[u8; 8], u64>([1u8, 2u8, 3u8, 4u8, 5u8, 6u8, 7u8, 8u8]);
assert(U8ARRAY_U64 == 0x0102030405060708u64);
}

fn main() {
const_transmute();

// Check transmute work as nop
let u8_u8 = __transmute::<u8, u8>(1);
assert(u8_u8 == 1);
Expand Down

0 comments on commit a49593b

Please sign in to comment.