Skip to content

Commit 287b83c

Browse files
Sharpening the parsing logic:
1. filtered any intrinsic arguments where the only parameter is of type "void" 2. Better parsing for intrinsic return type 3. Filtering intrinsics that are difficult to test (void returns) 4. Reduced the variants in TypeKind (which differed only in bit_len)
1 parent c77800a commit 287b83c

File tree

5 files changed

+217
-99
lines changed

5 files changed

+217
-99
lines changed

crates/intrinsic-test/src/common/intrinsic_helpers.rs

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,10 @@ use super::values::value_for_array;
1212
pub enum TypeKind {
1313
BFloat,
1414
Float,
15-
Double,
1615

1716
// if signed, then the inner value is true
1817
Int(bool),
1918
Char(bool),
20-
Short(bool),
2119
Poly,
2220
Void,
2321
}
@@ -29,9 +27,8 @@ impl FromStr for TypeKind {
2927
match s {
3028
"bfloat" => Ok(Self::BFloat),
3129
"float" => Ok(Self::Float),
32-
"double" => Ok(Self::Double),
33-
"int" | "long" => Ok(Self::Int(true)),
34-
"short" => Ok(Self::Short(true)),
30+
"double" => Ok(Self::Float),
31+
"int" | "long" | "short" => Ok(Self::Int(true)),
3532
"poly" => Ok(Self::Poly),
3633
"char" => Ok(Self::Char(true)),
3734
"uint" | "unsigned" => Ok(Self::Int(false)),
@@ -49,15 +46,12 @@ impl fmt::Display for TypeKind {
4946
match self {
5047
Self::BFloat => "bfloat",
5148
Self::Float => "float",
52-
Self::Double => "double",
5349
Self::Int(true) => "int",
5450
Self::Int(false) => "uint",
5551
Self::Poly => "poly",
5652
Self::Void => "void",
5753
Self::Char(true) => "char",
5854
Self::Char(false) => "unsigned char",
59-
Self::Short(true) => "short",
60-
Self::Short(false) => "unsigned short",
6155
}
6256
)
6357
}
@@ -72,7 +66,6 @@ impl TypeKind {
7266
Self::Int(false) => "uint",
7367
Self::Poly => "poly",
7468
Self::Char(true) => "char",
75-
Self::Double => "double",
7669
_ => unreachable!("Not used: {:#?}", self),
7770
}
7871
}
@@ -126,7 +119,7 @@ impl IntrinsicType {
126119
if let Some(bl) = self.bit_len {
127120
bl
128121
} else {
129-
unreachable!("")
122+
unreachable!("{}", self.kind)
130123
}
131124
}
132125

@@ -159,11 +152,17 @@ impl IntrinsicType {
159152
}
160153

161154
pub fn c_scalar_type(&self) -> String {
162-
format!(
163-
"{prefix}{bits}_t",
164-
prefix = self.kind().c_prefix(),
165-
bits = self.inner_size()
166-
)
155+
match self {
156+
IntrinsicType {
157+
kind: TypeKind::Char(_),
158+
..
159+
} => String::from("char"),
160+
_ => format!(
161+
"{prefix}{bits}_t",
162+
prefix = self.kind().c_prefix(),
163+
bits = self.inner_size()
164+
),
165+
}
167166
}
168167

169168
pub fn rust_scalar_type(&self) -> String {
@@ -198,6 +197,21 @@ impl IntrinsicType {
198197
128 => "",
199198
_ => panic!("invalid bit_len"),
200199
},
200+
IntrinsicType {
201+
kind: TypeKind::Float,
202+
bit_len: Some(bit_len),
203+
..
204+
} => match bit_len {
205+
16 => "(float16_t)",
206+
32 => "(float)",
207+
64 => "(double)",
208+
128 => "",
209+
_ => panic!("invalid bit_len"),
210+
},
211+
IntrinsicType {
212+
kind: TypeKind::Char(_),
213+
..
214+
} => "(char)",
201215
_ => "",
202216
}
203217
}

crates/intrinsic-test/src/x86/intrinsic.rs

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::common::argument::ArgumentList;
22
use crate::common::indentation::Indentation;
33
use crate::common::intrinsic::{Intrinsic, IntrinsicDefinition};
4-
use crate::common::intrinsic_helpers::IntrinsicType;
4+
use crate::common::intrinsic_helpers::{IntrinsicType, IntrinsicTypeDefinition, TypeKind};
55
use std::ops::{Deref, DerefMut};
66

77
#[derive(Debug, Clone, PartialEq)]
@@ -38,7 +38,69 @@ impl IntrinsicDefinition<X86IntrinsicType> for Intrinsic<X86IntrinsicType> {
3838
/// Generates a std::cout for the intrinsics results that will match the
3939
/// rust debug output format for the return type. The generated line assumes
4040
/// there is an int i in scope which is the current pass number.
41-
fn print_result_c(&self, _indentation: Indentation, _additional: &str) -> String {
42-
todo!("print_result_c in Intrinsic<X86IntrinsicType> needs to be implemented!");
41+
fn print_result_c(&self, indentation: Indentation, additional: &str) -> String {
42+
let lanes = if self.results().num_vectors() > 1 {
43+
(0..self.results().num_vectors())
44+
.map(|vector| {
45+
format!(
46+
r#""{ty}(" << {lanes} << ")""#,
47+
ty = self.results().c_single_vector_type(),
48+
lanes = (0..self.results().num_lanes())
49+
.map(move |idx| -> std::string::String {
50+
format!(
51+
"{cast}{lane_fn}(__return_value.val[{vector}], {lane})",
52+
cast = self.results().c_promotion(),
53+
lane_fn = self.results().get_lane_function(),
54+
lane = idx,
55+
vector = vector,
56+
)
57+
})
58+
.collect::<Vec<_>>()
59+
.join(r#" << ", " << "#)
60+
)
61+
})
62+
.collect::<Vec<_>>()
63+
.join(r#" << ", " << "#)
64+
} else if self.results().num_lanes() > 1 {
65+
(0..self.results().num_lanes())
66+
.map(|idx| -> std::string::String {
67+
format!(
68+
"{cast}{lane_fn}(__return_value, {lane})",
69+
cast = self.results().c_promotion(),
70+
lane_fn = self.results().get_lane_function(),
71+
lane = idx
72+
)
73+
})
74+
.collect::<Vec<_>>()
75+
.join(r#" << ", " << "#)
76+
} else {
77+
format!(
78+
"{promote}cast<{cast}>(__return_value)",
79+
cast = match self.results.kind() {
80+
TypeKind::Void => "void".to_string(),
81+
TypeKind::Float if self.results().inner_size() == 64 => "double".to_string(),
82+
TypeKind::Float if self.results().inner_size() == 32 => "float".to_string(),
83+
// TypeKind::Float if self.results().inner_size() == 16 => "float16_t".to_string(),
84+
// TypeKind::Int(true) if self.results().inner_size() == 64 => "long".to_string(),
85+
// TypeKind::Int(false) if self.results().inner_size() == 64 => "unsigned long".to_string(),
86+
// TypeKind::Int(true) if self.results().inner_size() == 32 => "int".to_string(),
87+
// TypeKind::Int(false) if self.results().inner_size() == 32 => "unsigned int".to_string(),
88+
// TypeKind::Int(true) if self.results().inner_size() == 16 => "short".to_string(),
89+
// TypeKind::Int(false) if self.results().inner_size() == 16 => "unsigned short".to_string(),
90+
_ => self.results.c_scalar_type(),
91+
},
92+
promote = self.results().c_promotion(),
93+
)
94+
};
95+
96+
format!(
97+
r#"{indentation}std::cout << "Result {additional}-" << i+1 << ": {ty}" << std::fixed << std::setprecision(150) << {lanes} << "{close}" << std::endl;"#,
98+
ty = if self.results().is_simd() {
99+
format!("{}(", self.results().c_type())
100+
} else {
101+
String::from("")
102+
},
103+
close = if self.results.is_simd() { ")" } else { "" },
104+
)
43105
}
44106
}

crates/intrinsic-test/src/x86/mod.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ mod xml_parser;
66
use crate::common::SupportedArchitectureTest;
77
use crate::common::cli::ProcessedCli;
88
use crate::common::intrinsic::{Intrinsic, IntrinsicDefinition};
9+
use crate::common::intrinsic_helpers::TypeKind;
910
use crate::common::write_file::{write_c_testfiles, write_rust_testfiles};
1011
use config::build_notices;
1112
use intrinsic::X86IntrinsicType;
@@ -18,9 +19,24 @@ pub struct X86ArchitectureTest {
1819

1920
impl SupportedArchitectureTest for X86ArchitectureTest {
2021
fn create(cli_options: ProcessedCli) -> Box<Self> {
21-
let intrinsics = get_xml_intrinsics(&cli_options.filename, &cli_options.target)
22+
let mut intrinsics = get_xml_intrinsics(&cli_options.filename, &cli_options.target)
2223
.expect("Error parsing input file");
2324

25+
intrinsics.sort_by(|a, b| a.name.cmp(&b.name));
26+
let intrinsics = intrinsics
27+
.into_iter()
28+
// Not sure how we would compare intrinsic that returns void.
29+
.filter(|i| i.results.kind() != TypeKind::Void)
30+
.filter(|i| i.results.kind() != TypeKind::BFloat)
31+
.filter(|i| i.arguments().args.len() > 0)
32+
.filter(|i| !i.arguments.iter().any(|a| a.ty.kind() == TypeKind::BFloat))
33+
// Skip pointers for now, we would probably need to look at the return
34+
// type to work out how many elements we need to point to.
35+
.filter(|i| !i.arguments.iter().any(|a| a.is_ptr()))
36+
.filter(|i| !i.arguments.iter().any(|a| a.ty.inner_size() == 128))
37+
.filter(|i| !cli_options.skip.contains(&i.name))
38+
.collect::<Vec<_>>();
39+
2440
Box::new(Self {
2541
intrinsics: intrinsics,
2642
cli_options: cli_options,

crates/intrinsic-test/src/x86/types.rs

Lines changed: 82 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use std::str::FromStr;
22

3+
use itertools::Itertools;
4+
35
use super::intrinsic::X86IntrinsicType;
46
use crate::common::cli::Language;
57
use crate::common::intrinsic_helpers::{IntrinsicType, IntrinsicTypeDefinition, TypeKind};
@@ -11,15 +13,9 @@ impl IntrinsicTypeDefinition for X86IntrinsicType {
1113
let part_1 = match self.kind {
1214
TypeKind::Int(false) => "unsigned int",
1315
TypeKind::Char(false) => "unsigned char",
14-
TypeKind::Short(false) => "unsigned short",
15-
TypeKind::Short(true) => "short",
1616
_ => self.kind.c_prefix(),
1717
};
18-
let part_2 = if self.ptr {
19-
if self.ptr_constant { "* const" } else { "*" }
20-
} else {
21-
""
22-
};
18+
let part_2 = if self.ptr { "*" } else { "" };
2319

2420
String::from(vec![part_0, part_1, part_2].join(" ").trim())
2521
}
@@ -46,6 +42,7 @@ impl IntrinsicTypeDefinition for X86IntrinsicType {
4642
let mut s_copy = s.to_string();
4743
s_copy = s_copy
4844
.replace("*", "")
45+
.replace("_", "")
4946
.replace("constexpr", "")
5047
.replace("const", "")
5148
.replace("literal", "");
@@ -55,30 +52,25 @@ impl IntrinsicTypeDefinition for X86IntrinsicType {
5552
.filter_map(|s| if s.len() == 0 { None } else { Some(s) })
5653
.last();
5754

58-
// TODO: add more intrinsics by modifying
59-
// functionality below this line.
60-
// Currently all the intrinsics that have an "_"
61-
// is ignored.
62-
if let Some(_) = s.matches("_").next() {
63-
return Err(String::from("This functionality needs to be implemented"));
64-
};
55+
let s_split = s_split.map(|s| s.chars().filter(|c| !c.is_numeric()).join(""));
6556

6657
// TODO: make the unwrapping safe
67-
let kind = TypeKind::from_str(s_split.unwrap()).expect("Unable to parse type!");
68-
let mut ptr_constant = false;
69-
let mut constant = false;
70-
let mut ptr = false;
58+
let kind = TypeKind::from_str(s_split.unwrap().trim()).unwrap_or(TypeKind::Void);
7159

72-
if let Some(_) = s.matches("const*").next() {
73-
ptr_constant = true;
74-
};
75-
if let Some(_) = s.matches("const").next() {
76-
constant = true;
77-
};
78-
if let Some(_) = s.matches("*").next() {
79-
ptr = true;
60+
let kind = if s.find("unsigned").is_some() {
61+
match kind {
62+
TypeKind::Int(_) => TypeKind::Int(false),
63+
TypeKind::Char(_) => TypeKind::Char(false),
64+
a => a,
65+
}
66+
} else {
67+
kind
8068
};
8169

70+
let ptr_constant = false;
71+
let constant = s.matches("const").next().is_some();
72+
let ptr = s.matches("*").next().is_some();
73+
8274
Ok(X86IntrinsicType(IntrinsicType {
8375
ptr,
8476
ptr_constant,
@@ -91,3 +83,67 @@ impl IntrinsicTypeDefinition for X86IntrinsicType {
9183
}))
9284
}
9385
}
86+
87+
impl X86IntrinsicType {
88+
pub fn from_param(param: &Parameter) -> Result<Self, String> {
89+
match Self::from_c(param.type_data.as_str()) {
90+
Err(message) => Err(message),
91+
Ok(mut ret) => {
92+
// First correct the type of the parameter using param.etype.
93+
// The assumption is that the parameter of type void may have param.type
94+
// as "__m128i", "__mmask8" and the like.
95+
ret.set_metadata("etype".to_string(), param.etype.clone());
96+
if !param.etype.is_empty() {
97+
match TypeKind::from_str(param.etype.as_str()) {
98+
Ok(value) => {
99+
ret.kind = value;
100+
}
101+
Err(_) => {}
102+
};
103+
}
104+
105+
// check for param.etype.
106+
// extract the numeric part and set as bit-len
107+
// If param.etype is not present, guess the default bit-len
108+
109+
let mut etype_processed = param.etype.clone();
110+
etype_processed.retain(|c| c.is_numeric());
111+
112+
match str::parse::<u32>(etype_processed.as_str()) {
113+
Ok(value) => ret.bit_len = Some(value),
114+
Err(_) => {
115+
ret.bit_len = match ret.kind() {
116+
TypeKind::Char(_) => Some(8),
117+
TypeKind::BFloat => Some(16),
118+
TypeKind::Int(_) => Some(32),
119+
TypeKind::Float => Some(32),
120+
_ => None,
121+
};
122+
}
123+
}
124+
125+
// then check the param.type and extract numeric part if there are double
126+
// underscores. divide this number with bit-len and set this as simd-len.
127+
128+
let mut type_processed = param.etype.clone();
129+
type_processed.retain(|c| c.is_numeric());
130+
131+
ret.vec_len = match str::parse::<u32>(etype_processed.as_str()) {
132+
// If bit_len is None, vec_len will be None.
133+
// Else vec_len will be (num_bits / bit_len).
134+
Ok(num_bits) => ret.bit_len.and(Some(num_bits / ret.bit_len.unwrap())),
135+
Err(_) => None,
136+
};
137+
138+
// if param.etype == IMM, then it is a constant.
139+
// else it stays unchanged.
140+
ret.constant |= param.etype == "IMM";
141+
142+
Ok(ret)
143+
}
144+
}
145+
// Tile types won't currently reach here, since the intrinsic that involve them
146+
// often return "null" type. Such intrinsics are not tested in `intrinsic-test`
147+
// currently and are filtered out at `mod.rs`.
148+
}
149+
}

0 commit comments

Comments
 (0)