Skip to content

Commit 567dab7

Browse files
committed
Split up TypeId into pointer sized fields for CTFE to use as opaque ids
1 parent 2e44bf9 commit 567dab7

File tree

19 files changed

+177
-147
lines changed

19 files changed

+177
-147
lines changed

compiler/rustc_codegen_cranelift/src/constant.rs

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
use std::cmp::Ordering;
44

55
use cranelift_module::*;
6+
use rustc_abi::Align;
7+
use rustc_const_eval::interpret::{AllocInit, Allocation, alloc_range};
68
use rustc_data_structures::fx::FxHashSet;
79
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
810
use rustc_middle::mir::interpret::{AllocId, GlobalAlloc, Scalar, read_target_uint};
@@ -175,8 +177,13 @@ pub(crate) fn codegen_const_value<'tcx>(
175177
fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
176178
fx.bcx.ins().global_value(fx.pointer_type, local_data_id)
177179
}
178-
// TODO: generate pointer to allocation containing the actual type id hash u128 value
179-
GlobalAlloc::Type(_) => todo!(),
180+
GlobalAlloc::Type { ty: type_id_ty, segment } => {
181+
return CValue::const_val(
182+
fx,
183+
layout,
184+
type_id_segment(fx.tcx, type_id_ty, segment),
185+
);
186+
}
180187
GlobalAlloc::Static(def_id) => {
181188
assert!(fx.tcx.is_static(def_id));
182189
let data_id = data_id_for_static(
@@ -214,6 +221,23 @@ pub(crate) fn codegen_const_value<'tcx>(
214221
}
215222
}
216223

224+
fn type_id_segment<'tcx>(tcx: TyCtxt<'tcx>, type_id_ty: Ty<'tcx>, segment: u8) -> ScalarInt {
225+
let type_id = tcx.type_id_hash(type_id_ty).as_u128();
226+
let mut alloc: Allocation =
227+
Allocation::new(Size::from_bytes(16), Align::from_bytes(8).unwrap(), AllocInit::Uninit, ());
228+
alloc
229+
.write_scalar(
230+
&tcx,
231+
alloc_range(Size::ZERO, Size::from_bytes(16)),
232+
Scalar::from_u128(type_id),
233+
)
234+
.unwrap();
235+
let pointer_size = tcx.data_layout.pointer_size;
236+
let offset = pointer_size * u64::from(segment);
237+
let value = alloc.read_scalar(&tcx, alloc_range(offset, pointer_size), false).unwrap();
238+
value.to_scalar_int().unwrap()
239+
}
240+
217241
fn pointer_for_allocation<'tcx>(
218242
fx: &mut FunctionCx<'_, '_, 'tcx>,
219243
alloc_id: AllocId,
@@ -362,7 +386,7 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
362386
GlobalAlloc::Memory(alloc) => alloc,
363387
GlobalAlloc::Function { .. }
364388
| GlobalAlloc::Static(_)
365-
| GlobalAlloc::Type(_)
389+
| GlobalAlloc::Type { .. }
366390
| GlobalAlloc::VTable(..) => {
367391
unreachable!()
368392
}
@@ -474,8 +498,18 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
474498
.principal()
475499
.map(|principal| tcx.instantiate_bound_regions_with_erased(principal)),
476500
),
477-
// TODO
478-
GlobalAlloc::Type(_ty) => todo!(),
501+
GlobalAlloc::Type { ty, segment } => {
502+
let val = type_id_segment(tcx, ty, segment);
503+
let Init::Bytes { contents } = &mut data.init else { unreachable!() };
504+
let start = offset.bytes_usize();
505+
let ptr_size = tcx.data_layout.pointer_size;
506+
let src = val.to_bits(ptr_size);
507+
let src = u128::to_le_bytes(src);
508+
let len = ptr_size.bytes_usize();
509+
assert!(src[len..].iter().all(|b| *b == 0));
510+
contents[start..(start + len)].copy_from_slice(&src[..len]);
511+
continue;
512+
}
479513
GlobalAlloc::Static(def_id) => {
480514
if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL)
481515
{

compiler/rustc_codegen_cranelift/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ extern crate rustc_middle;
2020
extern crate rustc_abi;
2121
extern crate rustc_ast;
2222
extern crate rustc_codegen_ssa;
23+
extern crate rustc_const_eval;
2324
extern crate rustc_data_structures;
2425
extern crate rustc_errors;
2526
extern crate rustc_fs_util;

compiler/rustc_codegen_gcc/src/common.rs

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
use gccjit::{LValue, RValue, ToRValue, Type};
2-
use rustc_abi as abi;
3-
use rustc_abi::HasDataLayout;
42
use rustc_abi::Primitive::Pointer;
3+
use rustc_abi::{self as abi, Align, HasDataLayout, Size};
54
use rustc_codegen_ssa::traits::{
65
BaseTypeCodegenMethods, ConstCodegenMethods, MiscCodegenMethods, StaticCodegenMethods,
76
};
7+
use rustc_const_eval::interpret::{AllocInit, Allocation, alloc_range};
88
use rustc_middle::mir::Mutability;
99
use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar};
1010
use rustc_middle::ty::layout::LayoutOf;
@@ -282,8 +282,30 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> {
282282
let init = self.const_data_from_alloc(alloc);
283283
self.static_addr_of(init, alloc.inner().align, None)
284284
}
285-
// TODO: generate pointer to allocation containing the actual type id hash u128 value
286-
GlobalAlloc::Type(_ty) => todo!(),
285+
GlobalAlloc::Type { ty: type_id_ty, segment } => {
286+
let type_id = self.tcx.type_id_hash(type_id_ty).as_u128();
287+
let mut alloc: Allocation = Allocation::new(
288+
Size::from_bytes(16),
289+
Align::from_bytes(8).unwrap(),
290+
AllocInit::Uninit,
291+
(),
292+
);
293+
alloc
294+
.write_scalar(
295+
&self.tcx,
296+
alloc_range(Size::ZERO, Size::from_bytes(16)),
297+
Scalar::from_u128(type_id),
298+
)
299+
.unwrap();
300+
let pointer_size = self.tcx.data_layout.pointer_size;
301+
let offset = pointer_size * u64::from(segment);
302+
let value = alloc
303+
.read_scalar(&self.tcx, alloc_range(offset, pointer_size), false)
304+
.unwrap();
305+
let data = value.to_bits(pointer_size).unwrap() as u64;
306+
let val = self.const_usize(data);
307+
return self.context.new_cast(None, val, ty);
308+
}
287309
GlobalAlloc::Static(def_id) => {
288310
assert!(self.tcx.is_static(def_id));
289311
self.get_static(def_id).get_address(None)

compiler/rustc_codegen_gcc/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ extern crate rustc_apfloat;
4141
extern crate rustc_ast;
4242
extern crate rustc_attr_data_structures;
4343
extern crate rustc_codegen_ssa;
44+
extern crate rustc_const_eval;
4445
extern crate rustc_data_structures;
4546
extern crate rustc_errors;
4647
extern crate rustc_fluent_macro;

compiler/rustc_codegen_llvm/src/common.rs

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::borrow::Borrow;
44

55
use libc::{c_char, c_uint};
66
use rustc_abi::Primitive::Pointer;
7-
use rustc_abi::{self as abi, Align, HasDataLayout, Size};
7+
use rustc_abi::{self as abi, Align, HasDataLayout as _, Size};
88
use rustc_ast::Mutability;
99
use rustc_codegen_ssa::common::TypeKind;
1010
use rustc_codegen_ssa::traits::*;
@@ -319,17 +319,16 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> {
319319
)))
320320
.unwrap_memory();
321321
let init = const_alloc_to_llvm(self, alloc.inner(), /*static*/ false);
322-
let value = self.static_addr_of_impl(init, alloc.inner().align, None);
323-
value
322+
self.static_addr_of_impl(init, alloc.inner().align, None)
324323
}
325324
GlobalAlloc::Static(def_id) => {
326325
assert!(self.tcx.is_static(def_id));
327326
assert!(!self.tcx.is_thread_local_static(def_id));
328327
self.get_static(def_id)
329328
}
330-
GlobalAlloc::Type(ty) => {
329+
GlobalAlloc::Type { ty, segment } => {
331330
let type_id = self.tcx.type_id_hash(ty).as_u128();
332-
let mut alloc = Allocation::new(
331+
let mut alloc: Allocation = Allocation::new(
333332
Size::from_bytes(16),
334333
Align::from_bytes(8).unwrap(),
335334
AllocInit::Uninit,
@@ -342,17 +341,13 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> {
342341
Scalar::from_u128(type_id),
343342
)
344343
.unwrap();
345-
alloc.mutability = Mutability::Not;
346-
let init = const_alloc_to_llvm(self, &alloc, /*static*/ false);
347-
self.static_addr_of_impl(init, alloc.align, None)
348-
}
349-
GlobalAlloc::PartialHash(ty) => {
350-
assert!(matches!(layout.primitive(), Pointer(_)));
351-
let bytes = self.tcx.type_id_hash(ty).truncate().as_u64().to_be_bytes();
352-
let bits = self.tcx.data_layout.pointer_size.bits();
353-
let mask = u64::MAX >> (64 - bits);
354-
// It doesn't matter which bits we pick as long as the scheme is the same with the same compiler.
355-
let llval = self.const_usize(u64::from_be_bytes(bytes) & mask);
344+
let pointer_size = self.tcx.data_layout.pointer_size;
345+
let offset = pointer_size * u64::from(segment);
346+
let value = alloc
347+
.read_scalar(&self.tcx, alloc_range(offset, pointer_size), false)
348+
.unwrap();
349+
let data = value.to_bits(pointer_size).unwrap() as u64;
350+
let llval = self.const_usize(data);
356351
return unsafe { llvm::LLVMConstIntToPtr(llval, llty) };
357352
}
358353
};

compiler/rustc_codegen_ssa/src/mir/operand.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
185185
offset: Size,
186186
) -> Self {
187187
let alloc_align = alloc.inner().align;
188-
assert!(alloc_align >= layout.align.abi);
188+
assert!(alloc_align >= layout.align.abi, "{alloc_align:?} < {:?}", layout.align.abi);
189189

190190
let read_scalar = |start, size, s: abi::Scalar, ty| {
191191
match alloc.0.read_scalar(

compiler/rustc_const_eval/src/const_eval/machine.rs

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -405,18 +405,34 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
405405
}
406406
sym::type_id_eq => {
407407
let a = ecx.project_field(&args[0], FieldIdx::ZERO)?;
408-
let a = ecx.deref_pointer(&a)?;
409-
let (a, offset) = a.ptr().into_parts();
410-
assert_eq!(offset, Size::ZERO);
411-
let a = a.unwrap().alloc_id();
412-
let GlobalAlloc::Type(a) = ecx.tcx.global_alloc(a) else { bug!() };
413408
let b = ecx.project_field(&args[1], FieldIdx::ZERO)?;
414-
let b = ecx.deref_pointer(&b)?;
415-
let (b, offset) = b.ptr().into_parts();
416-
assert_eq!(offset, Size::ZERO);
417-
let b = b.unwrap().alloc_id();
418-
let GlobalAlloc::Type(b) = ecx.tcx.global_alloc(b) else { bug!() };
419-
ecx.write_scalar(Scalar::from_bool(a == b), dest)?;
409+
let mut eq = true;
410+
for index in 0..(16 / ecx.tcx.data_layout.pointer_size.bytes()) {
411+
let a = ecx.project_index(&a, index)?;
412+
let a = ecx.deref_pointer(&a)?;
413+
let (a, offset) = a.ptr().into_parts();
414+
assert_eq!(offset, Size::ZERO);
415+
let a = a.unwrap().alloc_id();
416+
let GlobalAlloc::Type { ty: a, segment: a_segment } = ecx.tcx.global_alloc(a)
417+
else {
418+
bug!()
419+
};
420+
let b = ecx.project_index(&b, index)?;
421+
let b = ecx.deref_pointer(&b)?;
422+
let (b, offset) = b.ptr().into_parts();
423+
assert_eq!(offset, Size::ZERO);
424+
let b = b.unwrap().alloc_id();
425+
let GlobalAlloc::Type { ty: b, segment: b_segment } = ecx.tcx.global_alloc(b)
426+
else {
427+
bug!()
428+
};
429+
430+
eq &= a == b && a_segment == b_segment;
431+
if !eq {
432+
break;
433+
}
434+
}
435+
ecx.write_scalar(Scalar::from_bool(eq), dest)?;
420436
}
421437
sym::const_allocate => {
422438
let size = ecx.read_scalar(&args[0])?.to_target_usize(ecx)?;

compiler/rustc_const_eval/src/interpret/intrinsics.rs

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use std::assert_matches::assert_matches;
77
use rustc_abi::Size;
88
use rustc_apfloat::ieee::{Double, Half, Quad, Single};
99
use rustc_ast::Mutability;
10-
use rustc_middle::mir::interpret::{AllocId, AllocInit, CtfeProvenance, alloc_range};
10+
use rustc_middle::mir::interpret::{AllocId, AllocInit, alloc_range};
1111
use rustc_middle::mir::{self, BinOp, ConstValue, NonDivergingIntrinsic};
1212
use rustc_middle::ty::layout::{TyAndLayout, ValidityRequirement};
1313
use rustc_middle::ty::{Ty, TyCtxt};
@@ -32,24 +32,17 @@ pub(crate) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ConstAll
3232
}
3333

3434
pub(crate) fn alloc_type_id<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> AllocId {
35-
let ptr_size = tcx.data_layout.pointer_size;
35+
let size = Size::from_bytes(16);
3636
let align = tcx.data_layout.pointer_align;
37-
38-
let mut alloc = Allocation::new(ptr_size * 2, *align, AllocInit::Uninit, ());
39-
// Write a pointer pointing to the hash. At ctfe time this is an opaque pointer that you cannot deref
40-
let ptr = tcx.reserve_and_set_type_id_alloc(ty);
41-
let ptr = Pointer::new(CtfeProvenance::from(ptr), Size::ZERO);
42-
alloc
43-
.write_scalar(&tcx, alloc_range(Size::ZERO, ptr_size), Scalar::from_pointer(ptr, &tcx))
44-
.unwrap();
45-
46-
// Write a pointer that is not actually a pointer but will just get replaced by the first `pointer_size` bytes of the hash
47-
// in codegen. It is a pointer in CTFE so no one can access the bits.
48-
let ptr = tcx.reserve_and_set_type_id_partial_hash(ty);
49-
let ptr = Pointer::new(CtfeProvenance::from(ptr), Size::ZERO);
50-
alloc
51-
.write_scalar(&tcx, alloc_range(ptr_size, ptr_size), Scalar::from_pointer(ptr, &tcx))
52-
.unwrap();
37+
let mut alloc = Allocation::new(size, *align, AllocInit::Uninit, ());
38+
let ptr_size = tcx.data_layout.pointer_size;
39+
for step in 0..size.bytes() / ptr_size.bytes() {
40+
let offset = ptr_size * step;
41+
let alloc_id = tcx.reserve_and_set_type_id_alloc(ty, step.try_into().unwrap());
42+
let ptr = Pointer::new(alloc_id.into(), Size::ZERO);
43+
let val = Scalar::from_pointer(ptr, &tcx);
44+
alloc.write_scalar(&tcx, alloc_range(offset, ptr_size), val).unwrap();
45+
}
5346

5447
alloc.mutability = Mutability::Not;
5548

@@ -90,7 +83,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
9083
sym::type_id => {
9184
let tp_ty = instance.args.type_at(0);
9285
ensure_monomorphic_enough(tcx, tp_ty)?;
93-
let alloc_id = alloc_type_id(tcx, tp_ty);
86+
let alloc_id = alloc_type_id(tcx, tp_ty);
9487
let val = ConstValue::Indirect { alloc_id, offset: Size::ZERO };
9588
let val = self.const_val_to_op(val, dest.layout.ty, Some(dest.layout))?;
9689
self.copy_op(&val, dest)?;

compiler/rustc_const_eval/src/interpret/memory.rs

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -346,20 +346,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
346346
kind = "vtable",
347347
)
348348
}
349-
Some(GlobalAlloc::Type(..)) => {
349+
Some(GlobalAlloc::Type { .. }) => {
350350
err_ub_custom!(
351351
fluent::const_eval_invalid_dealloc,
352352
alloc_id = alloc_id,
353353
kind = "typeid",
354354
)
355355
}
356-
Some(GlobalAlloc::PartialHash(..)) => {
357-
err_ub_custom!(
358-
fluent::const_eval_invalid_dealloc,
359-
alloc_id = alloc_id,
360-
kind = "partial_hash",
361-
)
362-
}
363356
Some(GlobalAlloc::Static(..) | GlobalAlloc::Memory(..)) => {
364357
err_ub_custom!(
365358
fluent::const_eval_invalid_dealloc,
@@ -629,9 +622,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
629622
}
630623
Some(GlobalAlloc::Function { .. }) => throw_ub!(DerefFunctionPointer(id)),
631624
Some(GlobalAlloc::VTable(..)) => throw_ub!(DerefVTablePointer(id)),
632-
Some(GlobalAlloc::Type(..)) | Some(GlobalAlloc::PartialHash(..)) => {
633-
throw_ub!(DerefTypeIdPointer(id))
634-
}
625+
Some(GlobalAlloc::Type { .. }) => throw_ub!(DerefTypeIdPointer(id)),
635626
None => throw_ub!(PointerUseAfterFree(id, CheckInAllocMsg::MemoryAccess)),
636627
Some(GlobalAlloc::Static(def_id)) => {
637628
assert!(self.tcx.is_static(def_id));
@@ -911,8 +902,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
911902
let (size, align) = global_alloc.size_and_align(*self.tcx, self.typing_env);
912903
let mutbl = global_alloc.mutability(*self.tcx, self.typing_env);
913904
let kind = match global_alloc {
914-
GlobalAlloc::Type(_)
915-
| GlobalAlloc::PartialHash(_)
905+
GlobalAlloc::Type { .. }
916906
| GlobalAlloc::Static { .. }
917907
| GlobalAlloc::Memory { .. } => AllocKind::LiveData,
918908
GlobalAlloc::Function { .. } => bug!("We already checked function pointers above"),
@@ -1224,11 +1214,8 @@ impl<'a, 'tcx, M: Machine<'tcx>> std::fmt::Debug for DumpAllocs<'a, 'tcx, M> {
12241214
Some(GlobalAlloc::VTable(ty, dyn_ty)) => {
12251215
write!(fmt, " (vtable: impl {dyn_ty} for {ty})")?;
12261216
}
1227-
Some(GlobalAlloc::Type(ty)) => {
1228-
write!(fmt, " (typeid for {ty})")?;
1229-
}
1230-
Some(GlobalAlloc::PartialHash(ty)) => {
1231-
write!(fmt, " (partial hash of {ty})")?;
1217+
Some(GlobalAlloc::Type { ty, segment }) => {
1218+
write!(fmt, " (typeid segment {segment } for {ty})")?;
12321219
}
12331220
Some(GlobalAlloc::Static(did)) => {
12341221
write!(fmt, " (static: {})", self.ecx.tcx.def_path_str(did))?;

compiler/rustc_const_eval/src/interpret/validity.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -610,9 +610,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
610610
}
611611
}
612612
// These are controlled by rustc and not available for CTFE
613-
GlobalAlloc::Type(_) | GlobalAlloc::PartialHash(_) => {
614-
skip_recursive_check = true
615-
}
613+
GlobalAlloc::Type { .. } => skip_recursive_check = true,
616614
_ => (),
617615
}
618616

0 commit comments

Comments
 (0)