]> git.lizzy.rs Git - rust.git/blob - src/common.rs
Implement 128bit shl and shr binops
[rust.git] / src / common.rs
1 use rustc_target::spec::{HasTargetSpec, Target};
2
3 use cranelift::codegen::ir::{Opcode, InstructionData, ValueDef};
4 use cranelift_module::Module;
5
6 use crate::prelude::*;
7
8 pub fn mir_var(loc: Local) -> Variable {
9     Variable::with_u32(loc.index() as u32)
10 }
11
12 pub fn pointer_ty(tcx: TyCtxt) -> types::Type {
13     match tcx.data_layout.pointer_size.bits() {
14         16 => types::I16,
15         32 => types::I32,
16         64 => types::I64,
17         bits => bug!("ptr_sized_integer: unknown pointer bit size {}", bits),
18     }
19 }
20
21 pub fn clif_type_from_ty<'tcx>(
22     tcx: TyCtxt<'tcx>,
23     ty: Ty<'tcx>,
24 ) -> Option<types::Type> {
25     Some(match ty.sty {
26         ty::Bool => types::I8,
27         ty::Uint(size) => match size {
28             UintTy::U8 => types::I8,
29             UintTy::U16 => types::I16,
30             UintTy::U32 => types::I32,
31             UintTy::U64 => types::I64,
32             UintTy::U128 => types::I128,
33             UintTy::Usize => pointer_ty(tcx),
34         },
35         ty::Int(size) => match size {
36             IntTy::I8 => types::I8,
37             IntTy::I16 => types::I16,
38             IntTy::I32 => types::I32,
39             IntTy::I64 => types::I64,
40             IntTy::I128 => types::I128,
41             IntTy::Isize => pointer_ty(tcx),
42         },
43         ty::Char => types::I32,
44         ty::Float(size) => match size {
45             FloatTy::F32 => types::F32,
46             FloatTy::F64 => types::F64,
47         },
48         ty::FnPtr(_) => pointer_ty(tcx),
49         ty::RawPtr(TypeAndMut { ty, mutbl: _ }) | ty::Ref(_, ty, _) => {
50             if ty.is_sized(tcx.at(DUMMY_SP), ParamEnv::reveal_all()) {
51                 pointer_ty(tcx)
52             } else {
53                 return None;
54             }
55         }
56         ty::Param(_) => bug!("ty param {:?}", ty),
57         _ => return None,
58     })
59 }
60
61 pub fn codegen_select(bcx: &mut FunctionBuilder, cond: Value, lhs: Value, rhs: Value) -> Value {
62     let lhs_ty = bcx.func.dfg.value_type(lhs);
63     let rhs_ty = bcx.func.dfg.value_type(rhs);
64     assert_eq!(lhs_ty, rhs_ty);
65     if lhs_ty == types::I8 || lhs_ty == types::I16 {
66         // FIXME workaround for missing encoding for select.i8
67         let lhs = bcx.ins().uextend(types::I32, lhs);
68         let rhs = bcx.ins().uextend(types::I32, rhs);
69         let res = bcx.ins().select(cond, lhs, rhs);
70         bcx.ins().ireduce(lhs_ty, res)
71     } else {
72         bcx.ins().select(cond, lhs, rhs)
73     }
74 }
75
76 pub fn clif_intcast<'a, 'tcx: 'a>(
77     fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
78     val: Value,
79     to: Type,
80     signed: bool,
81 ) -> Value {
82     let from = fx.bcx.func.dfg.value_type(val);
83     match (from, to) {
84         // equal
85         (_, _) if from == to => val,
86
87         // extend
88         (_, types::I128) => {
89             let wider = if from == types::I64 {
90                 val
91             } else if signed {
92                 fx.bcx.ins().sextend(types::I64, val)
93             } else {
94                 fx.bcx.ins().uextend(types::I64, val)
95             };
96             let zero = fx.bcx.ins().iconst(types::I64, 0);
97             fx.bcx.ins().iconcat(wider, zero)
98         }
99         (_, _) if to.wider_or_equal(from) => {
100             if signed {
101                 fx.bcx.ins().sextend(to, val)
102             } else {
103                 fx.bcx.ins().uextend(to, val)
104             }
105         }
106
107         // reduce
108         (types::I128, _) => {
109             let (lsb, _msb) = fx.bcx.ins().isplit(val);
110             if to == types::I64 {
111                 lsb
112             } else {
113                 fx.bcx.ins().ireduce(to, lsb)
114             }
115         }
116         (_, _) => {
117             fx.bcx.ins().ireduce(to, val)
118         }
119     }
120 }
121
122 fn resolve_normal_value_imm(func: &Function, val: Value) -> Option<i64> {
123     if let ValueDef::Result(inst, 0 /*param*/) = func.dfg.value_def(val) {
124         if let InstructionData::UnaryImm {
125             opcode: Opcode::Iconst,
126             imm,
127         } = func.dfg[inst] {
128             Some(imm.into())
129         } else {
130             None
131         }
132     } else {
133         None
134     }
135 }
136
137 fn resolve_128bit_value_imm(func: &Function, val: Value) -> Option<u128> {
138     let (lsb, msb) = if let ValueDef::Result(inst, 0 /*param*/) = func.dfg.value_def(val) {
139         if let InstructionData::Binary {
140             opcode: Opcode::Iconcat,
141             args: [lsb, msb],
142         } = func.dfg[inst] {
143             (lsb, msb)
144         } else {
145             return None;
146         }
147     } else {
148         return None;
149     };
150
151     let lsb = resolve_normal_value_imm(func, lsb)? as u64 as u128;
152     let msb = resolve_normal_value_imm(func, msb)? as u64 as u128;
153
154     Some(msb << 64 | lsb)
155 }
156
157 pub fn resolve_value_imm(func: &Function, val: Value) -> Option<u128> {
158     if func.dfg.value_type(val) == types::I128 {
159         resolve_128bit_value_imm(func, val)
160     } else {
161         resolve_normal_value_imm(func, val).map(|imm| imm as u64 as u128)
162     }
163 }
164
165 pub struct FunctionCx<'a, 'tcx: 'a, B: Backend> {
166     // FIXME use a reference to `CodegenCx` instead of `tcx`, `module` and `constants` and `caches`
167     pub tcx: TyCtxt<'tcx>,
168     pub module: &'a mut Module<B>,
169     pub pointer_type: Type, // Cached from module
170
171     pub instance: Instance<'tcx>,
172     pub mir: &'tcx Body<'tcx>,
173
174     pub bcx: FunctionBuilder<'a>,
175     pub ebb_map: HashMap<BasicBlock, Ebb>,
176     pub local_map: HashMap<Local, CPlace<'tcx>>,
177
178     pub clif_comments: crate::pretty_clif::CommentWriter,
179     pub constants: &'a mut crate::constant::ConstantCx,
180     pub caches: &'a mut Caches<'tcx>,
181     pub source_info_set: indexmap::IndexSet<SourceInfo>,
182 }
183
184 impl<'a, 'tcx: 'a, B: Backend> LayoutOf for FunctionCx<'a, 'tcx, B> {
185     type Ty = Ty<'tcx>;
186     type TyLayout = TyLayout<'tcx>;
187
188     fn layout_of(&self, ty: Ty<'tcx>) -> TyLayout<'tcx> {
189         let ty = self.monomorphize(&ty);
190         self.tcx.layout_of(ParamEnv::reveal_all().and(&ty)).unwrap()
191     }
192 }
193
194 impl<'a, 'tcx, B: Backend + 'a> layout::HasTyCtxt<'tcx> for FunctionCx<'a, 'tcx, B> {
195     fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
196         self.tcx
197     }
198 }
199
200 impl<'a, 'tcx, B: Backend + 'a> layout::HasDataLayout for FunctionCx<'a, 'tcx, B> {
201     fn data_layout(&self) -> &layout::TargetDataLayout {
202         &self.tcx.data_layout
203     }
204 }
205
206 impl<'a, 'tcx, B: Backend + 'a> layout::HasParamEnv<'tcx> for FunctionCx<'a, 'tcx, B> {
207     fn param_env(&self) -> ParamEnv<'tcx> {
208         ParamEnv::reveal_all()
209     }
210 }
211
212 impl<'a, 'tcx, B: Backend + 'a> HasTargetSpec for FunctionCx<'a, 'tcx, B> {
213     fn target_spec(&self) -> &Target {
214         &self.tcx.sess.target.target
215     }
216 }
217
218 impl<'a, 'tcx, B: Backend> BackendTypes for FunctionCx<'a, 'tcx, B> {
219     type Value = Value;
220     type BasicBlock = Ebb;
221     type Type = Type;
222     type Funclet = !;
223     type DIScope = !;
224 }
225
226 impl<'a, 'tcx: 'a, B: Backend + 'a> FunctionCx<'a, 'tcx, B> {
227     pub fn monomorphize<T>(&self, value: &T) -> T
228     where
229         T: TypeFoldable<'tcx>,
230     {
231         self.tcx.subst_and_normalize_erasing_regions(
232             self.instance.substs,
233             ty::ParamEnv::reveal_all(),
234             value,
235         )
236     }
237
238     pub fn clif_type(&self, ty: Ty<'tcx>) -> Option<Type> {
239         clif_type_from_ty(self.tcx, self.monomorphize(&ty))
240     }
241
242     pub fn get_ebb(&self, bb: BasicBlock) -> Ebb {
243         *self.ebb_map.get(&bb).unwrap()
244     }
245
246     pub fn get_local_place(&mut self, local: Local) -> CPlace<'tcx> {
247         *self.local_map.get(&local).unwrap()
248     }
249
250     pub fn set_debug_loc(&mut self, source_info: mir::SourceInfo) {
251         let (index, _) = self.source_info_set.insert_full(source_info);
252         self.bcx.set_srcloc(SourceLoc::new(index as u32));
253     }
254 }