1+ use std:: collections:: HashMap ;
2+ use std:: str:: FromStr ;
3+
4+ use itertools:: Itertools ;
5+ use regex:: Regex ;
6+
17use super :: intrinsic:: X86IntrinsicType ;
28use crate :: common:: cli:: Language ;
3- use crate :: common:: intrinsic_helpers:: IntrinsicTypeDefinition ;
9+ use crate :: common:: intrinsic_helpers:: { IntrinsicType , IntrinsicTypeDefinition , Sign , TypeKind } ;
410use crate :: x86:: xml_parser:: Parameter ;
511
612impl IntrinsicTypeDefinition for X86IntrinsicType {
713 /// Gets a string containing the type in C format.
814 /// This function assumes that this value is present in the metadata hashmap.
915 fn c_type ( & self ) -> String {
10- todo ! ( "c_type from IntrinsicTypeDefinition is not defined!" )
16+ self . metadata
17+ . get ( "type" )
18+ . expect ( "Failed to extract the C typename in X86!" )
19+ . to_string ( )
1120 }
1221
1322 fn c_single_vector_type ( & self ) -> String {
1423 // matches __m128, __m256 and similar types
15- todo ! ( "c_type from IntrinsicTypeDefinition is not defined!" )
24+ let re = Regex :: new ( r"\__m\d+\" ) . unwrap ( ) ;
25+ match self . metadata . get ( "type" ) {
26+ Some ( type_data) if re. is_match ( type_data) => type_data. to_string ( ) ,
27+ _ => unreachable ! ( "Shouldn't be called on this type" ) ,
28+ }
1629 }
1730
31+ // fn rust_type(&self) -> String {
32+ // // handling edge cases first
33+ // // the general handling is implemented below
34+ // if let Some(val) = self.metadata.get("type") {
35+ // match val.as_str() {
36+ // "__m128 const *" => {
37+ // return "&__m128".to_string();
38+ // }
39+ // "__m128d const *" => {
40+ // return "&__m128d".to_string();
41+ // }
42+ // "const void*" => {
43+ // return "&__m128d".to_string();
44+ // }
45+ // _ => {}
46+ // }
47+ // }
48+
49+ // if self.kind() == TypeKind::Void && self.ptr {
50+ // // this has been handled by default settings in
51+ // // the from_param function of X86IntrinsicType
52+ // unreachable!()
53+ // }
54+
55+ // // general handling cases
56+ // let core_part = if self.kind() == TypeKind::Mask {
57+ // // all types of __mmask<int> are handled here
58+ // format!("__mask{}", self.bit_len.unwrap())
59+ // } else if self.simd_len.is_some() {
60+ // // all types of __m<int> vector types are handled here
61+ // let re = Regex::new(r"\__m\d+[a-z]*").unwrap();
62+ // let rust_type = self
63+ // .metadata
64+ // .get("type")
65+ // .map(|val| re.find(val).unwrap().as_str());
66+ // rust_type.unwrap().to_string()
67+ // } else {
68+ // format!(
69+ // "{}{}",
70+ // self.kind.rust_prefix().to_string(),
71+ // self.bit_len.unwrap()
72+ // )
73+ // };
74+
75+ // // extracting "memsize" so that even vector types can be involved
76+ // let memwidth = self
77+ // .metadata
78+ // .get("memwidth")
79+ // .map(|n| str::parse::<u32>(n).unwrap());
80+ // let prefix_part = if self.ptr && self.constant && self.bit_len.eq(&memwidth) {
81+ // "&"
82+ // } else if self.ptr && self.bit_len.eq(&memwidth) {
83+ // "&mut "
84+ // } else if self.ptr && self.constant {
85+ // "*const "
86+ // } else if self.ptr {
87+ // "*mut "
88+ // } else {
89+ // ""
90+ // };
91+
92+ // return prefix_part.to_string() + core_part.as_str();
93+ // }
94+
1895 /// Determines the load function for this type.
1996 fn get_load_function ( & self , _language : Language ) -> String {
20- todo ! ( "get_load_function from IntrinsicTypeDefinition is not defined!" )
97+ if let Some ( type_value) = self . metadata . get ( "type" ) {
98+ if type_value. starts_with ( "__mmask" ) {
99+ // no need of loads, since they work directly
100+ // with hex constants
101+ String :: from ( "*" )
102+ } else if type_value. starts_with ( "__m" ) {
103+ // the structure is like the follows:
104+ // if "type" starts with __m<num>{h/i/<null>},
105+ // then use either _mm_set1_epi64,
106+ // _mm256_set1_epi64 or _mm512_set1_epi64
107+ let type_val_filtered = type_value
108+ . chars ( )
109+ . filter ( |c| c. is_numeric ( ) )
110+ . join ( "" )
111+ . replace ( "128" , "" ) ;
112+ format ! ( "_mm{type_val_filtered}_set1_epi64" )
113+ } else {
114+ // if it is a pointer, then rely on type conversion
115+ // If it is not any of the above type (__int<num>, __bfloat16, unsigned short, etc)
116+ // then typecast it.
117+ format ! ( "({type_value})" )
118+ }
119+ // Look for edge cases (constexpr, literal, etc)
120+ } else {
121+ unimplemented ! ( "the value for key 'type' is not present!" ) ;
122+ }
21123 }
22124
23125 /// Determines the get lane function for this type.
24126 fn get_lane_function ( & self ) -> String {
25127 todo ! ( "get_lane_function for X86IntrinsicType needs to be implemented!" ) ;
26128 }
27129
28- fn from_c ( s : & str , target : & str ) -> Result < Self , String > {
29- todo ! ( "from_c from IntrinsicTypeDefinition is not defined!" )
130+ fn from_c ( s : & str ) -> Result < Self , String > {
131+ let mut s_copy = s. to_string ( ) ;
132+ let mut metadata: HashMap < String , String > = HashMap :: new ( ) ;
133+ metadata. insert ( "type" . to_string ( ) , s. to_string ( ) ) ;
134+ s_copy = s_copy
135+ . replace ( "*" , "" )
136+ . replace ( "_" , "" )
137+ . replace ( "constexpr" , "" )
138+ . replace ( "const" , "" )
139+ . replace ( "literal" , "" ) ;
140+
141+ let s_split = s_copy
142+ . split ( " " )
143+ . filter_map ( |s| if s. len ( ) == 0 { None } else { Some ( s) } )
144+ . last ( ) ;
145+
146+ let s_split = s_split. map ( |s| s. chars ( ) . filter ( |c| !c. is_numeric ( ) ) . join ( "" ) ) ;
147+
148+ // TODO: make the unwrapping safe
149+ let kind = TypeKind :: from_str ( s_split. unwrap ( ) . trim ( ) ) . unwrap_or ( TypeKind :: Void ) ;
150+
151+ let kind = if s. find ( "unsigned" ) . is_some ( ) {
152+ match kind {
153+ TypeKind :: Int ( _) => TypeKind :: Int ( Sign :: Unsigned ) ,
154+ TypeKind :: Char ( _) => TypeKind :: Char ( Sign :: Unsigned ) ,
155+ a => a,
156+ }
157+ } else {
158+ kind
159+ } ;
160+
161+ let ptr_constant = false ;
162+ let constant = s. matches ( "const" ) . next ( ) . is_some ( ) ;
163+ let ptr = s. matches ( "*" ) . next ( ) . is_some ( ) ;
164+
165+ Ok ( X86IntrinsicType ( IntrinsicType {
166+ ptr,
167+ ptr_constant,
168+ constant,
169+ kind,
170+ bit_len : None ,
171+ simd_len : None ,
172+ vec_len : None ,
173+ metadata,
174+ } ) )
30175 }
31176}
32177
33178impl X86IntrinsicType {
34179 pub fn from_param ( param : & Parameter ) -> Result < Self , String > {
35- todo ! ( "from_param from X86IntrinsicType is not defined!" )
180+ match Self :: from_c ( param. type_data . as_str ( ) ) {
181+ Err ( message) => Err ( message) ,
182+ Ok ( mut ret) => {
183+ // First correct the type of the parameter using param.etype.
184+ // The assumption is that the parameter of type void may have param.type
185+ // as "__m128i", "__mmask8" and the like.
186+ ret. set_metadata ( "etype" . to_string ( ) , param. etype . clone ( ) ) ;
187+ ret. set_metadata ( "memwidth" . to_string ( ) , param. memwidth . to_string ( ) ) ;
188+ if !param. etype . is_empty ( ) {
189+ match TypeKind :: from_str ( param. etype . as_str ( ) ) {
190+ Ok ( value) => {
191+ ret. kind = value;
192+ }
193+ Err ( _) => { }
194+ } ;
195+ }
196+
197+ // check for param.etype.
198+ // extract the numeric part and set as bit-len
199+ // If param.etype is not present, guess the default bit-len
200+
201+ let mut etype_processed = param. etype . clone ( ) ;
202+ etype_processed. retain ( |c| c. is_numeric ( ) ) ;
203+
204+ match str:: parse :: < u32 > ( etype_processed. as_str ( ) ) {
205+ Ok ( value) => ret. bit_len = Some ( value) ,
206+ Err ( _) => {
207+ ret. bit_len = match ret. kind ( ) {
208+ TypeKind :: Char ( _) => Some ( 8 ) ,
209+ TypeKind :: BFloat => Some ( 16 ) ,
210+ TypeKind :: Int ( _) => Some ( 32 ) ,
211+ TypeKind :: Float => Some ( 32 ) ,
212+ _ => None ,
213+ } ;
214+ }
215+ }
216+
217+ // then check the param.type and extract numeric part if there are double
218+ // underscores. divide this number with bit-len and set this as simd-len.
219+ // Only __m<int> types can have a simd-len.
220+ if param. type_data . matches ( "__m" ) . next ( ) . is_some ( )
221+ && param. type_data . matches ( "__mmask" ) . next ( ) . is_none ( )
222+ {
223+ let mut type_processed = param. type_data . clone ( ) ;
224+ type_processed. retain ( |c| c. is_numeric ( ) ) ;
225+ ret. vec_len = match str:: parse :: < u32 > ( type_processed. as_str ( ) ) {
226+ // If bit_len is None, vec_len will be None.
227+ // Else vec_len will be (num_bits / bit_len).
228+ Ok ( num_bits) => ret. bit_len . and ( Some ( num_bits / ret. bit_len . unwrap ( ) ) ) ,
229+ Err ( _) => None ,
230+ } ;
231+ }
232+
233+ // default settings for "void *" parameters
234+ // often used by intrinsics to denote memory address or so.
235+ if ret. kind == TypeKind :: Void && ret. ptr {
236+ ret. kind = TypeKind :: Int ( Sign :: Unsigned ) ;
237+ ret. bit_len = Some ( 8 ) ;
238+ }
239+
240+ // if param.etype == IMM, then it is a constant.
241+ // else it stays unchanged.
242+ ret. constant |= param. etype == "IMM" ;
243+
244+ Ok ( ret)
245+ }
246+ }
247+ // Tile types won't currently reach here, since the intrinsic that involve them
248+ // often return "null" type. Such intrinsics are not tested in `intrinsic-test`
249+ // currently and are filtered out at `mod.rs`.
36250 }
37- }
251+ }
0 commit comments