1use std::convert::TryFrom;
4
5use llvm_support::bitcodes::{IrBlockId, TypeCode};
6use llvm_support::{
7 AddressSpace, ArrayTypeError, FunctionTypeError, IntegerTypeError, PointerTypeError,
8 StructTypeError, Type, VectorTypeError,
9};
10use num_enum::TryFromPrimitiveError;
11use thiserror::Error;
12
13use crate::block::IrBlock;
14use crate::map::{MapError, PartialMapCtx};
15use crate::unroll::UnrolledBlock;
16
17#[derive(Debug, Error)]
19pub enum TypeTableError {
20 #[error("invalid type table size (expected {0} elements, got {1})")]
22 BadSize(usize, usize),
23
24 #[error("invalid type table index: {0}")]
26 BadIndex(usize),
27
28 #[error("unknown type code")]
30 UnknownTypeCode(#[from] TryFromPrimitiveError<TypeCode>),
31
32 #[error("invalid type table structure (broken records)")]
34 BadTable,
35
36 #[error("invalid integer type")]
38 InvalidIntegerType(#[from] IntegerTypeError),
39
40 #[error("invalid pointer type")]
42 InvalidPointerType(#[from] PointerTypeError),
43
44 #[error("invalid array type")]
46 InvalidArrayType(#[from] ArrayTypeError),
47
48 #[error("invalid vector type")]
50 InvalidVectorType(#[from] VectorTypeError),
51
52 #[error("invalid structure type")]
54 InvalidStructType(#[from] StructTypeError),
55
56 #[error("invalid function type")]
58 InvalidFunctionType(#[from] FunctionTypeError),
59
60 #[error("mapping error in string table")]
62 Map(#[from] MapError),
63}
64
65#[derive(Debug)]
68pub(crate) struct TypeRef(pub(crate) usize);
69
70impl From<usize> for TypeRef {
71 fn from(value: usize) -> TypeRef {
72 TypeRef(value)
73 }
74}
75
76impl From<u64> for TypeRef {
77 fn from(value: u64) -> TypeRef {
78 TypeRef::from(value as usize)
79 }
80}
81
82#[derive(Debug)]
85enum PartialType {
86 Half,
87 BFloat,
88 Float,
89 Double,
90 Metadata,
91 X86Fp80,
92 Fp128,
93 PpcFp128,
94 Void,
95 Label,
96 X86Mmx,
97 X86Amx,
98 Token,
99 Integer(PartialIntegerType),
100 Function(PartialFunctionType),
101 Pointer(PartialPointerType),
102 OpaquePointer(AddressSpace),
103 Struct(PartialStructType),
104 Array(PartialArrayType),
105 FixedVector(PartialVectorType),
106 ScalableVector(PartialVectorType),
107}
108
109impl PartialType {
110 fn resolve(&self, partials: &PartialTypeTable) -> Result<Type, TypeTableError> {
113 match self {
114 PartialType::Half => Ok(Type::Half),
115 PartialType::BFloat => Ok(Type::BFloat),
116 PartialType::Float => Ok(Type::Float),
117 PartialType::Double => Ok(Type::Double),
118 PartialType::Metadata => Ok(Type::Metadata),
119 PartialType::X86Fp80 => Ok(Type::X86Fp80),
120 PartialType::Fp128 => Ok(Type::Fp128),
121 PartialType::PpcFp128 => Ok(Type::PpcFp128),
122 PartialType::Void => Ok(Type::Void),
123 PartialType::Label => Ok(Type::Label),
124 PartialType::X86Mmx => Ok(Type::X86Mmx),
125 PartialType::X86Amx => Ok(Type::X86Amx),
126 PartialType::Token => Ok(Type::Token),
127 PartialType::Integer(ity) => Ok(Type::new_integer(ity.bit_width)?),
128 PartialType::Function(fty) => {
129 let return_type = partials.resolve(&fty.return_type)?;
130 let param_types = fty
131 .param_types
132 .iter()
133 .map(|ty_ref| partials.resolve(ty_ref))
134 .collect::<Result<Vec<_>, _>>()?;
135
136 Ok(Type::new_function(return_type, param_types, fty.is_vararg)?)
137 }
138 PartialType::Pointer(pty) => {
139 let pointee = partials.resolve(&pty.pointee)?;
140
141 Ok(Type::new_pointer(pointee, pty.address_space)?)
142 }
143 PartialType::OpaquePointer(oty) => Ok(Type::OpaquePointer(*oty)),
144 PartialType::Struct(sty) => {
145 let field_types = sty
146 .field_types
147 .iter()
148 .map(|fty| partials.resolve(fty))
149 .collect::<Result<Vec<_>, _>>()?;
150
151 Ok(Type::new_struct(
152 sty.name.clone(),
153 field_types,
154 sty.is_packed,
155 )?)
156 }
157 PartialType::Array(aty) => {
158 let element_type = partials.resolve(&aty.element_type)?;
159
160 Ok(Type::new_array(aty.num_elements, element_type)?)
161 }
162 PartialType::FixedVector(vty) => {
163 log::debug!("vty: {:?}", vty);
164
165 let element_type = partials.resolve(&vty.element_type)?;
166 log::debug!("element_type: {:?}", partials.get(&vty.element_type));
167
168 Ok(Type::new_vector(vty.num_elements, element_type)?)
169 }
170 PartialType::ScalableVector(vty) => {
171 let element_type = partials.resolve(&vty.element_type)?;
172
173 Ok(Type::new_scalable_vector(vty.num_elements, element_type)?)
174 }
175 }
176 }
177}
178
179#[derive(Debug)]
180struct PartialIntegerType {
181 bit_width: u32,
182}
183
184#[derive(Debug)]
186struct PartialFunctionType {
187 return_type: TypeRef,
188 param_types: Vec<TypeRef>,
189 is_vararg: bool,
190}
191
192#[derive(Debug)]
194struct PartialPointerType {
195 pointee: TypeRef,
196 address_space: AddressSpace,
197}
198
199#[derive(Debug)]
200struct PartialStructType {
201 name: Option<String>,
202 field_types: Vec<TypeRef>,
203 is_packed: bool,
204}
205
206#[derive(Debug)]
207struct PartialArrayType {
208 num_elements: u64,
209 element_type: TypeRef,
210}
211
212#[derive(Debug)]
213struct PartialVectorType {
214 num_elements: u64,
215 element_type: TypeRef,
216}
217
218#[derive(Debug)]
223struct PartialTypeTable {
224 numentries: usize,
225 inner: Vec<PartialType>,
226}
227
228impl PartialTypeTable {
229 fn new(numentries: usize) -> Self {
230 Self {
231 numentries: numentries,
232 inner: Vec::with_capacity(numentries),
233 }
234 }
235
236 fn add(&mut self, ty: PartialType) {
237 self.inner.push(ty)
238 }
239
240 fn last_mut(&mut self) -> Option<&mut PartialType> {
241 self.inner.last_mut()
242 }
243
244 fn get(&self, ty_ref: &TypeRef) -> Result<&PartialType, TypeTableError> {
246 self.inner
247 .get(ty_ref.0)
248 .ok_or(TypeTableError::BadIndex(ty_ref.0))
249 }
250
251 fn resolve(&self, ty_ref: &TypeRef) -> Result<Type, TypeTableError> {
253 let pty = self.get(ty_ref)?;
256
257 log::debug!("type ref {} resolves to {:?}", ty_ref.0, pty);
258
259 pty.resolve(self)
260 }
261
262 fn reify(self) -> Result<TypeTable, TypeTableError> {
264 if self.inner.len() != self.numentries {
265 return Err(TypeTableError::BadSize(self.numentries, self.inner.len()));
266 }
267
268 let types = self
271 .inner
272 .iter()
273 .map(|pty| pty.resolve(&self))
274 .collect::<Result<Vec<_>, _>>()?;
275
276 Ok(TypeTable(types))
277 }
278}
279
280#[derive(Clone, Debug)]
282pub struct TypeTable(Vec<Type>);
283
284impl TypeTable {
285 pub(crate) fn get(&self, ty_ref: impl Into<TypeRef>) -> Option<&Type> {
286 let ty_ref = ty_ref.into();
287 self.0.get(ty_ref.0)
288 }
289}
290
291impl IrBlock for TypeTable {
292 type Error = TypeTableError;
293
294 const BLOCK_ID: IrBlockId = IrBlockId::Type;
295
296 fn try_map_inner(block: &UnrolledBlock, _ctx: &mut PartialMapCtx) -> Result<Self, Self::Error> {
297 let numentries = *block
299 .records()
300 .one(TypeCode::NumEntry)
301 .ok_or(TypeTableError::BadTable)
302 .and_then(|r| r.fields().get(0).ok_or(TypeTableError::BadTable))?
303 as usize;
304
305 let mut partial_types = PartialTypeTable::new(numentries);
313 let mut last_type_name = String::new();
314 for record in block.records() {
315 macro_rules! type_field {
317 ($n:literal) => {
318 record
319 .fields()
320 .get($n)
321 .copied()
322 .ok_or(TypeTableError::BadTable)?
323 };
324 }
325
326 let code = TypeCode::try_from(record.code()).map_err(TypeTableError::from)?;
327
328 match code {
329 TypeCode::NumEntry => continue,
331 TypeCode::Void => partial_types.add(PartialType::Void),
332 TypeCode::Half => partial_types.add(PartialType::Half),
333 TypeCode::BFloat => partial_types.add(PartialType::BFloat),
334 TypeCode::Float => partial_types.add(PartialType::Float),
335 TypeCode::Double => partial_types.add(PartialType::Double),
336 TypeCode::Label => partial_types.add(PartialType::Label),
337 TypeCode::Opaque => {
338 if last_type_name.is_empty() {
344 return Err(MapError::Invalid(
345 "opaque type but no preceding type name".into(),
346 )
347 .into());
348 }
349
350 if let Some(PartialType::Struct(s)) = partial_types.last_mut() {
354 if s.name.is_some() {
355 return Err(MapError::Invalid(
356 "forward-declared opaque type already has name".into(),
357 )
358 .into());
359 }
360
361 s.name = Some(last_type_name.clone());
362 } else {
363 partial_types.add(PartialType::Struct(PartialStructType {
364 name: Some(last_type_name.clone()),
365 field_types: vec![],
366 is_packed: false,
367 }));
368 }
369
370 last_type_name.clear();
371 }
372 TypeCode::Integer => {
373 let bit_width = type_field!(0) as u32;
374 partial_types.add(PartialType::Integer(PartialIntegerType { bit_width }));
375 }
376 TypeCode::Pointer => {
377 let pointee = TypeRef(type_field!(0) as usize);
378
379 let address_space = AddressSpace::try_from(type_field!(1)).map_err(|e| {
380 MapError::Invalid(format!("bad address space for pointer type: {:?}", e))
381 })?;
382
383 partial_types.add(PartialType::Pointer(PartialPointerType {
384 pointee,
385 address_space,
386 }));
387 }
388 TypeCode::FunctionOld => {
389 return Err(MapError::Unsupported(
391 "unsupported: old function type codes; please implement!".into(),
392 )
393 .into());
394 }
395 TypeCode::Array => {
396 let num_elements = type_field!(0);
397
398 let element_type = TypeRef(type_field!(1) as usize);
399
400 partial_types.add(PartialType::Array(PartialArrayType {
401 num_elements,
402 element_type,
403 }));
404 }
405 TypeCode::Vector => {
406 let num_elements = type_field!(0);
407
408 let element_type = TypeRef(type_field!(1) as usize);
409
410 let scalable = record.fields().get(2).map_or_else(|| false, |f| *f > 0);
413 let new_type = match scalable {
414 true => PartialType::ScalableVector(PartialVectorType {
415 num_elements,
416 element_type,
417 }),
418 false => PartialType::FixedVector(PartialVectorType {
419 num_elements,
420 element_type,
421 }),
422 };
423
424 partial_types.add(new_type);
425 }
426 TypeCode::X86Fp80 => partial_types.add(PartialType::X86Fp80),
427 TypeCode::Fp128 => partial_types.add(PartialType::Fp128),
428 TypeCode::PpcFp128 => partial_types.add(PartialType::PpcFp128),
429 TypeCode::Metadata => partial_types.add(PartialType::Metadata),
430 TypeCode::X86Mmx => partial_types.add(PartialType::X86Mmx),
431 TypeCode::StructAnon => {
432 let is_packed = type_field!(0) > 0;
433
434 let field_types = record.fields()[1..]
435 .iter()
436 .map(|f| TypeRef(*f as usize))
437 .collect::<Vec<_>>();
438
439 partial_types.add(PartialType::Struct(PartialStructType {
440 name: None,
441 field_types,
442 is_packed,
443 }));
444 }
445 TypeCode::StructName => {
446 last_type_name.push_str(&record.try_string(0).map_err(MapError::RecordString)?);
449 continue;
450 }
451 TypeCode::StructNamed => {
452 let is_packed = type_field!(0) > 0;
456
457 let field_types = record.fields()[1..]
458 .iter()
459 .map(|f| TypeRef(*f as usize))
460 .collect::<Vec<_>>();
461
462 if let Some(PartialType::Struct(s)) = partial_types.last_mut() {
466 if s.name.is_some() || !s.field_types.is_empty() {
467 return Err(MapError::Invalid(
468 "forward-declared struct type already has name and/or type fields"
469 .into(),
470 )
471 .into());
472 }
473
474 s.name = Some(last_type_name.clone());
475 s.field_types = field_types;
476 } else {
477 partial_types.add(PartialType::Struct(PartialStructType {
478 name: Some(last_type_name.clone()),
479 field_types,
480 is_packed,
481 }));
482 }
483
484 last_type_name.clear();
485 }
486 TypeCode::Function => {
487 let is_vararg = type_field!(0) > 0;
488 let return_type = TypeRef(type_field!(1) as usize);
489
490 let param_types = record.fields()[2..]
491 .iter()
492 .map(|f| TypeRef(*f as usize))
493 .collect::<Vec<_>>();
494
495 partial_types.add(PartialType::Function(PartialFunctionType {
496 return_type,
497 param_types,
498 is_vararg,
499 }));
500 }
501 TypeCode::Token => partial_types.add(PartialType::Token),
502 TypeCode::X86Amx => partial_types.add(PartialType::X86Amx),
503 TypeCode::OpaquePointer => {
504 let address_space = AddressSpace::try_from(type_field!(0)).map_err(|e| {
505 MapError::Invalid(format!("bad address space in type: {:?}", e))
506 })?;
507
508 partial_types.add(PartialType::OpaquePointer(address_space))
509 }
510 }
511 }
512
513 partial_types.reify()
514 }
515}