1
+ use std:: collections:: HashMap ;
2
+ use std:: str:: FromStr ;
3
+
4
+ use itertools:: Itertools ;
5
+ use regex:: Regex ;
6
+
1
7
use super :: intrinsic:: X86IntrinsicType ;
2
8
use crate :: common:: cli:: Language ;
3
- use crate :: common:: intrinsic_helpers:: IntrinsicTypeDefinition ;
9
+ use crate :: common:: intrinsic_helpers:: { IntrinsicType , IntrinsicTypeDefinition , Sign , TypeKind } ;
4
10
use crate :: x86:: xml_parser:: Parameter ;
5
11
6
12
impl IntrinsicTypeDefinition for X86IntrinsicType {
7
13
/// Gets a string containing the type in C format.
8
14
/// This function assumes that this value is present in the metadata hashmap.
9
15
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 ( )
11
20
}
12
21
13
22
fn c_single_vector_type ( & self ) -> String {
14
23
// 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
+ }
16
29
}
17
30
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
+
18
95
/// Determines the load function for this type.
19
96
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
+ }
21
123
}
22
124
23
125
/// Determines the get lane function for this type.
24
126
fn get_lane_function ( & self ) -> String {
25
127
todo ! ( "get_lane_function for X86IntrinsicType needs to be implemented!" ) ;
26
128
}
27
129
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
+ } ) )
30
175
}
31
176
}
32
177
33
178
impl X86IntrinsicType {
34
179
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`.
36
250
}
37
- }
251
+ }
0 commit comments