about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-08-08 13:33:53 +0000
committerbors <bors@rust-lang.org>2020-08-08 13:33:53 +0000
commit2bac92bba14f3b260b337d2a51c77c0780456e65 (patch)
tree92e808c9d9a93e2423dd62fd12eaa2165b9b6ac2
parentc989ac132a81503ceaaa1054da0a3a8c5c305ef0 (diff)
parent7e5c7cf8e32d43b1c7fca06effbc7739634c31a0 (diff)
Auto merge of #74533 - nikic:issue-74425, r=eddyb
Emit == null instead of <= null for niche check

When the niche maximum is zero, emit a "== zero" check instead of a "<= zero" check. In particular, this avoids the awkward case of "<= null". While LLVM does canonicalize this to "== null", this apparently doesn't happen for constant expressions, leading to the issue in #74425. While that can be addressed on the LLVM side, it still seems prudent to emit sensible IR here, because this will allow null checks to be optimized earlier in the pipeline.

Fixes #74425.
-rw-r--r--src/librustc_codegen_ssa/mir/place.rs15
-rw-r--r--src/test/codegen/some-global-nonnull.rs25
2 files changed, 32 insertions, 8 deletions
diff --git a/src/librustc_codegen_ssa/mir/place.rs b/src/librustc_codegen_ssa/mir/place.rs
index 0c8638b673d..05656774f0e 100644
--- a/src/librustc_codegen_ssa/mir/place.rs
+++ b/src/librustc_codegen_ssa/mir/place.rs
@@ -253,14 +253,13 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
                     bx.sub(tag, bx.cx().const_uint_big(niche_llty, niche_start))
                 };
                 let relative_max = niche_variants.end().as_u32() - niche_variants.start().as_u32();
-                let is_niche = {
-                    let relative_max = if relative_max == 0 {
-                        // Avoid calling `const_uint`, which wouldn't work for pointers.
-                        // FIXME(eddyb) check the actual primitive type here.
-                        bx.cx().const_null(niche_llty)
-                    } else {
-                        bx.cx().const_uint(niche_llty, relative_max as u64)
-                    };
+                let is_niche = if relative_max == 0 {
+                    // Avoid calling `const_uint`, which wouldn't work for pointers.
+                    // Also use canonical == 0 instead of non-canonical u<= 0.
+                    // FIXME(eddyb) check the actual primitive type here.
+                    bx.icmp(IntPredicate::IntEQ, relative_discr, bx.cx().const_null(niche_llty))
+                } else {
+                    let relative_max = bx.cx().const_uint(niche_llty, relative_max as u64);
                     bx.icmp(IntPredicate::IntULE, relative_discr, relative_max)
                 };
 
diff --git a/src/test/codegen/some-global-nonnull.rs b/src/test/codegen/some-global-nonnull.rs
new file mode 100644
index 00000000000..59c47de4129
--- /dev/null
+++ b/src/test/codegen/some-global-nonnull.rs
@@ -0,0 +1,25 @@
+// compile-flags: -O
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @test
+// CHECK-NEXT: start:
+// CHECK-NEXT: tail call void @ext_fn0()
+#[no_mangle]
+pub fn test() {
+    test_inner(Some(inner0));
+}
+
+fn test_inner(f_maybe: Option<fn()>) {
+    if let Some(f) = f_maybe {
+        f();
+    }
+}
+
+fn inner0() {
+    unsafe { ext_fn0() };
+}
+
+extern "C" {
+    fn ext_fn0();
+}