]>
Commit | Line | Data |
---|---|---|
29967ef6 | 1 | use rustc_index::vec::IndexVec; |
17df50a5 | 2 | use rustc_middle::ty::SymbolName; |
5869c6ff | 3 | use rustc_target::abi::call::FnAbi; |
29967ef6 XL |
4 | use rustc_target::abi::{Integer, Primitive}; |
5 | use rustc_target::spec::{HasTargetSpec, Target}; | |
6 | ||
17df50a5 | 7 | use crate::constant::ConstantCx; |
29967ef6 XL |
8 | use crate::prelude::*; |
9 | ||
10 | pub(crate) fn pointer_ty(tcx: TyCtxt<'_>) -> types::Type { | |
11 | match tcx.data_layout.pointer_size.bits() { | |
12 | 16 => types::I16, | |
13 | 32 => types::I32, | |
14 | 64 => types::I64, | |
15 | bits => bug!("ptr_sized_integer: unknown pointer bit size {}", bits), | |
16 | } | |
17 | } | |
18 | ||
19 | pub(crate) fn scalar_to_clif_type(tcx: TyCtxt<'_>, scalar: Scalar) -> Type { | |
20 | match scalar.value { | |
21 | Primitive::Int(int, _sign) => match int { | |
22 | Integer::I8 => types::I8, | |
23 | Integer::I16 => types::I16, | |
24 | Integer::I32 => types::I32, | |
25 | Integer::I64 => types::I64, | |
26 | Integer::I128 => types::I128, | |
27 | }, | |
28 | Primitive::F32 => types::F32, | |
29 | Primitive::F64 => types::F64, | |
30 | Primitive::Pointer => pointer_ty(tcx), | |
31 | } | |
32 | } | |
33 | ||
34 | fn clif_type_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<types::Type> { | |
35 | Some(match ty.kind() { | |
36 | ty::Bool => types::I8, | |
37 | ty::Uint(size) => match size { | |
38 | UintTy::U8 => types::I8, | |
39 | UintTy::U16 => types::I16, | |
40 | UintTy::U32 => types::I32, | |
41 | UintTy::U64 => types::I64, | |
42 | UintTy::U128 => types::I128, | |
43 | UintTy::Usize => pointer_ty(tcx), | |
44 | }, | |
45 | ty::Int(size) => match size { | |
46 | IntTy::I8 => types::I8, | |
47 | IntTy::I16 => types::I16, | |
48 | IntTy::I32 => types::I32, | |
49 | IntTy::I64 => types::I64, | |
50 | IntTy::I128 => types::I128, | |
51 | IntTy::Isize => pointer_ty(tcx), | |
52 | }, | |
53 | ty::Char => types::I32, | |
54 | ty::Float(size) => match size { | |
55 | FloatTy::F32 => types::F32, | |
56 | FloatTy::F64 => types::F64, | |
57 | }, | |
58 | ty::FnPtr(_) => pointer_ty(tcx), | |
6a06907d | 59 | ty::RawPtr(TypeAndMut { ty: pointee_ty, mutbl: _ }) | ty::Ref(_, pointee_ty, _) => { |
29967ef6 XL |
60 | if has_ptr_meta(tcx, pointee_ty) { |
61 | return None; | |
62 | } else { | |
63 | pointer_ty(tcx) | |
64 | } | |
65 | } | |
66 | ty::Adt(adt_def, _) if adt_def.repr.simd() => { | |
67 | let (element, count) = match &tcx.layout_of(ParamEnv::reveal_all().and(ty)).unwrap().abi | |
68 | { | |
69 | Abi::Vector { element, count } => (element.clone(), *count), | |
70 | _ => unreachable!(), | |
71 | }; | |
72 | ||
73 | match scalar_to_clif_type(tcx, element).by(u16::try_from(count).unwrap()) { | |
74 | // Cranelift currently only implements icmp for 128bit vectors. | |
75 | Some(vector_ty) if vector_ty.bits() == 128 => vector_ty, | |
76 | _ => return None, | |
77 | } | |
78 | } | |
79 | ty::Param(_) => bug!("ty param {:?}", ty), | |
80 | _ => return None, | |
81 | }) | |
82 | } | |
83 | ||
84 | fn clif_pair_type_from_ty<'tcx>( | |
85 | tcx: TyCtxt<'tcx>, | |
86 | ty: Ty<'tcx>, | |
87 | ) -> Option<(types::Type, types::Type)> { | |
88 | Some(match ty.kind() { | |
89 | ty::Tuple(substs) if substs.len() == 2 => { | |
90 | let mut types = substs.types(); | |
91 | let a = clif_type_from_ty(tcx, types.next().unwrap())?; | |
92 | let b = clif_type_from_ty(tcx, types.next().unwrap())?; | |
93 | if a.is_vector() || b.is_vector() { | |
94 | return None; | |
95 | } | |
96 | (a, b) | |
97 | } | |
6a06907d | 98 | ty::RawPtr(TypeAndMut { ty: pointee_ty, mutbl: _ }) | ty::Ref(_, pointee_ty, _) => { |
29967ef6 XL |
99 | if has_ptr_meta(tcx, pointee_ty) { |
100 | (pointer_ty(tcx), pointer_ty(tcx)) | |
101 | } else { | |
102 | return None; | |
103 | } | |
104 | } | |
105 | _ => return None, | |
106 | }) | |
107 | } | |
108 | ||
109 | /// Is a pointer to this type a fat ptr? | |
110 | pub(crate) fn has_ptr_meta<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { | |
6a06907d XL |
111 | let ptr_ty = tcx.mk_ptr(TypeAndMut { ty, mutbl: rustc_hir::Mutability::Not }); |
112 | match &tcx.layout_of(ParamEnv::reveal_all().and(ptr_ty)).unwrap().abi { | |
29967ef6 XL |
113 | Abi::Scalar(_) => false, |
114 | Abi::ScalarPair(_, _) => true, | |
115 | abi => unreachable!("Abi of ptr to {:?} is {:?}???", ty, abi), | |
116 | } | |
117 | } | |
118 | ||
119 | pub(crate) fn codegen_icmp_imm( | |
6a06907d | 120 | fx: &mut FunctionCx<'_, '_, '_>, |
29967ef6 XL |
121 | intcc: IntCC, |
122 | lhs: Value, | |
123 | rhs: i128, | |
124 | ) -> Value { | |
125 | let lhs_ty = fx.bcx.func.dfg.value_type(lhs); | |
126 | if lhs_ty == types::I128 { | |
127 | // FIXME legalize `icmp_imm.i128` in Cranelift | |
128 | ||
129 | let (lhs_lsb, lhs_msb) = fx.bcx.ins().isplit(lhs); | |
130 | let (rhs_lsb, rhs_msb) = (rhs as u128 as u64 as i64, (rhs as u128 >> 64) as u64 as i64); | |
131 | ||
132 | match intcc { | |
133 | IntCC::Equal => { | |
134 | let lsb_eq = fx.bcx.ins().icmp_imm(IntCC::Equal, lhs_lsb, rhs_lsb); | |
135 | let msb_eq = fx.bcx.ins().icmp_imm(IntCC::Equal, lhs_msb, rhs_msb); | |
136 | fx.bcx.ins().band(lsb_eq, msb_eq) | |
137 | } | |
138 | IntCC::NotEqual => { | |
139 | let lsb_ne = fx.bcx.ins().icmp_imm(IntCC::NotEqual, lhs_lsb, rhs_lsb); | |
140 | let msb_ne = fx.bcx.ins().icmp_imm(IntCC::NotEqual, lhs_msb, rhs_msb); | |
141 | fx.bcx.ins().bor(lsb_ne, msb_ne) | |
142 | } | |
143 | _ => { | |
144 | // if msb_eq { | |
145 | // lsb_cc | |
146 | // } else { | |
147 | // msb_cc | |
148 | // } | |
149 | ||
150 | let msb_eq = fx.bcx.ins().icmp_imm(IntCC::Equal, lhs_msb, rhs_msb); | |
151 | let lsb_cc = fx.bcx.ins().icmp_imm(intcc, lhs_lsb, rhs_lsb); | |
152 | let msb_cc = fx.bcx.ins().icmp_imm(intcc, lhs_msb, rhs_msb); | |
153 | ||
154 | fx.bcx.ins().select(msb_eq, lsb_cc, msb_cc) | |
155 | } | |
156 | } | |
157 | } else { | |
158 | let rhs = i64::try_from(rhs).expect("codegen_icmp_imm rhs out of range for <128bit int"); | |
159 | fx.bcx.ins().icmp_imm(intcc, lhs, rhs) | |
160 | } | |
161 | } | |
162 | ||
29967ef6 XL |
163 | pub(crate) fn type_min_max_value( |
164 | bcx: &mut FunctionBuilder<'_>, | |
165 | ty: Type, | |
166 | signed: bool, | |
167 | ) -> (Value, Value) { | |
168 | assert!(ty.is_int()); | |
169 | ||
170 | if ty == types::I128 { | |
171 | if signed { | |
172 | let min = i128::MIN as u128; | |
173 | let min_lsb = bcx.ins().iconst(types::I64, min as u64 as i64); | |
174 | let min_msb = bcx.ins().iconst(types::I64, (min >> 64) as u64 as i64); | |
175 | let min = bcx.ins().iconcat(min_lsb, min_msb); | |
176 | ||
fc512014 | 177 | let max = i128::MAX as u128; |
29967ef6 XL |
178 | let max_lsb = bcx.ins().iconst(types::I64, max as u64 as i64); |
179 | let max_msb = bcx.ins().iconst(types::I64, (max >> 64) as u64 as i64); | |
180 | let max = bcx.ins().iconcat(max_lsb, max_msb); | |
181 | ||
182 | return (min, max); | |
183 | } else { | |
184 | let min_half = bcx.ins().iconst(types::I64, 0); | |
185 | let min = bcx.ins().iconcat(min_half, min_half); | |
186 | ||
187 | let max_half = bcx.ins().iconst(types::I64, u64::MAX as i64); | |
188 | let max = bcx.ins().iconcat(max_half, max_half); | |
189 | ||
190 | return (min, max); | |
191 | } | |
192 | } | |
193 | ||
194 | let min = match (ty, signed) { | |
195 | (types::I8, false) | (types::I16, false) | (types::I32, false) | (types::I64, false) => { | |
196 | 0i64 | |
197 | } | |
198 | (types::I8, true) => i64::from(i8::MIN), | |
199 | (types::I16, true) => i64::from(i16::MIN), | |
200 | (types::I32, true) => i64::from(i32::MIN), | |
201 | (types::I64, true) => i64::MIN, | |
202 | _ => unreachable!(), | |
203 | }; | |
204 | ||
205 | let max = match (ty, signed) { | |
206 | (types::I8, false) => i64::from(u8::MAX), | |
207 | (types::I16, false) => i64::from(u16::MAX), | |
208 | (types::I32, false) => i64::from(u32::MAX), | |
209 | (types::I64, false) => u64::MAX as i64, | |
210 | (types::I8, true) => i64::from(i8::MAX), | |
211 | (types::I16, true) => i64::from(i16::MAX), | |
212 | (types::I32, true) => i64::from(i32::MAX), | |
213 | (types::I64, true) => i64::MAX, | |
214 | _ => unreachable!(), | |
215 | }; | |
216 | ||
217 | let (min, max) = (bcx.ins().iconst(ty, min), bcx.ins().iconst(ty, max)); | |
218 | ||
219 | (min, max) | |
220 | } | |
221 | ||
222 | pub(crate) fn type_sign(ty: Ty<'_>) -> bool { | |
223 | match ty.kind() { | |
224 | ty::Ref(..) | ty::RawPtr(..) | ty::FnPtr(..) | ty::Char | ty::Uint(..) | ty::Bool => false, | |
225 | ty::Int(..) => true, | |
226 | ty::Float(..) => false, // `signed` is unused for floats | |
227 | _ => panic!("{}", ty), | |
228 | } | |
229 | } | |
230 | ||
17df50a5 XL |
231 | pub(crate) struct FunctionCx<'m, 'clif, 'tcx: 'm> { |
232 | pub(crate) cx: &'clif mut crate::CodegenCx<'tcx>, | |
233 | pub(crate) module: &'m mut dyn Module, | |
29967ef6 XL |
234 | pub(crate) tcx: TyCtxt<'tcx>, |
235 | pub(crate) pointer_type: Type, // Cached from module | |
17df50a5 | 236 | pub(crate) constants_cx: ConstantCx, |
29967ef6 XL |
237 | |
238 | pub(crate) instance: Instance<'tcx>, | |
17df50a5 | 239 | pub(crate) symbol_name: SymbolName<'tcx>, |
29967ef6 | 240 | pub(crate) mir: &'tcx Body<'tcx>, |
5869c6ff | 241 | pub(crate) fn_abi: Option<FnAbi<'tcx, Ty<'tcx>>>, |
29967ef6 XL |
242 | |
243 | pub(crate) bcx: FunctionBuilder<'clif>, | |
244 | pub(crate) block_map: IndexVec<BasicBlock, Block>, | |
245 | pub(crate) local_map: IndexVec<Local, CPlace<'tcx>>, | |
246 | ||
247 | /// When `#[track_caller]` is used, the implicit caller location is stored in this variable. | |
248 | pub(crate) caller_location: Option<CValue<'tcx>>, | |
249 | ||
29967ef6 XL |
250 | pub(crate) clif_comments: crate::pretty_clif::CommentWriter, |
251 | pub(crate) source_info_set: indexmap::IndexSet<SourceInfo>, | |
252 | ||
253 | /// This should only be accessed by `CPlace::new_var`. | |
254 | pub(crate) next_ssa_var: u32, | |
255 | ||
256 | pub(crate) inline_asm_index: u32, | |
257 | } | |
258 | ||
6a06907d | 259 | impl<'tcx> LayoutOf for FunctionCx<'_, '_, 'tcx> { |
29967ef6 XL |
260 | type Ty = Ty<'tcx>; |
261 | type TyAndLayout = TyAndLayout<'tcx>; | |
262 | ||
263 | fn layout_of(&self, ty: Ty<'tcx>) -> TyAndLayout<'tcx> { | |
5869c6ff | 264 | RevealAllLayoutCx(self.tcx).layout_of(ty) |
29967ef6 XL |
265 | } |
266 | } | |
267 | ||
6a06907d | 268 | impl<'tcx> layout::HasTyCtxt<'tcx> for FunctionCx<'_, '_, 'tcx> { |
29967ef6 XL |
269 | fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { |
270 | self.tcx | |
271 | } | |
272 | } | |
273 | ||
6a06907d | 274 | impl<'tcx> rustc_target::abi::HasDataLayout for FunctionCx<'_, '_, 'tcx> { |
29967ef6 XL |
275 | fn data_layout(&self) -> &rustc_target::abi::TargetDataLayout { |
276 | &self.tcx.data_layout | |
277 | } | |
278 | } | |
279 | ||
6a06907d | 280 | impl<'tcx> layout::HasParamEnv<'tcx> for FunctionCx<'_, '_, 'tcx> { |
29967ef6 XL |
281 | fn param_env(&self) -> ParamEnv<'tcx> { |
282 | ParamEnv::reveal_all() | |
283 | } | |
284 | } | |
285 | ||
6a06907d | 286 | impl<'tcx> HasTargetSpec for FunctionCx<'_, '_, 'tcx> { |
29967ef6 XL |
287 | fn target_spec(&self) -> &Target { |
288 | &self.tcx.sess.target | |
289 | } | |
290 | } | |
291 | ||
6a06907d | 292 | impl<'tcx> FunctionCx<'_, '_, 'tcx> { |
fc512014 | 293 | pub(crate) fn monomorphize<T>(&self, value: T) -> T |
29967ef6 XL |
294 | where |
295 | T: TypeFoldable<'tcx> + Copy, | |
296 | { | |
297 | self.instance.subst_mir_and_normalize_erasing_regions( | |
298 | self.tcx, | |
299 | ty::ParamEnv::reveal_all(), | |
fc512014 | 300 | value, |
29967ef6 XL |
301 | ) |
302 | } | |
303 | ||
304 | pub(crate) fn clif_type(&self, ty: Ty<'tcx>) -> Option<Type> { | |
305 | clif_type_from_ty(self.tcx, ty) | |
306 | } | |
307 | ||
308 | pub(crate) fn clif_pair_type(&self, ty: Ty<'tcx>) -> Option<(Type, Type)> { | |
309 | clif_pair_type_from_ty(self.tcx, ty) | |
310 | } | |
311 | ||
312 | pub(crate) fn get_block(&self, bb: BasicBlock) -> Block { | |
313 | *self.block_map.get(bb).unwrap() | |
314 | } | |
315 | ||
316 | pub(crate) fn get_local_place(&mut self, local: Local) -> CPlace<'tcx> { | |
317 | *self.local_map.get(local).unwrap_or_else(|| { | |
318 | panic!("Local {:?} doesn't exist", local); | |
319 | }) | |
320 | } | |
321 | ||
322 | pub(crate) fn set_debug_loc(&mut self, source_info: mir::SourceInfo) { | |
323 | let (index, _) = self.source_info_set.insert_full(source_info); | |
324 | self.bcx.set_srcloc(SourceLoc::new(index as u32)); | |
325 | } | |
326 | ||
327 | pub(crate) fn get_caller_location(&mut self, span: Span) -> CValue<'tcx> { | |
328 | if let Some(loc) = self.caller_location { | |
329 | // `#[track_caller]` is used; return caller location instead of current location. | |
330 | return loc; | |
331 | } | |
332 | ||
333 | let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span); | |
334 | let caller = self.tcx.sess.source_map().lookup_char_pos(topmost.lo()); | |
335 | let const_loc = self.tcx.const_caller_location(( | |
17df50a5 XL |
336 | rustc_span::symbol::Symbol::intern( |
337 | &caller.file.name.prefer_remapped().to_string_lossy(), | |
338 | ), | |
29967ef6 XL |
339 | caller.line as u32, |
340 | caller.col_display as u32 + 1, | |
341 | )); | |
342 | crate::constant::codegen_const_value(self, const_loc, self.tcx.caller_location_ty()) | |
343 | } | |
344 | ||
345 | pub(crate) fn triple(&self) -> &target_lexicon::Triple { | |
17df50a5 | 346 | self.module.isa().triple() |
29967ef6 XL |
347 | } |
348 | ||
17df50a5 | 349 | pub(crate) fn anonymous_str(&mut self, msg: &str) -> Value { |
29967ef6 XL |
350 | let mut data_ctx = DataContext::new(); |
351 | data_ctx.define(msg.as_bytes().to_vec().into_boxed_slice()); | |
17df50a5 | 352 | let msg_id = self.module.declare_anonymous_data(false, false).unwrap(); |
29967ef6 XL |
353 | |
354 | // Ignore DuplicateDefinition error, as the data will be the same | |
17df50a5 | 355 | let _ = self.module.define_data(msg_id, &data_ctx); |
29967ef6 | 356 | |
17df50a5 | 357 | let local_msg_id = self.module.declare_data_in_func(msg_id, self.bcx.func); |
cdc7bbd5 | 358 | if self.clif_comments.enabled() { |
29967ef6 XL |
359 | self.add_comment(local_msg_id, msg); |
360 | } | |
361 | self.bcx.ins().global_value(self.pointer_type, local_msg_id) | |
362 | } | |
363 | } | |
5869c6ff XL |
364 | |
365 | pub(crate) struct RevealAllLayoutCx<'tcx>(pub(crate) TyCtxt<'tcx>); | |
366 | ||
367 | impl<'tcx> LayoutOf for RevealAllLayoutCx<'tcx> { | |
368 | type Ty = Ty<'tcx>; | |
369 | type TyAndLayout = TyAndLayout<'tcx>; | |
370 | ||
371 | fn layout_of(&self, ty: Ty<'tcx>) -> TyAndLayout<'tcx> { | |
372 | assert!(!ty.still_further_specializable()); | |
6a06907d XL |
373 | self.0.layout_of(ParamEnv::reveal_all().and(&ty)).unwrap_or_else(|e| { |
374 | if let layout::LayoutError::SizeOverflow(_) = e { | |
375 | self.0.sess.fatal(&e.to_string()) | |
376 | } else { | |
377 | bug!("failed to get layout for `{}`: {}", ty, e) | |
378 | } | |
379 | }) | |
5869c6ff XL |
380 | } |
381 | } | |
382 | ||
383 | impl<'tcx> layout::HasTyCtxt<'tcx> for RevealAllLayoutCx<'tcx> { | |
384 | fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { | |
385 | self.0 | |
386 | } | |
387 | } | |
388 | ||
389 | impl<'tcx> rustc_target::abi::HasDataLayout for RevealAllLayoutCx<'tcx> { | |
390 | fn data_layout(&self) -> &rustc_target::abi::TargetDataLayout { | |
391 | &self.0.data_layout | |
392 | } | |
393 | } | |
394 | ||
395 | impl<'tcx> layout::HasParamEnv<'tcx> for RevealAllLayoutCx<'tcx> { | |
396 | fn param_env(&self) -> ParamEnv<'tcx> { | |
397 | ParamEnv::reveal_all() | |
398 | } | |
399 | } | |
400 | ||
401 | impl<'tcx> HasTargetSpec for RevealAllLayoutCx<'tcx> { | |
402 | fn target_spec(&self) -> &Target { | |
403 | &self.0.sess.target | |
404 | } | |
405 | } |