Skip to content

Commit dba6c35

Browse files
authored
Merge commit from fork
* cmov: add regressions tests for aarch64 Cmov/CmovEq * cmov: fix aarch64 Cmov not ignoring high bits of condition * cmov: fix aarch64 CmovEq not ignoring high bits
1 parent dad5e3b commit dba6c35

2 files changed

Lines changed: 59 additions & 7 deletions

File tree

cmov/src/backends/aarch64.rs

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ use core::arch::asm;
33

44
/// Conditional select
55
macro_rules! csel {
6-
($cmp:expr, $csel:expr, $dst:expr, $src:expr, $condition:expr) => {
6+
($tst:expr, $csel:expr, $dst:expr, $src:expr, $condition:expr) => {
77
unsafe {
88
asm! {
9-
"cmp {0:w}, 0",
9+
$tst,
1010
$csel,
1111
in(reg) $condition,
1212
inlateout(reg) *$dst,
@@ -45,14 +45,30 @@ macro_rules! cseleq {
4545
/// Conditional select using 32-bit `:w` registers
4646
macro_rules! csel32 {
4747
($csel:expr, $dst:expr, $src:expr, $condition:expr) => {
48-
csel!("cmp {0:w}, 0", $csel, $dst, $src, $condition)
48+
csel!("tst {0:w}, 0xff", $csel, $dst, $src, $condition)
4949
};
5050
}
5151

5252
/// Conditional select using 64-bit `:x` registers
5353
macro_rules! csel64 {
5454
($csel:expr, $dst:expr, $src:expr, $condition:expr) => {
55-
csel!("cmp {0:x}, 0", $csel, $dst, $src, $condition)
55+
csel!("tst {0:x}, 0xff", $csel, $dst, $src, $condition)
56+
};
57+
}
58+
59+
/// Conditional select equality test using 32-bit `:w` registers and
60+
/// correctly handling unspecified upper bits of 16 bit inputs
61+
macro_rules! cseleq16 {
62+
($instruction:expr, $lhs:expr, $rhs:expr, $condition:expr, $dst:expr) => {
63+
cseleq!(
64+
"eor {0:w}, {1:w}, {2:w}",
65+
"tst {0:w}, 0xffff",
66+
$instruction,
67+
$lhs,
68+
$rhs,
69+
$condition,
70+
$dst
71+
)
5672
};
5773
}
5874

@@ -129,12 +145,12 @@ impl Cmov for u64 {
129145
impl CmovEq for u16 {
130146
#[inline]
131147
fn cmovne(&self, rhs: &Self, input: Condition, output: &mut Condition) {
132-
cseleq32!("csel {3:w}, {4:w}, {5:w}, NE", self, rhs, input, output);
148+
cseleq16!("csel {3:w}, {4:w}, {5:w}, NE", self, rhs, input, output);
133149
}
134150

135151
#[inline]
136152
fn cmoveq(&self, rhs: &Self, input: Condition, output: &mut Condition) {
137-
cseleq32!("csel {3:w}, {4:w}, {5:w}, EQ", self, rhs, input, output);
153+
cseleq16!("csel {3:w}, {4:w}, {5:w}, EQ", self, rhs, input, output);
138154
}
139155
}
140156

cmov/tests/regression.rs

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
//! Tests for previous bugs in the implementation.
22
3-
use cmov::CmovEq;
3+
use std::hint::black_box;
4+
5+
use cmov::{Cmov, CmovEq};
46

57
#[test]
68
fn u64_cmoveq() {
@@ -11,3 +13,37 @@ fn u64_cmoveq() {
1113
// 0x8200_0000_0000_0000 is not equal to 0
1214
assert_eq!(cond, 0);
1315
}
16+
17+
#[test]
18+
fn cmovz_wrong_output() {
19+
// The black box is necessary here, as otherwise the compiler will
20+
// provide a constant 0 to the csel
21+
let condition: u32 = black_box(1 << 8);
22+
let mut left = 1;
23+
let right = 2;
24+
debug_assert_eq!(0, condition as u8);
25+
left.cmovz(&right, condition as u8);
26+
assert_eq!(left, right);
27+
}
28+
29+
#[test]
30+
fn cmoveq_wrong_output_u16() {
31+
let input = 1;
32+
let mut output = 0;
33+
let left: u32 = black_box(1 << 16);
34+
let right: u32 = black_box(1 << 17);
35+
debug_assert_eq!(left as u16, right as u16);
36+
(left as u16).cmoveq(&(right as u16), input, &mut output);
37+
assert_eq!(input, output);
38+
}
39+
40+
#[test]
41+
fn cmoveq_wrong_output_i16() {
42+
let input = 1;
43+
let mut output = 0;
44+
let left: u32 = black_box(1 << 16);
45+
let right: u32 = black_box(1 << 17);
46+
debug_assert_eq!(left as i16, right as i16);
47+
(left as i16).cmoveq(&(right as i16), input, &mut output);
48+
assert_eq!(input, output);
49+
}

0 commit comments

Comments
 (0)