about summary refs log tree commit diff
path: root/src/test/codegen
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-06-14 21:37:11 +0000
committerbors <bors@rust-lang.org>2022-06-14 21:37:11 +0000
commit2d1e0750792529248ed6f11061940c7203d668c9 (patch)
tree354b2d33e105f927b0e0a25d509b56f003eb0597 /src/test/codegen
parent1f34da9ec8a85b6f86c5fa1c121ab6f88f2f4966 (diff)
parent195f2082002c9db456e0fde8c1d5db79929ae293 (diff)
Auto merge of #96285 - flip1995:pk-vfe, r=nagisa
Introduce `-Zvirtual-function-elimination` codegen flag

Fixes #68262

This PR adds a codegen flag `-Zvirtual-function-elimination` to enable the VFE optimization in LLVM. To make this work, additonal  information has to be added to vtables ([`!vcall_visibility` metadata](https://llvm.org/docs/TypeMetadata.html#vcall-visibility-metadata) and a `typeid` of the trait). Furthermore, instead of just `load`ing functions, the [`llvm.type.checked.load` intrinsic](https://llvm.org/docs/LangRef.html#llvm-type-checked-load-intrinsic) has to be used to map functions to vtables.

For technical details of the changes, see the commit messages.

I also tested this flag on https://github.com/tock/tock on different boards to verify that this fixes the issue https://github.com/tock/tock/issues/2594. This flag is able to improve the size of the resulting binary by about 8k-9k bytes by removing the unused debug print functions.

[Rendered documentation update](https://github.com/flip1995/rust/blob/pk-vfe/src/doc/rustc/src/codegen-options/index.md#virtual-function-elimination)
Diffstat (limited to 'src/test/codegen')
-rw-r--r--src/test/codegen/virtual-function-elimination-32bit.rs35
-rw-r--r--src/test/codegen/virtual-function-elimination.rs100
2 files changed, 135 insertions, 0 deletions
diff --git a/src/test/codegen/virtual-function-elimination-32bit.rs b/src/test/codegen/virtual-function-elimination-32bit.rs
new file mode 100644
index 00000000000..6f963363a99
--- /dev/null
+++ b/src/test/codegen/virtual-function-elimination-32bit.rs
@@ -0,0 +1,35 @@
+// compile-flags: -Zvirtual-function-elimination -Clto -O -Csymbol-mangling-version=v0
+// ignore-64bit
+
+// CHECK: @vtable.0 = {{.*}}, !type ![[TYPE0:[0-9]+]], !vcall_visibility ![[VCALL_VIS0:[0-9]+]]
+
+#![crate_type = "lib"]
+
+trait T {
+    // CHECK-LABEL: ; <virtual_function_elimination_32bit::S as virtual_function_elimination_32bit::T>::used
+    fn used(&self) -> i32 {
+        1
+    }
+    // CHECK-LABEL-NOT: {{.*}}::unused
+    fn unused(&self) -> i32 {
+        2
+    }
+}
+
+#[derive(Copy, Clone)]
+struct S;
+
+impl T for S {}
+
+fn taking_t(t: &dyn T) -> i32 {
+    // CHECK: @llvm.type.checked.load({{.*}}, i32 12, metadata !"[[MANGLED_TYPE0:[0-9a-zA-Z_]+]]")
+    t.used()
+}
+
+pub fn main() {
+    let s = S;
+    taking_t(&s);
+}
+
+// CHECK: ![[TYPE0]] = !{i32 0, !"[[MANGLED_TYPE0]]"}
+// CHECK: ![[VCALL_VIS0]] = !{i64 2}
diff --git a/src/test/codegen/virtual-function-elimination.rs b/src/test/codegen/virtual-function-elimination.rs
new file mode 100644
index 00000000000..4cf7e12fee2
--- /dev/null
+++ b/src/test/codegen/virtual-function-elimination.rs
@@ -0,0 +1,100 @@
+// compile-flags: -Zvirtual-function-elimination -Clto -O -Csymbol-mangling-version=v0
+// ignore-32bit
+
+// CHECK: @vtable.0 = {{.*}}, !type ![[TYPE0:[0-9]+]], !vcall_visibility ![[VCALL_VIS0:[0-9]+]]
+// CHECK: @vtable.1 = {{.*}}, !type ![[TYPE1:[0-9]+]], !vcall_visibility ![[VCALL_VIS0:[0-9]+]]
+// CHECK: @vtable.2 = {{.*}}, !type ![[TYPE2:[0-9]+]], !vcall_visibility ![[VCALL_VIS2:[0-9]+]]
+
+#![crate_type = "lib"]
+#![allow(incomplete_features)]
+#![feature(unsized_locals)]
+
+use std::rc::Rc;
+
+trait T {
+    // CHECK-LABEL: ; <virtual_function_elimination::S as virtual_function_elimination::T>::used
+    fn used(&self) -> i32 {
+        1
+    }
+    // CHECK-LABEL: ; <virtual_function_elimination::S as virtual_function_elimination::T>::used_through_sub_trait
+    fn used_through_sub_trait(&self) -> i32 {
+        3
+    }
+    // CHECK-LABEL: ; <virtual_function_elimination::S as virtual_function_elimination::T>::by_rc
+    fn by_rc(self: Rc<Self>) -> i32 {
+        self.used() + self.used()
+    }
+    // CHECK-LABEL-NOT: {{.*}}::unused
+    fn unused(&self) -> i32 {
+        2
+    }
+    // CHECK-LABEL-NOT: {{.*}}::by_rc_unused
+    fn by_rc_unused(self: Rc<Self>) -> i32 {
+        self.by_rc()
+    }
+}
+
+trait U: T {
+    // CHECK-LABEL: ; <virtual_function_elimination::S as virtual_function_elimination::U>::subtrait_used
+    fn subtrait_used(&self) -> i32 {
+        4
+    }
+    // CHECK-LABEL-NOT: {{.*}}::subtrait_unused
+    fn subtrait_unused(&self) -> i32 {
+        5
+    }
+}
+
+pub trait V {
+    // CHECK-LABEL: ; <virtual_function_elimination::S as virtual_function_elimination::V>::public_function
+    fn public_function(&self) -> i32;
+}
+
+#[derive(Copy, Clone)]
+struct S;
+
+impl T for S {}
+
+impl U for S {}
+
+impl V for S {
+    fn public_function(&self) -> i32 {
+        6
+    }
+}
+
+fn taking_t(t: &dyn T) -> i32 {
+    // CHECK: @llvm.type.checked.load({{.*}}, i32 24, metadata !"[[MANGLED_TYPE0:[0-9a-zA-Z_]+]]")
+    t.used()
+}
+
+fn taking_rc_t(t: Rc<dyn T>) -> i32 {
+    // CHECK: @llvm.type.checked.load({{.*}}, i32 40, metadata !"[[MANGLED_TYPE0:[0-9a-zA-Z_]+]]")
+    t.by_rc()
+}
+
+fn taking_u(u: &dyn U) -> i32 {
+    // CHECK: @llvm.type.checked.load({{.*}}, i32 64, metadata !"[[MANGLED_TYPE1:[0-9a-zA-Z_]+]]")
+    // CHECK: @llvm.type.checked.load({{.*}}, i32 24, metadata !"[[MANGLED_TYPE1:[0-9a-zA-Z_]+]]")
+    // CHECK: @llvm.type.checked.load({{.*}}, i32 32, metadata !"[[MANGLED_TYPE1:[0-9a-zA-Z_]+]]")
+    u.subtrait_used() + u.used() + u.used_through_sub_trait()
+}
+
+pub fn taking_v(v: &dyn V) -> i32 {
+    // CHECK: @llvm.type.checked.load({{.*}}, i32 24, metadata !"NtCsfRpWlKdQPZn_28virtual_function_elimination1V")
+    v.public_function()
+}
+
+pub fn main() {
+    let s = S;
+    taking_t(&s);
+    taking_rc_t(Rc::new(s));
+    taking_u(&s);
+    taking_v(&s);
+}
+
+// CHECK: ![[TYPE0]] = !{i64 0, !"[[MANGLED_TYPE0]]"}
+// CHECK: ![[VCALL_VIS0]] = !{i64 2}
+// CHECK: ![[TYPE1]] = !{i64 0, !"[[MANGLED_TYPE1]]"}
+// CHECK: ![[TYPE2]] = !{i64 0, !"NtCsfRpWlKdQPZn_28virtual_function_elimination1V"}
+// CHECK: ![[VCALL_VIS2]] = !{i64 1}