|
4 | 4 | //! of an assignment. The first step to retagging is to generate a [`RetagPlan`], which |
5 | 5 | //! describes which pointers within the place or operand can be retagged. |
6 | 6 |
|
7 | | -#![allow(unused)] |
8 | | -use rustc_abi::{BackendRepr, FieldIdx, FieldsShape, VariantIdx, Variants}; |
| 7 | +use rustc_abi::{FieldIdx, FieldsShape, Size, VariantIdx, Variants}; |
9 | 8 | use rustc_ast::Mutability; |
10 | 9 | use rustc_data_structures::fx::FxIndexMap; |
11 | 10 | use rustc_middle::mir::{Rvalue, WithRetag}; |
12 | 11 | use rustc_middle::ty; |
13 | 12 | use rustc_middle::ty::layout::TyAndLayout; |
14 | 13 |
|
15 | | -use crate::RetagInfo; |
16 | 14 | use crate::mir::FunctionCx; |
17 | | -use crate::mir::operand::OperandRef; |
| 15 | +use crate::mir::operand::{OperandRef, OperandRefBuilder, OperandValue}; |
18 | 16 | use crate::mir::place::PlaceRef; |
19 | | -use crate::traits::BuilderMethods; |
| 17 | +use crate::traits::{ |
| 18 | + BaseTypeCodegenMethods, BuilderMethods, ConstCodegenMethods, LayoutTypeCodegenMethods, |
| 19 | +}; |
| 20 | +use crate::{RetagFlags, RetagInfo}; |
20 | 21 |
|
21 | 22 | pub(crate) fn rvalue_needs_retag(rvalue: &Rvalue<'_>) -> bool { |
22 | 23 | // `Ref` has its own internal retagging |
@@ -58,12 +59,6 @@ impl<'a, 'tcx, V> RetagPlan<V> { |
58 | 59 | if layout.is_sized() && layout.size < bx.tcx().data_layout.pointer_size() { |
59 | 60 | return None; |
60 | 61 | } |
61 | | - // SIMD vectors may only contain raw pointers, integers, and floating point values, |
62 | | - // which do not need to be retagged. |
63 | | - if matches!(layout.backend_repr, BackendRepr::SimdVector { .. }) { |
64 | | - return None; |
65 | | - } |
66 | | - |
67 | 62 | // Check the type of this value to see what to do with it (retag, or recurse). |
68 | 63 | match layout.ty.kind() { |
69 | 64 | &ty::Ref(_, pointee, mt) => { |
@@ -168,32 +163,201 @@ impl<'a, 'tcx, V> RetagPlan<V> { |
168 | 163 | /// to types that are entirely covered by `UnsafePinned`, for which retags |
169 | 164 | /// are a no-op. |
170 | 165 | fn emit_retag<Bx: BuilderMethods<'a, 'tcx>>( |
171 | | - _bx: &mut Bx, |
172 | | - _pointee_layout: TyAndLayout<'tcx>, |
173 | | - _ptr_kind: Option<Mutability>, |
174 | | - _is_fn_entry: bool, |
| 166 | + bx: &mut Bx, |
| 167 | + pointee_layout: TyAndLayout<'tcx>, |
| 168 | + ptr_kind: Option<Mutability>, |
| 169 | + is_fn_entry: bool, |
175 | 170 | ) -> Option<RetagPlan<Bx::Value>> { |
176 | | - None |
| 171 | + let tcx = bx.tcx(); |
| 172 | + |
| 173 | + let pointee_ty = pointee_layout.ty; |
| 174 | + |
| 175 | + let is_mutable = matches!(ptr_kind, Some(Mutability::Mut) | None); |
| 176 | + let is_unpin = pointee_ty.is_unpin(tcx, bx.typing_env()); |
| 177 | + let is_freeze = pointee_ty.is_freeze(tcx, bx.typing_env()); |
| 178 | + let is_box = ptr_kind.is_none(); |
| 179 | + |
| 180 | + // `&mut !Unpin` is not protected |
| 181 | + let is_protected = is_fn_entry && (!is_mutable || is_unpin); |
| 182 | + |
| 183 | + if is_mutable && !is_unpin { |
| 184 | + return None; |
| 185 | + } |
| 186 | + |
| 187 | + let im_layout = bx.const_null(bx.type_ptr()); |
| 188 | + let pin_layout = bx.const_null(bx.type_ptr()); |
| 189 | + |
| 190 | + let mut flags = RetagFlags::empty(); |
| 191 | + flags.set(RetagFlags::IS_PROTECTED, is_protected); |
| 192 | + flags.set(RetagFlags::IS_MUTABLE, is_mutable); |
| 193 | + flags.set(RetagFlags::IS_FREEZE, is_freeze); |
| 194 | + flags.set(RetagFlags::IS_BOX, is_box); |
| 195 | + |
| 196 | + Some(RetagPlan::EmitRetag(RetagInfo { |
| 197 | + size: pointee_layout.size, |
| 198 | + im_layout, |
| 199 | + pin_layout, |
| 200 | + flags, |
| 201 | + })) |
177 | 202 | } |
178 | 203 | } |
179 | 204 |
|
180 | 205 | impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { |
181 | 206 | /// Retags the pointers within an [`OperandRef`]. |
182 | 207 | pub(crate) fn codegen_retag_operand( |
183 | 208 | &mut self, |
184 | | - _bx: &mut Bx, |
| 209 | + bx: &mut Bx, |
185 | 210 | operand: OperandRef<'tcx, Bx::Value>, |
186 | | - _is_fn_entry: bool, |
| 211 | + is_fn_entry: bool, |
187 | 212 | ) -> OperandRef<'tcx, Bx::Value> { |
| 213 | + if let OperandValue::Ref(place_ref) = operand.val { |
| 214 | + let place_ref = place_ref.with_type(operand.layout); |
| 215 | + self.codegen_retag_place(bx, place_ref, is_fn_entry); |
| 216 | + } else if let Some(plan) = RetagPlan::<Bx::Value>::build(bx, operand.layout, is_fn_entry) { |
| 217 | + let mut builder = OperandRefBuilder::from_existing(operand); |
| 218 | + self.retag_operand(bx, &plan, operand, &mut builder, Size::ZERO); |
| 219 | + return builder.build(bx.cx()); |
| 220 | + } |
188 | 221 | operand |
189 | 222 | } |
190 | 223 |
|
191 | 224 | /// Retags the pointers within a [`PlaceRef`]. |
192 | 225 | pub(crate) fn codegen_retag_place( |
193 | 226 | &mut self, |
194 | | - _bx: &mut Bx, |
195 | | - _place_ref: PlaceRef<'tcx, Bx::Value>, |
196 | | - _is_fn_entry: bool, |
| 227 | + bx: &mut Bx, |
| 228 | + place_ref: PlaceRef<'tcx, Bx::Value>, |
| 229 | + is_fn_entry: bool, |
197 | 230 | ) { |
| 231 | + if let Some(plan) = RetagPlan::<Bx::Value>::build(bx, place_ref.layout, is_fn_entry) { |
| 232 | + self.retag_place(bx, &plan, place_ref); |
| 233 | + } |
| 234 | + } |
| 235 | + |
| 236 | + fn retag_operand( |
| 237 | + &mut self, |
| 238 | + bx: &mut Bx, |
| 239 | + plan: &RetagPlan<Bx::Value>, |
| 240 | + curr_operand: OperandRef<'tcx, Bx::Value>, |
| 241 | + builder: &mut OperandRefBuilder<'tcx, Bx::Value>, |
| 242 | + offset: Size, |
| 243 | + ) { |
| 244 | + match plan { |
| 245 | + RetagPlan::EmitRetag(info) => { |
| 246 | + let (pointer, _) = curr_operand.val.pointer_parts(); |
| 247 | + let retagged_pointer = bx.retag_reg(pointer, info); |
| 248 | + builder.update_imm(offset, retagged_pointer); |
| 249 | + } |
| 250 | + RetagPlan::Recurse { field_plans, variant_plans } => { |
| 251 | + let layout = curr_operand.layout; |
| 252 | + for (ix, plan) in field_plans { |
| 253 | + let inner_offset = layout.fields.offset(ix.as_usize()); |
| 254 | + let field_offset = offset + inner_offset; |
| 255 | + |
| 256 | + let field_layout = curr_operand.layout.field(bx, ix.index()); |
| 257 | + // Part of https://github.com/rust-lang/compiler-team/issues/838 |
| 258 | + if !bx.is_backend_ref(curr_operand.layout) && bx.is_backend_ref(field_layout) { |
| 259 | + // FIXME: support vector types, requires insert_element as part of cg-ssa |
| 260 | + } else { |
| 261 | + let field_operand = curr_operand.extract_field(self, bx, ix.as_usize()); |
| 262 | + self.retag_operand(bx, &plan, field_operand, builder, field_offset); |
| 263 | + } |
| 264 | + } |
| 265 | + |
| 266 | + if !variant_plans.is_empty() { |
| 267 | + let discr_ty = layout.ty.discriminant_ty(bx.tcx()); |
| 268 | + let discr_val = curr_operand.codegen_get_discr(self, bx, discr_ty); |
| 269 | + |
| 270 | + if let Some(val) = bx.const_to_opt_u128(discr_val, false) { |
| 271 | + let ix = VariantIdx::from_usize(val as usize); |
| 272 | + if let Some(plan) = variant_plans.get(&ix) { |
| 273 | + let mut variant_op = curr_operand; |
| 274 | + variant_op.layout = curr_operand.layout.for_variant(bx, ix); |
| 275 | + |
| 276 | + self.retag_operand(bx, plan, variant_op, builder, offset); |
| 277 | + } |
| 278 | + } else { |
| 279 | + // We create a temporary place to store the operand, because its value will differ |
| 280 | + // depending on the variant that we have. |
| 281 | + let scratch = PlaceRef::alloca(bx, curr_operand.layout); |
| 282 | + scratch.storage_live(bx); |
| 283 | + curr_operand.store_with_annotation(bx, scratch); |
| 284 | + |
| 285 | + // We retag the contents of the place |
| 286 | + self.retag_variants(bx, scratch, discr_val, variant_plans); |
| 287 | + |
| 288 | + // Afterward, we load the now-updated operand and end the lifetime of the place. |
| 289 | + let updated_op = bx.load_operand(scratch); |
| 290 | + scratch.storage_dead(bx); |
| 291 | + |
| 292 | + match updated_op.val { |
| 293 | + OperandValue::ZeroSized | OperandValue::Ref(_) => {} |
| 294 | + OperandValue::Immediate(imm) => builder.update_imm(offset, imm), |
| 295 | + OperandValue::Pair(fst, snd) => { |
| 296 | + builder.update_imm(offset, fst); |
| 297 | + builder.update_imm(offset + Size::from_bytes(1), snd) |
| 298 | + } |
| 299 | + } |
| 300 | + } |
| 301 | + } |
| 302 | + } |
| 303 | + } |
| 304 | + } |
| 305 | + |
| 306 | + fn retag_place( |
| 307 | + &mut self, |
| 308 | + bx: &mut Bx, |
| 309 | + plan: &RetagPlan<Bx::Value>, |
| 310 | + place: PlaceRef<'tcx, Bx::Value>, |
| 311 | + ) { |
| 312 | + match plan { |
| 313 | + RetagPlan::EmitRetag(info) => { |
| 314 | + bx.retag_mem(place.val.llval, info); |
| 315 | + } |
| 316 | + RetagPlan::Recurse { field_plans, variant_plans } => { |
| 317 | + for (ix, plan) in field_plans { |
| 318 | + let field_place = place.project_field(bx, ix.as_usize()); |
| 319 | + self.retag_place(bx, &plan, field_place); |
| 320 | + } |
| 321 | + if !variant_plans.is_empty() { |
| 322 | + let operand = bx.load_operand(place); |
| 323 | + let discr_ty = place.layout.ty.discriminant_ty(bx.tcx()); |
| 324 | + let discr_val = operand.codegen_get_discr(self, bx, discr_ty); |
| 325 | + self.retag_variants(bx, place, discr_val, variant_plans); |
| 326 | + } |
| 327 | + } |
| 328 | + } |
| 329 | + } |
| 330 | + |
| 331 | + /// Retags each variant of a [`PlaceRef`] with the given discriminant. |
| 332 | + fn retag_variants( |
| 333 | + &mut self, |
| 334 | + bx: &mut Bx, |
| 335 | + place: PlaceRef<'tcx, Bx::Value>, |
| 336 | + discr: Bx::Value, |
| 337 | + variant_plans: &FxIndexMap<VariantIdx, RetagPlan<Bx::Value>>, |
| 338 | + ) { |
| 339 | + let layout = place.layout; |
| 340 | + |
| 341 | + let root_block = bx.llbb(); |
| 342 | + let mut variant_blocks = Vec::with_capacity(variant_plans.len()); |
| 343 | + let join_block = bx.append_sibling_block("retag_join"); |
| 344 | + |
| 345 | + for (ix, plan) in variant_plans { |
| 346 | + let variant_discr = layout.ty.discriminant_for_variant(bx.tcx(), *ix); |
| 347 | + let variant_discr_val = variant_discr.expect("Invalid variant index.").val; |
| 348 | + |
| 349 | + let variant_block = bx.append_sibling_block("retag_variant"); |
| 350 | + bx.switch_to_block(variant_block); |
| 351 | + |
| 352 | + let variant_place = place.project_downcast(bx, *ix); |
| 353 | + self.retag_place(bx, plan, variant_place); |
| 354 | + |
| 355 | + variant_blocks.push((variant_discr_val, variant_block)); |
| 356 | + bx.br(join_block); |
| 357 | + } |
| 358 | + |
| 359 | + bx.switch_to_block(root_block); |
| 360 | + bx.switch(discr, join_block, variant_blocks.into_iter()); |
| 361 | + bx.switch_to_block(join_block); |
198 | 362 | } |
199 | 363 | } |
0 commit comments