use stdarch-gen to generate instructions

This commit is contained in:
surechen 2021-03-05 22:35:42 +08:00 committed by Amanieu d'Antras
parent 400651adfa
commit 10d6ae269f
6 changed files with 182 additions and 142 deletions

View file

@ -271,6 +271,22 @@ pub unsafe fn vceqzq_f64(a: float64x2_t) -> uint64x2_t {
simd_eq(a, transmute(b))
}
/// Floating-point absolute value
#[inline]
#[target_feature(enable = "neon")]
#[cfg_attr(test, assert_instr(fabs))]
pub unsafe fn vabs_f64(a: float64x1_t) -> float64x1_t {
simd_fabs(a)
}
/// Floating-point absolute value
#[inline]
#[target_feature(enable = "neon")]
#[cfg_attr(test, assert_instr(fabs))]
pub unsafe fn vabsq_f64(a: float64x2_t) -> float64x2_t {
simd_fabs(a)
}
/// Compare signed greater than
#[inline]
#[target_feature(enable = "neon")]
@ -838,6 +854,22 @@ mod test {
assert_eq!(r, e);
}
#[simd_test(enable = "neon")]
unsafe fn test_vabs_f64() {
let a: f64 = -0.1;
let e: f64 = 0.1;
let r: f64 = transmute(vabs_f64(transmute(a)));
assert_eq!(r, e);
}
#[simd_test(enable = "neon")]
unsafe fn test_vabsq_f64() {
let a: f64x2 = f64x2::new(-0.1, -2.2);
let e: f64x2 = f64x2::new(0.1, 2.2);
let r: f64x2 = transmute(vabsq_f64(transmute(a)));
assert_eq!(r, e);
}
#[simd_test(enable = "neon")]
unsafe fn test_vcgt_s64() {
let a: i64x1 = i64x1::new(1);

View file

@ -72,10 +72,6 @@ extern "C" {
fn vabs_s64_(a: int64x1_t) -> int64x1_t;
#[link_name = "llvm.aarch64.neon.abs.v2i64"]
fn vabsq_s64_(a: int64x2_t) -> int64x2_t;
#[link_name = "llvm.fabs.v1f64"]
fn vabs_f64_(a: float64x1_t) -> float64x1_t;
#[link_name = "llvm.fabs.v2f64"]
fn vabsq_f64_(a: float64x2_t) -> float64x2_t;
#[link_name = "llvm.aarch64.neon.suqadd.v8i8"]
fn vuqadd_s8_(a: int8x8_t, b: uint8x8_t) -> int8x8_t;
@ -708,21 +704,6 @@ pub unsafe fn vabsq_s64(a: int64x2_t) -> int64x2_t {
vabsq_s64_(a)
}
/// Floating-point absolute value.
#[inline]
#[target_feature(enable = "neon")]
#[cfg_attr(test, assert_instr(fabs))]
pub unsafe fn vabs_f64(a: float64x1_t) -> float64x1_t {
vabs_f64_(a)
}
/// Floating-point absolute value.
#[inline]
#[target_feature(enable = "neon")]
#[cfg_attr(test, assert_instr(fabs))]
pub unsafe fn vabsq_f64(a: float64x2_t) -> float64x2_t {
vabsq_f64_(a)
}
/// Signed saturating Accumulate of Unsigned value.
#[inline]
#[target_feature(enable = "neon")]
@ -3932,20 +3913,6 @@ mod tests {
let e = i64x2::new(i64::MIN, i64::MAX);
assert_eq!(r, e);
}
#[simd_test(enable = "neon")]
unsafe fn test_vabs_f64() {
let a = f64x1::new(f64::MIN);
let r: f64x1 = transmute(vabs_f64(transmute(a)));
let e = f64x1::new(f64::MAX);
assert_eq!(r, e);
}
#[simd_test(enable = "neon")]
unsafe fn test_vabsq_f64() {
let a = f64x2::new(f64::MIN, -4.2);
let r: f64x2 = transmute(vabsq_f64(transmute(a)));
let e = f64x2::new(f64::MAX, 4.2);
assert_eq!(r, e);
}
#[simd_test(enable = "neon")]
unsafe fn test_vaddv_s16() {

View file

@ -629,6 +629,26 @@ pub unsafe fn vceqq_f32(a: float32x4_t, b: float32x4_t) -> uint32x4_t {
simd_eq(a, b)
}
/// Floating-point absolute value
#[inline]
#[target_feature(enable = "neon")]
#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))]
#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vabs))]
#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fabs))]
pub unsafe fn vabs_f32(a: float32x2_t) -> float32x2_t {
simd_fabs(a)
}
/// Floating-point absolute value
#[inline]
#[target_feature(enable = "neon")]
#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))]
#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vabs))]
#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fabs))]
pub unsafe fn vabsq_f32(a: float32x4_t) -> float32x4_t {
simd_fabs(a)
}
/// Compare signed greater than
#[inline]
#[target_feature(enable = "neon")]
@ -3651,6 +3671,22 @@ mod test {
assert_eq!(r, e);
}
#[simd_test(enable = "neon")]
unsafe fn test_vabs_f32() {
let a: f32x2 = f32x2::new(-0.1, -2.2);
let e: f32x2 = f32x2::new(0.1, 2.2);
let r: f32x2 = transmute(vabs_f32(transmute(a)));
assert_eq!(r, e);
}
#[simd_test(enable = "neon")]
unsafe fn test_vabsq_f32() {
let a: f32x4 = f32x4::new(-0.1, -2.2, -3.3, -6.6);
let e: f32x4 = f32x4::new(0.1, 2.2, 3.3, 6.6);
let r: f32x4 = transmute(vabsq_f32(transmute(a)));
assert_eq!(r, e);
}
#[simd_test(enable = "neon")]
unsafe fn test_vcgt_s8() {
let a: i8x8 = i8x8::new(1, 2, 3, 4, 5, 6, 7, 8);

View file

@ -125,9 +125,6 @@ extern "C" {
#[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vabs.v2i32")]
#[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.abs.v2i32")]
fn vabs_s32_(a: int32x2_t) -> int32x2_t;
#[cfg_attr(target_arch = "arm", link_name = "llvm.fabs.v2f32")]
#[cfg_attr(target_arch = "aarch64", link_name = "llvm.fabs.v2f32")]
fn vabs_f32_(a: float32x2_t) -> float32x2_t;
// absolute value (128-bit)
#[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vabs.v16i8")]
#[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.abs.v16i8")]
@ -1153,24 +1150,6 @@ pub unsafe fn vabsq_s16(a: int16x8_t) -> int16x8_t {
pub unsafe fn vabsq_s32(a: int32x4_t) -> int32x4_t {
vabsq_s32_(a)
}
/// Floating-point absolute value.
#[inline]
#[target_feature(enable = "neon")]
#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))]
#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vabs))]
#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fabs))]
pub unsafe fn vabs_f32(a: float32x2_t) -> float32x2_t {
vabs_f32_(a)
}
/// Floating-point absolute value.
#[inline]
#[target_feature(enable = "neon")]
#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))]
#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vabs))]
#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fabs))]
pub unsafe fn vabsq_f32(a: float32x4_t) -> float32x4_t {
vabsq_f32_(a)
}
/// Add pairwise.
#[inline]
@ -8588,20 +8567,7 @@ mod tests {
let e = i32x4::new(i32::MIN, i32::MAX, 0, 1);
assert_eq!(r, e);
}
#[simd_test(enable = "neon")]
unsafe fn test_vabs_f32() {
let a = f32x2::new(f32::MIN, -1.0);
let r: f32x2 = transmute(vabs_f32(transmute(a)));
let e = f32x2::new(f32::MAX, 1.0);
assert_eq!(r, e);
}
#[simd_test(enable = "neon")]
unsafe fn test_vabsq_f32() {
let a = f32x4::new(f32::MIN, -1.32, -4.3, -6.8);
let r: f32x4 = transmute(vabsq_f32(transmute(a)));
let e = f32x4::new(f32::MAX, 1.32, 4.3, 6.8);
assert_eq!(r, e);
}
#[simd_test(enable = "neon")]
unsafe fn test_vpadd_s16() {
let a = i16x4::new(1, 2, 3, 4);

View file

@ -53,12 +53,12 @@
// FALSE - 'false' all bits are set to 0
// FF - same as 'true'
// MIN - minimal value (either 0 or the lowest negative number)
// MAX - maximal value propr to overflow
// MAX - maximal value proper to overflow
//
// # validate <values>
// Validates a and b aginst the expected result of the test.
// The special values 'TRUE' and 'FALSE' can be used to
// represent the corect NEON representation of true or
// represent the correct NEON representation of true or
// false values. It too gets scaled to the type.
//
// Validate needs to be called before generate as it sets
@ -166,6 +166,29 @@ validate TRUE, FALSE, FALSE, FALSE
aarch64 = fcmeq
generate float32x2_t:uint32x2_t, float32x4_t:uint32x4_t, float64x1_t:uint64x1_t, float64x2_t:uint64x2_t
////////////////////
// Floating-point absolute value
////////////////////
/// Floating-point absolute value
name = vabs
fn = simd_fabs
a = -0.1, -2.2, -3.3, -6.6
validate 0.1, 2.2, 3.3, 6.6
arm = vabs
aarch64 = fabs
generate float32x2_t:float32x2_t, float32x4_t:float32x4_t
/// Floating-point absolute value
name = vabs
fn = simd_fabs
a = -0.1, -2.2, -3.3, -6.6
validate 0.1, 2.2, 3.3, 6.6
aarch64 = fabs
generate float64x1_t:float64x1_t, float64x2_t:float64x2_t
////////////////////
// greater then
////////////////////

View file

@ -299,7 +299,7 @@ fn gen_aarch64(
in_t: &str,
out_t: &str,
current_tests: &[(Vec<String>, Vec<String>, Vec<String>)],
single_para: bool,
para_num: i32,
fixed: &Vec<String>,
) -> (String, String) {
let _global_t = type_to_global_type(in_t);
@ -335,27 +335,36 @@ fn gen_aarch64(
} else {
String::new()
};
let call = if !single_para {
let call = if para_num == 2 {
format!(
r#"pub unsafe fn {}(a: {}, b: {}) -> {} {{
{}{}(a, b)
}}"#,
name, in_t, in_t, out_t, ext_c, current_fn,
)
} else if fixed.len() != 0 {
let fixed: Vec<String> = fixed.iter().take(type_len(in_t)).cloned().collect();
format!(
r#"pub unsafe fn {}(a: {}) -> {} {{
} else if para_num == 1 {
if fixed.len() != 0 {
let fixed: Vec<String> = fixed.iter().take(type_len(in_t)).cloned().collect();
format!(
r#"pub unsafe fn {}(a: {}) -> {} {{
let b{};
{}{}(a, transmute(b))
}}"#,
name,
in_t,
out_t,
values(in_t, &fixed),
ext_c,
current_fn,
)
name,
in_t,
out_t,
values(in_t, &fixed),
ext_c,
current_fn,
)
} else {
format!(
r#"pub unsafe fn {}(a: {}) -> {} {{
{}{}(a)
}}"#,
name, in_t, out_t, ext_c, current_fn,
)
}
} else {
String::new()
};
@ -370,14 +379,7 @@ fn gen_aarch64(
current_comment, current_aarch64, call
);
let test = gen_test(
name,
&in_t,
&out_t,
current_tests,
type_len(in_t),
single_para,
);
let test = gen_test(name, &in_t, &out_t, current_tests, type_len(in_t), para_num);
(function, test)
}
@ -387,7 +389,7 @@ fn gen_test(
out_t: &str,
current_tests: &[(Vec<String>, Vec<String>, Vec<String>)],
len: usize,
single_para: bool,
para_num: i32,
) -> String {
let mut test = format!(
r#"
@ -399,35 +401,44 @@ fn gen_test(
let a: Vec<String> = a.iter().take(len).cloned().collect();
let b: Vec<String> = b.iter().take(len).cloned().collect();
let e: Vec<String> = e.iter().take(len).cloned().collect();
let t = if !single_para {
format!(
r#"
let t = {
match para_num {
1 => {
format!(
r#"
let a{};
let e{};
let r: {} = transmute({}(transmute(a)));
assert_eq!(r, e);
"#,
values(in_t, &a),
values(out_t, &e),
type_to_global_type(out_t),
name
)
}
2 => {
format!(
r#"
let a{};
let b{};
let e{};
let r: {} = transmute({}(transmute(a), transmute(b)));
assert_eq!(r, e);
"#,
values(in_t, &a),
values(in_t, &b),
values(out_t, &e),
type_to_global_type(out_t),
name
)
} else {
format!(
r#"
let a{};
let e{};
let r: {} = transmute({}(transmute(a)));
assert_eq!(r, e);
"#,
values(in_t, &a),
values(out_t, &e),
type_to_global_type(out_t),
name
)
values(in_t, &a),
values(in_t, &b),
values(out_t, &e),
type_to_global_type(out_t),
name
)
}
_ => {
panic!("no support para_num:{}", para_num.to_string())
}
}
};
test.push_str(&t);
}
test.push_str(" }\n");
@ -446,7 +457,7 @@ fn gen_arm(
in_t: &str,
out_t: &str,
current_tests: &[(Vec<String>, Vec<String>, Vec<String>)],
single_para: bool,
para_num: i32,
fixed: &Vec<String>,
) -> (String, String) {
let _global_t = type_to_global_type(in_t);
@ -472,7 +483,6 @@ fn gen_arm(
}
format!("{}_", name)
};
let ext_c =
if let (Some(link_arm), Some(link_aarch64)) = (link_arm.clone(), link_aarch64.clone()) {
let ext = type_to_ext(in_t);
@ -495,27 +505,36 @@ fn gen_arm(
} else {
String::new()
};
let call = if !single_para {
let call = if para_num == 2 {
format!(
r#"pub unsafe fn {}(a: {}, b: {}) -> {} {{
{}{}(a, b)
}}"#,
name, in_t, in_t, out_t, ext_c, current_fn,
)
} else if fixed.len() != 0 {
let fixed: Vec<String> = fixed.iter().take(type_len(in_t)).cloned().collect();
format!(
r#"pub unsafe fn {}(a: {}) -> {} {{
} else if para_num == 1 {
if fixed.len() != 0 {
let fixed: Vec<String> = fixed.iter().take(type_len(in_t)).cloned().collect();
format!(
r#"pub unsafe fn {}(a: {}) -> {} {{
let b{};
{}{}(a, transmute(b))
}}"#,
name,
in_t,
out_t,
values(in_t, &fixed),
ext_c,
current_fn,
)
name,
in_t,
out_t,
values(in_t, &fixed),
ext_c,
current_fn,
)
} else {
format!(
r#"pub unsafe fn {}(a: {}) -> {} {{
{}{}(a)
}}"#,
name, in_t, out_t, ext_c, current_fn,
)
}
} else {
String::new()
};
@ -534,14 +553,7 @@ fn gen_arm(
expand_intrinsic(&current_aarch64, in_t),
call,
);
let test = gen_test(
name,
&in_t,
&out_t,
current_tests,
type_len(in_t),
single_para,
);
let test = gen_test(name, &in_t, &out_t, current_tests, type_len(in_t), para_num);
(function, test)
}
@ -628,10 +640,10 @@ fn main() -> io::Result<()> {
let mut current_aarch64: Option<String> = None;
let mut link_arm: Option<String> = None;
let mut link_aarch64: Option<String> = None;
let mut para_num = 2;
let mut a: Vec<String> = Vec::new();
let mut b: Vec<String> = Vec::new();
let mut fixed: Vec<String> = Vec::new();
let mut single_para: bool = true;
let mut current_tests: Vec<(Vec<String>, Vec<String>, Vec<String>)> = Vec::new();
//
@ -702,7 +714,10 @@ mod test {
link_aarch64 = None;
link_arm = None;
current_tests = Vec::new();
single_para = true;
para_num = 2;
a = vec![];
b = vec![];
fixed = vec![];
} else if line.starts_with("//") {
} else if line.starts_with("name = ") {
current_name = Some(String::from(&line[7..]));
@ -716,7 +731,6 @@ mod test {
a = line[4..].split(',').map(|v| v.trim().to_string()).collect();
} else if line.starts_with("b = ") {
b = line[4..].split(',').map(|v| v.trim().to_string()).collect();
single_para = false;
} else if line.starts_with("fixed = ") {
fixed = line[8..].split(',').map(|v| v.trim().to_string()).collect();
} else if line.starts_with("validate ") {
@ -755,9 +769,11 @@ mod test {
} else {
panic!("Bad spec: {}", line)
}
if b.len() == 0 {
para_num = 1;
}
let current_name = current_name.clone().unwrap();
let name = format!("{}{}", current_name, type_to_suffix(in_t),);
if let Some(current_arm) = current_arm.clone() {
let (function, test) = gen_arm(
&current_comment,
@ -770,7 +786,7 @@ mod test {
&in_t,
&out_t,
&current_tests,
single_para,
para_num,
&fixed,
);
out_arm.push_str(&function);
@ -785,7 +801,7 @@ mod test {
&in_t,
&out_t,
&current_tests,
single_para,
para_num,
&fixed,
);
out_aarch64.push_str(&function);