diff --git a/crates/aarch64/src/lib.rs b/crates/aarch64/src/lib.rs index 22ee0ac..3feef97 100644 --- a/crates/aarch64/src/lib.rs +++ b/crates/aarch64/src/lib.rs @@ -1198,7 +1198,7 @@ fn lower_control_pcode( destination: lower_place(language, output)?, left: lower_value(language, left)?, right: lower_value(language, right)?, - element_size: arguments[0]?, + element_size: neon_comparison_element_size(language, left, arguments[0])?, }), NEON_UNSIGNED_MAXIMUM_ACROSS_USER_OP => { Some(Operation::NeonUnsignedMaximumAcross { @@ -1225,7 +1225,7 @@ fn lower_control_pcode( destination: lower_place(language, output)?, left: lower_value(language, left)?, right: lower_value(language, right)?, - element_size: arguments[0]?, + element_size: neon_comparison_element_size(language, left, arguments[0])?, }), NEON_BITWISE_INSERT_USER_OP | NEON_BITWISE_INSERT_IF_FALSE_USER_OP => { lower_neon_bitwise_insert_pcode( @@ -1267,6 +1267,20 @@ fn lower_neon_bitwise_insert_pcode( }) } +fn neon_comparison_element_size( + language: &SleighData, + left: PcodeValue, + explicit: Option, +) -> Option { + explicit.or_else(|| { + let size = lower_value(language, left)?.size; + Some(Value { + source: ValueSource::Constant(u128::from(size)), + size: 1, + }) + }) +} + fn is_extended_user_op(user_op: &str) -> bool { matches!( user_op, @@ -1328,21 +1342,21 @@ fn lower_extended_user_pcode( destination: lower_place(language, output)?, left: lower_value(language, left)?, right: lower_value(language, right)?, - element_size: arguments[0]?, + element_size: neon_comparison_element_size(language, left, arguments[0])?, }), NEON_COMPARE_GREATER_THAN_OR_EQUAL_USER_OP => { Some(Operation::NeonCompareGreaterThanOrEqual { destination: lower_place(language, output)?, left: lower_value(language, left)?, right: lower_value(language, right)?, - element_size: arguments[0]?, + element_size: neon_comparison_element_size(language, left, arguments[0])?, }) } NEON_COMPARE_GREATER_THAN_USER_OP => Some(Operation::NeonCompareGreaterThan { destination: lower_place(language, output)?, left: lower_value(language, left)?, right: lower_value(language, right)?, - element_size: arguments[0]?, + element_size: neon_comparison_element_size(language, left, arguments[0])?, }), NEON_MINIMUM_NUMBER_USER_OP if arguments[0].is_none() => { Some(Operation::FloatMinimumNumber { @@ -3271,6 +3285,11 @@ fn execute_neon_comparison( result |= lane_mask << shift; } } + let destination = if destination.size == element_size { + scalar_vector_destination(destination).ok_or_else(unsupported)? + } else { + destination + }; Ok((destination, result)) } @@ -4778,6 +4797,16 @@ mod tests { state.vector(1), Some(u128::from(u32::MAX) << 64 | u128::from(u32::MAX)) ); + + let mut memory = executable_memory(&[ + 0x23, 0x34, 0xe2, 0x7e, // cmhi d3, d1, d2 + ]); + let mut state = Aarch64State::new(CODE_ADDRESS, GuestAddress::new(0x8000)); + state.set_vector(1, 9).unwrap(); + state.set_vector(2, 8).unwrap(); + state.set_vector(3, u128::MAX).unwrap(); + interpreter.step(&mut state, &mut memory).unwrap(); + assert_eq!(state.vector(3), Some(u128::from(u64::MAX))); } #[test]