1use std::fmt::{self, Debug};
2use std::num::NonZero;
3use std::ops::RangeInclusive;
4
5use serde::Serialize;
6use stable_mir::compiler_interface::with;
7use stable_mir::mir::FieldIdx;
8use stable_mir::target::{MachineInfo, MachineSize as Size};
9use stable_mir::ty::{Align, IndexedVal, Ty, VariantIdx};
10use stable_mir::{Error, Opaque, error};
11
12use crate::stable_mir;
13
14#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
16pub struct FnAbi {
17 pub args: Vec<ArgAbi>,
19
20 pub ret: ArgAbi,
22
23 pub fixed_count: u32,
27
28 pub conv: CallConvention,
30
31 pub c_variadic: bool,
33}
34
35#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
37pub struct ArgAbi {
38 pub ty: Ty,
39 pub layout: Layout,
40 pub mode: PassMode,
41}
42
43#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
45pub enum PassMode {
46 Ignore,
50 Direct(Opaque),
54 Pair(Opaque, Opaque),
58 Cast { pad_i32: bool, cast: Opaque },
60 Indirect { attrs: Opaque, meta_attrs: Opaque, on_stack: bool },
62}
63
64#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)]
66pub struct TyAndLayout {
67 pub ty: Ty,
68 pub layout: Layout,
69}
70
71#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
73pub struct LayoutShape {
74 pub fields: FieldsShape,
76
77 pub variants: VariantsShape,
84
85 pub abi: ValueAbi,
87
88 pub abi_align: Align,
90
91 pub size: Size,
93}
94
95impl LayoutShape {
96 #[inline]
98 pub fn is_unsized(&self) -> bool {
99 self.abi.is_unsized()
100 }
101
102 #[inline]
103 pub fn is_sized(&self) -> bool {
104 !self.abi.is_unsized()
105 }
106
107 pub fn is_1zst(&self) -> bool {
109 self.is_sized() && self.size.bits() == 0 && self.abi_align == 1
110 }
111}
112
113#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)]
114pub struct Layout(usize);
115
116impl Layout {
117 pub fn shape(self) -> LayoutShape {
118 with(|cx| cx.layout_shape(self))
119 }
120}
121
122impl IndexedVal for Layout {
123 fn to_val(index: usize) -> Self {
124 Layout(index)
125 }
126 fn to_index(&self) -> usize {
127 self.0
128 }
129}
130
131#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
133pub enum FieldsShape {
134 Primitive,
136
137 Union(NonZero<usize>),
139
140 Array { stride: Size, count: u64 },
142
143 Arbitrary {
151 offsets: Vec<Size>,
156 },
157}
158
159impl FieldsShape {
160 pub fn fields_by_offset_order(&self) -> Vec<FieldIdx> {
161 match self {
162 FieldsShape::Primitive => vec![],
163 FieldsShape::Union(_) | FieldsShape::Array { .. } => (0..self.count()).collect(),
164 FieldsShape::Arbitrary { offsets, .. } => {
165 let mut indices = (0..offsets.len()).collect::<Vec<_>>();
166 indices.sort_by_key(|idx| offsets[*idx]);
167 indices
168 }
169 }
170 }
171
172 pub fn count(&self) -> usize {
173 match self {
174 FieldsShape::Primitive => 0,
175 FieldsShape::Union(count) => count.get(),
176 FieldsShape::Array { count, .. } => *count as usize,
177 FieldsShape::Arbitrary { offsets, .. } => offsets.len(),
178 }
179 }
180}
181
182#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
183pub enum VariantsShape {
184 Empty,
186
187 Single { index: VariantIdx },
189
190 Multiple {
197 tag: Scalar,
198 tag_encoding: TagEncoding,
199 tag_field: usize,
200 variants: Vec<LayoutShape>,
201 },
202}
203
204#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
205pub enum TagEncoding {
206 Direct,
209
210 Niche {
221 untagged_variant: VariantIdx,
222 niche_variants: RangeInclusive<VariantIdx>,
223 niche_start: u128,
224 },
225}
226
227#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
230pub enum ValueAbi {
231 Scalar(Scalar),
232 ScalarPair(Scalar, Scalar),
233 Vector {
234 element: Scalar,
235 count: u64,
236 },
237 Aggregate {
238 sized: bool,
240 },
241}
242
243impl ValueAbi {
244 pub fn is_unsized(&self) -> bool {
246 match *self {
247 ValueAbi::Scalar(_) | ValueAbi::ScalarPair(..) | ValueAbi::Vector { .. } => false,
248 ValueAbi::Aggregate { sized } => !sized,
249 }
250 }
251}
252
253#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Serialize)]
255pub enum Scalar {
256 Initialized {
257 value: Primitive,
259 valid_range: WrappingRange,
262 },
263 Union {
264 value: Primitive,
269 },
270}
271
272impl Scalar {
273 pub fn has_niche(&self, target: &MachineInfo) -> bool {
274 match self {
275 Scalar::Initialized { value, valid_range } => {
276 !valid_range.is_full(value.size(target)).unwrap()
277 }
278 Scalar::Union { .. } => false,
279 }
280 }
281}
282
283#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Serialize)]
285pub enum Primitive {
286 Int {
294 length: IntegerLength,
295 signed: bool,
296 },
297 Float {
298 length: FloatLength,
299 },
300 Pointer(AddressSpace),
301}
302
303impl Primitive {
304 pub fn size(self, target: &MachineInfo) -> Size {
305 match self {
306 Primitive::Int { length, .. } => Size::from_bits(length.bits()),
307 Primitive::Float { length } => Size::from_bits(length.bits()),
308 Primitive::Pointer(_) => target.pointer_width,
309 }
310 }
311}
312
313#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)]
315pub enum IntegerLength {
316 I8,
317 I16,
318 I32,
319 I64,
320 I128,
321}
322
323#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)]
325pub enum FloatLength {
326 F16,
327 F32,
328 F64,
329 F128,
330}
331
332impl IntegerLength {
333 pub fn bits(self) -> usize {
334 match self {
335 IntegerLength::I8 => 8,
336 IntegerLength::I16 => 16,
337 IntegerLength::I32 => 32,
338 IntegerLength::I64 => 64,
339 IntegerLength::I128 => 128,
340 }
341 }
342}
343
344impl FloatLength {
345 pub fn bits(self) -> usize {
346 match self {
347 FloatLength::F16 => 16,
348 FloatLength::F32 => 32,
349 FloatLength::F64 => 64,
350 FloatLength::F128 => 128,
351 }
352 }
353}
354
355#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
359pub struct AddressSpace(pub u32);
360
361impl AddressSpace {
362 pub const DATA: Self = AddressSpace(0);
364}
365
366#[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize)]
374pub struct WrappingRange {
375 pub start: u128,
376 pub end: u128,
377}
378
379impl WrappingRange {
380 #[inline]
382 pub fn is_full(&self, size: Size) -> Result<bool, Error> {
383 let Some(max_value) = size.unsigned_int_max() else {
384 return Err(error!("Expected size <= 128 bits, but found {} instead", size.bits()));
385 };
386 if self.start <= max_value && self.end <= max_value {
387 Ok(self.start == (self.end.wrapping_add(1) & max_value))
388 } else {
389 Err(error!("Range `{self:?}` out of bounds for size `{}` bits.", size.bits()))
390 }
391 }
392
393 #[inline(always)]
395 pub fn contains(&self, v: u128) -> bool {
396 if self.wraps_around() {
397 self.start <= v || v <= self.end
398 } else {
399 self.start <= v && v <= self.end
400 }
401 }
402
403 #[inline]
407 pub fn wraps_around(&self) -> bool {
408 self.start > self.end
409 }
410}
411
412impl Debug for WrappingRange {
413 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
414 if self.start > self.end {
415 write!(fmt, "(..={}) | ({}..)", self.end, self.start)?;
416 } else {
417 write!(fmt, "{}..={}", self.start, self.end)?;
418 }
419 Ok(())
420 }
421}
422
423#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)]
425pub enum CallConvention {
426 C,
427 Rust,
428
429 Cold,
430 PreserveMost,
431 PreserveAll,
432
433 Custom,
434
435 ArmAapcs,
437 CCmseNonSecureCall,
438 CCmseNonSecureEntry,
439
440 Msp430Intr,
441
442 PtxKernel,
443
444 GpuKernel,
445
446 X86Fastcall,
447 X86Intr,
448 X86Stdcall,
449 X86ThisCall,
450 X86VectorCall,
451
452 X86_64SysV,
453 X86_64Win64,
454
455 AvrInterrupt,
456 AvrNonBlockingInterrupt,
457
458 RiscvInterrupt,
459}
460
461#[non_exhaustive]
462#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)]
463pub struct ReprFlags {
464 pub is_simd: bool,
465 pub is_c: bool,
466 pub is_transparent: bool,
467 pub is_linear: bool,
468}
469
470#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)]
471pub enum IntegerType {
472 Pointer {
474 is_signed: bool,
476 },
477 Fixed {
479 length: IntegerLength,
481 is_signed: bool,
483 },
484}
485
486#[non_exhaustive]
488#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)]
489pub struct ReprOptions {
490 pub int: Option<IntegerType>,
491 pub align: Option<Align>,
492 pub pack: Option<Align>,
493 pub flags: ReprFlags,
494}