about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_abi/src/lib.rs12
-rw-r--r--compiler/rustc_codegen_ssa/src/glue.rs3
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/intrinsic.rs12
-rw-r--r--src/test/codegen/dst-vtable-align-nonzero.rs18
-rw-r--r--src/test/codegen/dst-vtable-size-range.rs37
5 files changed, 79 insertions, 3 deletions
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index e14c9ea9a5d..27b8377a9e0 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -775,6 +775,18 @@ impl Integer {
         }
     }
 
+    /// Returns the largest signed value that can be represented by this Integer.
+    #[inline]
+    pub fn signed_max(self) -> i128 {
+        match self {
+            I8 => i8::MAX as i128,
+            I16 => i16::MAX as i128,
+            I32 => i32::MAX as i128,
+            I64 => i64::MAX as i128,
+            I128 => i128::MAX,
+        }
+    }
+
     /// Finds the smallest Integer type which can represent the signed value.
     #[inline]
     pub fn fit_signed(x: i128) -> Integer {
diff --git a/compiler/rustc_codegen_ssa/src/glue.rs b/compiler/rustc_codegen_ssa/src/glue.rs
index 6015d48deca..0f6e6032f9b 100644
--- a/compiler/rustc_codegen_ssa/src/glue.rs
+++ b/compiler/rustc_codegen_ssa/src/glue.rs
@@ -29,6 +29,9 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
             let align = meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_ALIGN)
                 .get_usize(bx, vtable);
 
+            // Size is always <= isize::MAX.
+            let size_bound = bx.data_layout().ptr_sized_integer().signed_max() as u128;
+            bx.range_metadata(size, WrappingRange { start: 0, end: size_bound });
             // Alignment is always nonzero.
             bx.range_metadata(align, WrappingRange { start: 1, end: !0 });
 
diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
index 215edbe02c0..a75609260ed 100644
--- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
@@ -110,10 +110,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     _ => bug!(),
                 };
                 let value = meth::VirtualIndex::from_index(idx).get_usize(bx, vtable);
-                if name == sym::vtable_align {
+                match name {
+                    // Size is always <= isize::MAX.
+                    sym::vtable_size => {
+                        let size_bound = bx.data_layout().ptr_sized_integer().signed_max() as u128;
+                        bx.range_metadata(value, WrappingRange { start: 0, end: size_bound });
+                    },
                     // Alignment is always nonzero.
-                    bx.range_metadata(value, WrappingRange { start: 1, end: !0 });
-                };
+                    sym::vtable_align => bx.range_metadata(value, WrappingRange { start: 1, end: !0 }),
+                    _ => {}
+                }
                 value
             }
             sym::pref_align_of
diff --git a/src/test/codegen/dst-vtable-align-nonzero.rs b/src/test/codegen/dst-vtable-align-nonzero.rs
index 14c4c3f30f9..7ebb4173d56 100644
--- a/src/test/codegen/dst-vtable-align-nonzero.rs
+++ b/src/test/codegen/dst-vtable-align-nonzero.rs
@@ -1,6 +1,7 @@
 // compile-flags: -O
 
 #![crate_type = "lib"]
+#![feature(core_intrinsics)]
 
 // This test checks that we annotate alignment loads from vtables with nonzero range metadata,
 // and that this allows LLVM to eliminate redundant `align >= 1` checks.
@@ -42,4 +43,21 @@ pub fn does_not_eliminate_runtime_check_when_align_2(
     &x.dst
 }
 
+// CHECK-LABEL: @align_load_from_align_of_val
+#[no_mangle]
+pub fn align_load_from_align_of_val(x: &dyn Trait) -> usize {
+    // CHECK: {{%[0-9]+}} = load [[USIZE]], {{.+}} !range [[RANGE_META]]
+    core::mem::align_of_val(x)
+}
+
+// CHECK-LABEL: @align_load_from_vtable_align_intrinsic
+#[no_mangle]
+pub unsafe fn align_load_from_vtable_align_intrinsic(x: &dyn Trait) -> usize {
+    let (data, vtable): (*const (), *const ()) = core::mem::transmute(x);
+    // CHECK: {{%[0-9]+}} = load [[USIZE]], {{.+}} !range [[RANGE_META]]
+    let align = core::intrinsics::vtable_align(vtable);
+    // make this function unique so it doesn't get merged with the previous
+    align + 1
+}
+
 // CHECK: [[RANGE_META]] = !{[[USIZE]] 1, [[USIZE]] 0}
diff --git a/src/test/codegen/dst-vtable-size-range.rs b/src/test/codegen/dst-vtable-size-range.rs
new file mode 100644
index 00000000000..cec5876b348
--- /dev/null
+++ b/src/test/codegen/dst-vtable-size-range.rs
@@ -0,0 +1,37 @@
+// compile-flags: -O
+
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+// Check that we annotate size loads from vtables with 0..(isize::MAX + 1) range metadata.
+
+pub trait Trait {
+    fn f(&self);
+}
+
+// Note that rustc uses inclusive bounds, but LLVM uses exclusive bounds for range metadata.
+// CHECK-LABEL: @generate_exclusive_bound
+#[no_mangle]
+pub fn generate_exclusive_bound() -> usize {
+    // CHECK: ret [[USIZE:i[0-9]+]] [[EXCLUSIVE_BOUND:[-0-9]+]]
+    isize::MAX as usize + 1
+}
+
+// CHECK-LABEL: @size_load_from_size_of_val
+#[no_mangle]
+pub fn size_load_from_size_of_val(x: &dyn Trait) -> usize {
+    // CHECK: {{%[0-9]+}} = load [[USIZE]], {{.+}} !range [[RANGE_META:![0-9]+]]
+    core::mem::size_of_val(x)
+}
+
+// CHECK-LABEL: @size_load_from_vtable_size_intrinsic
+#[no_mangle]
+pub unsafe fn size_load_from_vtable_size_intrinsic(x: &dyn Trait) -> usize {
+    let (data, vtable): (*const (), *const ()) = core::mem::transmute(x);
+    // CHECK: {{%[0-9]+}} = load [[USIZE]], {{.+}} !range [[RANGE_META]]
+    let size = core::intrinsics::vtable_size(vtable);
+    // make this function unique so it doesn't get merged with the previous
+    size + 1
+}
+
+// CHECK: [[RANGE_META]] = !{[[USIZE]] 0, [[USIZE]] [[EXCLUSIVE_BOUND]]}