]> git.lizzy.rs Git - rust.git/blob - src/discriminant.rs
Move discriminant get and set to discriminant.rs
[rust.git] / src / discriminant.rs
1 use crate::prelude::*;
2
3 pub fn codegen_set_discriminant<'tcx>(
4     fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
5     place: CPlace<'tcx>,
6     variant_index: VariantIdx,
7 ) {
8     let layout = place.layout();
9     if layout.for_variant(&*fx, variant_index).abi == layout::Abi::Uninhabited {
10         return;
11     }
12     match layout.variants {
13         layout::Variants::Single { index } => {
14             assert_eq!(index, variant_index);
15         }
16         layout::Variants::Multiple {
17             discr: _,
18             discr_index,
19             discr_kind: layout::DiscriminantKind::Tag,
20             variants: _,
21         } => {
22             let ptr = place.place_field(fx, mir::Field::new(discr_index));
23             let to = layout
24                 .ty
25                 .discriminant_for_variant(fx.tcx, variant_index)
26                 .unwrap()
27                 .val;
28             let discr = CValue::const_val(fx, ptr.layout().ty, to);
29             ptr.write_cvalue(fx, discr);
30         }
31         layout::Variants::Multiple {
32             discr: _,
33             discr_index,
34             discr_kind: layout::DiscriminantKind::Niche {
35                 dataful_variant,
36                 ref niche_variants,
37                 niche_start,
38             },
39             variants: _,
40         } => {
41             if variant_index != dataful_variant {
42                 let niche = place.place_field(fx, mir::Field::new(discr_index));
43                 //let niche_llty = niche.layout.immediate_llvm_type(bx.cx);
44                 let niche_value =
45                     ((variant_index.as_u32() - niche_variants.start().as_u32()) as u128)
46                         .wrapping_add(niche_start);
47                 // FIXME(eddyb) Check the actual primitive type here.
48                 let niche_llval = if niche_value == 0 {
49                     CValue::const_val(fx, niche.layout().ty, 0)
50                 } else {
51                     CValue::const_val(fx, niche.layout().ty, niche_value)
52                 };
53                 niche.write_cvalue(fx, niche_llval);
54             }
55         }
56     }
57 }
58
59 pub fn codegen_get_discriminant<'tcx>(
60     fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
61     place: CPlace<'tcx>,
62     dest_layout: TyLayout<'tcx>,
63 ) -> CValue<'tcx> {
64     let layout = place.layout();
65
66     if layout.abi == layout::Abi::Uninhabited {
67         return trap_unreachable_ret_value(fx, dest_layout, "[panic] Tried to get discriminant for uninhabited type.");
68     }
69
70     let (discr_scalar, discr_index, discr_kind) = match &layout.variants {
71         layout::Variants::Single { index } => {
72             let discr_val = layout
73                 .ty
74                 .ty_adt_def()
75                 .map_or(u128::from(index.as_u32()), |def| {
76                     def.discriminant_for_variant(fx.tcx, *index).val
77                 });
78             return CValue::const_val(fx, dest_layout.ty, discr_val);
79         }
80         layout::Variants::Multiple { discr, discr_index, discr_kind, variants: _ } => {
81             (discr, *discr_index, discr_kind)
82         }
83     };
84
85     let discr = place.place_field(fx, mir::Field::new(discr_index)).to_cvalue(fx);
86     let discr_ty = discr.layout().ty;
87     let lldiscr = discr.load_scalar(fx);
88     match discr_kind {
89         layout::DiscriminantKind::Tag => {
90             let signed = match discr_scalar.value {
91                 layout::Int(_, signed) => signed,
92                 _ => false,
93             };
94             let val = clif_intcast(fx, lldiscr, fx.clif_type(dest_layout.ty).unwrap(), signed);
95             return CValue::by_val(val, dest_layout);
96         }
97         layout::DiscriminantKind::Niche {
98             dataful_variant,
99             ref niche_variants,
100             niche_start,
101         } => {
102             let niche_llty = fx.clif_type(discr_ty).unwrap();
103             let dest_clif_ty = fx.clif_type(dest_layout.ty).unwrap();
104             if niche_variants.start() == niche_variants.end() {
105                 let b = fx
106                     .bcx
107                     .ins()
108                     .icmp_imm(IntCC::Equal, lldiscr, *niche_start as u64 as i64);
109                 let if_true = fx
110                     .bcx
111                     .ins()
112                     .iconst(dest_clif_ty, niche_variants.start().as_u32() as i64);
113                 let if_false = fx
114                     .bcx
115                     .ins()
116                     .iconst(dest_clif_ty, dataful_variant.as_u32() as i64);
117                 let val = fx.bcx.ins().select(b, if_true, if_false);
118                 return CValue::by_val(val, dest_layout);
119             } else {
120                 // Rebase from niche values to discriminant values.
121                 let delta = niche_start.wrapping_sub(niche_variants.start().as_u32() as u128);
122                 let delta = fx.bcx.ins().iconst(niche_llty, delta as u64 as i64);
123                 let lldiscr = fx.bcx.ins().isub(lldiscr, delta);
124                 let b = fx.bcx.ins().icmp_imm(
125                     IntCC::UnsignedLessThanOrEqual,
126                     lldiscr,
127                     niche_variants.end().as_u32() as i64,
128                 );
129                 let if_true =
130                     clif_intcast(fx, lldiscr, fx.clif_type(dest_layout.ty).unwrap(), false);
131                 let if_false = fx
132                     .bcx
133                     .ins()
134                     .iconst(dest_clif_ty, dataful_variant.as_u32() as i64);
135                 let val = fx.bcx.ins().select(b, if_true, if_false);
136                 return CValue::by_val(val, dest_layout);
137             }
138         }
139     }
140 }