[llvm] [WIP] Consider datalayout sentinel pointer value for isKnownNonZero check (PR #91769)

Rana Pratap Reddy via llvm-commits llvm-commits at lists.llvm.org
Fri May 17 02:34:26 PDT 2024


https://github.com/ranapratap55 updated https://github.com/llvm/llvm-project/pull/91769

>From 4351f1098dfeed06b050d505103100dd5ae4d48a Mon Sep 17 00:00:00 2001
From: Rana Pratap Reddy N <RanaPratapReddy.Nimmakayala at amd.com>
Date: Fri, 10 May 2024 20:12:54 +0530
Subject: [PATCH 1/2] [WIP] Consider datalayout sentinel pointer value for
 isKnownNonZero check

---
 llvm/lib/Analysis/ValueTracking.cpp           |    9 +
 .../ArgumentPromotion/array-dl-sentinel.ll    |   56 +
 .../IPConstantProp/pthreads-dl-sentinel.ll    |  122 +
 .../Attributor/callbacks-dl-sentinel.ll       |  321 ++
 .../Attributor/nocapture-2-dl-sentinel.ll     |  892 +++++
 .../Attributor/nofree-dl-sentinel.ll          |  516 +++
 ...rite_returned_arguments_scc-dl-sentinel.ll |  336 ++
 .../Attributor/returned-dl-sentinel.ll        | 1421 +++++++
 .../Attributor/value-simplify-dl-sentinel.ll  | 1732 +++++++++
 .../alloca-cast-debuginfo-dl-sentinel.ll      |   88 +
 .../alloca-in-non-alloca-as-sentinel.ll       |   65 +
 .../InstCombine/assume-dl-sentinel.ll         |  944 +++++
 .../assume-icmp-null-select-dl-sentinel.ll    |   37 +
 .../InstSimplify/compare-dl-sentinel.ll       | 3270 +++++++++++++++++
 .../InstSimplify/icmp-dl-sentinel.ll          |  414 +++
 .../null-ptr-is-valid-dl-sentinel.ll          |   23 +
 16 files changed, 10246 insertions(+)
 create mode 100755 llvm/test/Transforms/Attributor/ArgumentPromotion/array-dl-sentinel.ll
 create mode 100755 llvm/test/Transforms/Attributor/IPConstantProp/pthreads-dl-sentinel.ll
 create mode 100755 llvm/test/Transforms/Attributor/callbacks-dl-sentinel.ll
 create mode 100755 llvm/test/Transforms/Attributor/nocapture-2-dl-sentinel.ll
 create mode 100755 llvm/test/Transforms/Attributor/nofree-dl-sentinel.ll
 create mode 100755 llvm/test/Transforms/Attributor/read_write_returned_arguments_scc-dl-sentinel.ll
 create mode 100755 llvm/test/Transforms/Attributor/returned-dl-sentinel.ll
 create mode 100755 llvm/test/Transforms/Attributor/value-simplify-dl-sentinel.ll
 create mode 100755 llvm/test/Transforms/InstCombine/alloca-cast-debuginfo-dl-sentinel.ll
 create mode 100755 llvm/test/Transforms/InstCombine/alloca-in-non-alloca-as-sentinel.ll
 create mode 100755 llvm/test/Transforms/InstCombine/assume-dl-sentinel.ll
 create mode 100755 llvm/test/Transforms/InstCombine/assume-icmp-null-select-dl-sentinel.ll
 create mode 100755 llvm/test/Transforms/InstSimplify/compare-dl-sentinel.ll
 create mode 100755 llvm/test/Transforms/InstSimplify/icmp-dl-sentinel.ll
 create mode 100755 llvm/test/Transforms/InstSimplify/null-ptr-is-valid-dl-sentinel.ll

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 375385aca7a39..51ad01219c6e2 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -3098,6 +3098,15 @@ bool isKnownNonZero(const Value *V, const APInt &DemandedElts,
   // Check for pointer simplifications.
 
   if (PointerType *PtrTy = dyn_cast<PointerType>(Ty)) {
+    const DataLayout &DL = Q.DL;
+    if (DL.isSentinelValueDefined() && PtrTy) {
+      unsigned AddrSpace = PtrTy->getPointerAddressSpace();
+
+      if (DL.getSentinelPointerValue(AddrSpace) == 0)
+        return false;
+      return true;
+    }
+
     // A byval, inalloca may not be null in a non-default addres space. A
     // nonnull argument is assumed never 0.
     if (const Argument *A = dyn_cast<Argument>(V)) {
diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/array-dl-sentinel.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/array-dl-sentinel.ll
new file mode 100755
index 0000000000000..1f6ee8bbc348a
--- /dev/null
+++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/array-dl-sentinel.ll
@@ -0,0 +1,56 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
+target datalayout = "e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32-p7:160:256:256:32-p8:128:128-p9:192:256:256:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-z0:1-z2:neg1-z3:neg1-z5:neg1-S32-A5-G1-ni:7:8:9"
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal  -attributor-annotate-decl-cs  -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal  -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
+;
+; FIXME: The GEP + BC + GEP solution we create is not great but correct.
+
+declare void @use(ptr nocapture readonly %arg)
+
+define void @caller() {
+; TUNIT-LABEL: define {{[^@]+}}@caller() {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    [[LEFT:%.*]] = alloca [3 x i32], align 4
+; TUNIT-NEXT:    [[TMP0:%.*]] = load i32, ptr [[LEFT]], align 4
+; TUNIT-NEXT:    [[LEFT_B4:%.*]] = getelementptr i8, ptr [[LEFT]], i64 4
+; TUNIT-NEXT:    [[TMP1:%.*]] = load i32, ptr [[LEFT_B4]], align 4
+; TUNIT-NEXT:    [[LEFT_B8:%.*]] = getelementptr i8, ptr [[LEFT]], i64 8
+; TUNIT-NEXT:    [[TMP2:%.*]] = load i32, ptr [[LEFT_B8]], align 4
+; TUNIT-NEXT:    call void @callee(i32 [[TMP0]], i32 [[TMP1]], i32 [[TMP2]])
+; TUNIT-NEXT:    ret void
+;
+; CGSCC-LABEL: define {{[^@]+}}@caller() {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    call void @callee(i32 undef, i32 undef, i32 undef)
+; CGSCC-NEXT:    ret void
+;
+entry:
+  %left = alloca [3 x i32], align 4
+  call void @callee(ptr %left)
+  ret void
+}
+
+define internal void @callee(ptr noalias %arg) {
+; CHECK: Function Attrs: memory(readwrite, argmem: none)
+; CHECK-LABEL: define {{[^@]+}}@callee
+; CHECK-SAME: (i32 [[TMP0:%.*]], i32 [[TMP1:%.*]], i32 [[TMP2:%.*]]) #[[ATTR0:[0-9]+]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[ARG_PRIV:%.*]] = alloca [3 x i32], align 4, addrspace(5)
+; CHECK-NEXT:    store i32 [[TMP0]], ptr addrspace(5) [[ARG_PRIV]], align 4
+; CHECK-NEXT:    [[ARG_PRIV_B4:%.*]] = getelementptr i8, ptr addrspace(5) [[ARG_PRIV]], i64 4
+; CHECK-NEXT:    store i32 [[TMP1]], ptr addrspace(5) [[ARG_PRIV_B4]], align 4
+; CHECK-NEXT:    [[ARG_PRIV_B8:%.*]] = getelementptr i8, ptr addrspace(5) [[ARG_PRIV]], i64 8
+; CHECK-NEXT:    store i32 [[TMP2]], ptr addrspace(5) [[ARG_PRIV_B8]], align 4
+; CHECK-NEXT:    [[TMP3:%.*]] = addrspacecast ptr addrspace(5) [[ARG_PRIV]] to ptr
+; CHECK-NEXT:    call void @use(ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(12) [[TMP3]])
+; CHECK-NEXT:    ret void
+;
+entry:
+  call void @use(ptr %arg)
+  ret void
+}
+;.
+; TUNIT: attributes #[[ATTR0]] = { memory(readwrite, argmem: none) }
+;.
+; CGSCC: attributes #[[ATTR0]] = { memory(readwrite, argmem: none) }
+;.
diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/pthreads-dl-sentinel.ll b/llvm/test/Transforms/Attributor/IPConstantProp/pthreads-dl-sentinel.ll
new file mode 100755
index 0000000000000..b93017bd58986
--- /dev/null
+++ b/llvm/test/Transforms/Attributor/IPConstantProp/pthreads-dl-sentinel.ll
@@ -0,0 +1,122 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal  -attributor-annotate-decl-cs  -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal  -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
+;
+;    #include <pthread.h>
+;
+;    ptr GlobalVPtr;
+;
+;    static ptr foo(ptr arg) { return arg; }
+;    static ptr bar(ptr arg) { return arg; }
+;
+;    int main() {
+;      pthread_t thread;
+;      pthread_create(&thread, NULL, foo, NULL);
+;      pthread_create(&thread, NULL, bar, &GlobalVPtr);
+;      return 0;
+;    }
+;
+; Verify the constant values NULL and &GlobalVPtr are propagated into foo and
+; bar, respectively.
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-z0:1-z2:neg1-z3:neg1-z5:neg1-S128"
+
+%union.pthread_attr_t = type { i64, [48 x i8] }
+
+ at GlobalVPtr = common dso_local global ptr null, align 8
+
+; FIXME: nocapture & noalias for @GlobalVPtr in %call1
+; FIXME: nocapture & noalias for %alloc2 in %call3
+
+;.
+; CHECK: @GlobalVPtr = common dso_local global ptr null, align 8
+;.
+define dso_local i32 @main() {
+; TUNIT-LABEL: define {{[^@]+}}@main() {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    [[ALLOC11:%.*]] = alloca i8, i32 0, align 8
+; TUNIT-NEXT:    [[ALLOC22:%.*]] = alloca i8, i32 0, align 8
+; TUNIT-NEXT:    [[THREAD:%.*]] = alloca i64, align 8
+; TUNIT-NEXT:    [[CALL:%.*]] = call i32 @pthread_create(ptr noundef nonnull align 8 dereferenceable(8) [[THREAD]], ptr noundef align 4294967296 null, ptr noundef nonnull @foo, ptr nofree readnone align 4294967296 undef)
+; TUNIT-NEXT:    [[CALL1:%.*]] = call i32 @pthread_create(ptr noundef nonnull align 8 dereferenceable(8) [[THREAD]], ptr noundef align 4294967296 null, ptr noundef nonnull @bar, ptr noalias nocapture nofree nonnull readnone align 8 dereferenceable(8) undef)
+; TUNIT-NEXT:    [[CALL2:%.*]] = call i32 @pthread_create(ptr noundef nonnull align 8 dereferenceable(8) [[THREAD]], ptr noundef align 4294967296 null, ptr noundef nonnull @baz, ptr noalias nocapture nofree noundef nonnull readnone align 8 dereferenceable(1) [[ALLOC11]])
+; TUNIT-NEXT:    [[CALL3:%.*]] = call i32 @pthread_create(ptr noundef nonnull align 8 dereferenceable(8) [[THREAD]], ptr noundef align 4294967296 null, ptr noundef nonnull @buz, ptr noalias nofree noundef nonnull readnone align 8 dereferenceable(1) "no-capture-maybe-returned" [[ALLOC22]])
+; TUNIT-NEXT:    ret i32 0
+;
+; CGSCC-LABEL: define {{[^@]+}}@main() {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    [[ALLOC1:%.*]] = alloca i8, align 8
+; CGSCC-NEXT:    [[ALLOC2:%.*]] = alloca i8, align 8
+; CGSCC-NEXT:    [[THREAD:%.*]] = alloca i64, align 8
+; CGSCC-NEXT:    unreachable
+;
+entry:
+  %alloc1 = alloca i8, align 8
+  %alloc2 = alloca i8, align 8
+  %thread = alloca i64, align 8
+  %call = call i32 @pthread_create(ptr nonnull %thread, ptr null, ptr nonnull @foo, ptr null)
+  %call1 = call i32 @pthread_create(ptr nonnull %thread, ptr null, ptr nonnull @bar, ptr @GlobalVPtr)
+  %call2 = call i32 @pthread_create(ptr nonnull %thread, ptr null, ptr nonnull @baz, ptr nocapture %alloc1)
+  %call3 = call i32 @pthread_create(ptr nonnull %thread, ptr null, ptr nonnull @buz, ptr %alloc2)
+  ret i32 0
+}
+
+declare !callback !0 dso_local i32 @pthread_create(ptr, ptr, ptr, ptr)
+
+define internal ptr @foo(ptr %arg) {
+; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CHECK-LABEL: define {{[^@]+}}@foo
+; CHECK-SAME: (ptr noalias nocapture nofree nonnull readnone align 4294967296 [[ARG:%.*]]) #[[ATTR0:[0-9]+]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    unreachable
+;
+entry:
+  ret ptr %arg
+}
+
+define internal ptr @bar(ptr %arg) {
+; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CHECK-LABEL: define {{[^@]+}}@bar
+; CHECK-SAME: (ptr noalias nocapture nofree nonnull readnone align 8 dereferenceable(8) [[ARG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    ret ptr @GlobalVPtr
+;
+entry:
+  ret ptr %arg
+}
+
+define internal ptr @baz(ptr %arg) {
+; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CHECK-LABEL: define {{[^@]+}}@baz
+; CHECK-SAME: (ptr noalias nofree noundef nonnull readnone returned align 8 dereferenceable(1) "no-capture-maybe-returned" [[ARG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    ret ptr [[ARG]]
+;
+entry:
+  ret ptr %arg
+}
+
+define internal ptr @buz(ptr %arg) {
+; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CHECK-LABEL: define {{[^@]+}}@buz
+; CHECK-SAME: (ptr noalias nofree noundef nonnull readnone returned align 8 dereferenceable(1) "no-capture-maybe-returned" [[ARG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    ret ptr [[ARG]]
+;
+entry:
+  ret ptr %arg
+}
+
+!1 = !{i64 2, i64 3, i1 false}
+!0 = !{!1}
+;.
+; TUNIT: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
+;.
+; CGSCC: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
+;.
+; TUNIT: [[META0:![0-9]+]] = !{[[META1:![0-9]+]]}
+; TUNIT: [[META1]] = !{i64 2, i64 3, i1 false}
+;.
+; CGSCC: [[META0:![0-9]+]] = !{[[META1:![0-9]+]]}
+; CGSCC: [[META1]] = !{i64 2, i64 3, i1 false}
+;.
diff --git a/llvm/test/Transforms/Attributor/callbacks-dl-sentinel.ll b/llvm/test/Transforms/Attributor/callbacks-dl-sentinel.ll
new file mode 100755
index 0000000000000..1e66ba25f166a
--- /dev/null
+++ b/llvm/test/Transforms/Attributor/callbacks-dl-sentinel.ll
@@ -0,0 +1,321 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal  -attributor-annotate-decl-cs  -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal  -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
+
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-z0:1-z2:neg1-z3:neg1-z5:neg1-S128"
+
+; Test 0
+;
+; Make sure we propagate information from the caller to the callback callee but
+; only for arguments that are mapped through the callback metadata. Here, the
+; first two arguments of the call and the callback callee do not correspond to
+; each other but argument 3-5 of the transitive call site in the caller match
+; arguments 2-4 of the callback callee. Here we should see information and value
+; transfer in both directions.
+
+define void @t0_caller(ptr %a) {
+; TUNIT-LABEL: define {{[^@]+}}@t0_caller
+; TUNIT-SAME: (ptr nonnull align 256 [[A:%.*]]) {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    [[B:%.*]] = alloca i32, align 32
+; TUNIT-NEXT:    [[C:%.*]] = alloca ptr, align 64
+; TUNIT-NEXT:    [[PTR:%.*]] = alloca i32, align 128
+; TUNIT-NEXT:    store i32 42, ptr [[B]], align 32
+; TUNIT-NEXT:    store ptr [[B]], ptr [[C]], align 64
+; TUNIT-NEXT:    call void (ptr, ptr, ptr, ...) @t0_callback_broker(ptr noundef align 4294967296 null, ptr noundef nonnull align 128 dereferenceable(4) [[PTR]], ptr noundef nonnull @t0_callback_callee, ptr nonnull align 256 [[A]], i64 undef, ptr noalias nocapture nofree noundef nonnull readonly align 64 dereferenceable(8) [[C]])
+; TUNIT-NEXT:    ret void
+;
+; CGSCC-LABEL: define {{[^@]+}}@t0_caller
+; CGSCC-SAME: (ptr nonnull align 256 [[A:%.*]]) {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    [[B:%.*]] = alloca i32, align 32
+; CGSCC-NEXT:    [[C:%.*]] = alloca ptr, align 64
+; CGSCC-NEXT:    [[PTR:%.*]] = alloca i32, align 128
+; CGSCC-NEXT:    store i32 42, ptr [[B]], align 32
+; CGSCC-NEXT:    store ptr [[B]], ptr [[C]], align 64
+; CGSCC-NEXT:    call void (ptr, ptr, ptr, ...) @t0_callback_broker(ptr noundef align 4294967296 null, ptr noundef nonnull align 128 dereferenceable(4) [[PTR]], ptr noundef nonnull @t0_callback_callee, ptr nonnull align 256 [[A]], i64 noundef 99, ptr noalias nocapture nofree noundef nonnull readonly align 64 dereferenceable(8) [[C]])
+; CGSCC-NEXT:    ret void
+;
+entry:
+  %b = alloca i32, align 32
+  %c = alloca ptr, align 64
+  %ptr = alloca i32, align 128
+  store i32 42, ptr %b, align 4
+  store ptr %b, ptr %c, align 8
+  call void (ptr, ptr, ptr, ...) @t0_callback_broker(ptr null, ptr %ptr, ptr @t0_callback_callee, ptr %a, i64 99, ptr %c)
+  ret void
+}
+
+; Note that the first two arguments are provided by the callback_broker according to the callback in !1 below!
+; The others are annotated with alignment information, amongst others, or even replaced by the constants passed to the call.
+define internal void @t0_callback_callee(ptr %is_not_null, ptr %ptr, ptr %a, i64 %b, ptr %c) {
+;
+; TUNIT-LABEL: define {{[^@]+}}@t0_callback_callee
+; TUNIT-SAME: (ptr nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], ptr nocapture nofree noundef nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], ptr nonnull align 256 [[A:%.*]], i64 [[B:%.*]], ptr noalias nocapture nofree noundef nonnull readonly align 64 dereferenceable(8) [[C:%.*]]) {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    [[PTR_VAL:%.*]] = load i32, ptr [[PTR]], align 8
+; TUNIT-NEXT:    store i32 [[PTR_VAL]], ptr [[IS_NOT_NULL]], align 4
+; TUNIT-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[C]], align 64
+; TUNIT-NEXT:    tail call void @t0_check(ptr nonnull align 256 [[A]], i64 noundef 99, ptr nonnull align 32 [[TMP0]])
+; TUNIT-NEXT:    ret void
+;
+; CGSCC-LABEL: define {{[^@]+}}@t0_callback_callee
+; CGSCC-SAME: (ptr nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], ptr nocapture nofree noundef nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], ptr nonnull align 256 [[A:%.*]], i64 [[B:%.*]], ptr noalias nocapture nofree noundef nonnull readonly align 64 dereferenceable(8) [[C:%.*]]) {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    [[PTR_VAL:%.*]] = load i32, ptr [[PTR]], align 8
+; CGSCC-NEXT:    store i32 [[PTR_VAL]], ptr [[IS_NOT_NULL]], align 4
+; CGSCC-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[C]], align 64
+; CGSCC-NEXT:    tail call void @t0_check(ptr nonnull align 256 [[A]], i64 noundef 99, ptr nonnull [[TMP0]])
+; CGSCC-NEXT:    ret void
+;
+entry:
+  %ptr_val = load i32, ptr %ptr, align 8
+  store i32 %ptr_val, ptr %is_not_null
+  %0 = load ptr, ptr %c, align 8
+  tail call void @t0_check(ptr %a, i64 %b, ptr %0)
+  ret void
+}
+
+declare void @t0_check(ptr align 256, i64, ptr)
+
+declare !callback !0 void @t0_callback_broker(ptr, ptr, ptr, ...)
+
+; Test 1
+;
+; Similar to test 0 but with some additional annotations (noalias/nocapute) to make sure
+; we deduce and propagate noalias and others properly.
+
+define void @t1_caller(ptr noalias %a) {
+;
+; TUNIT-LABEL: define {{[^@]+}}@t1_caller
+; TUNIT-SAME: (ptr noalias nocapture nonnull align 256 [[A:%.*]]) {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    [[B:%.*]] = alloca i32, align 32
+; TUNIT-NEXT:    [[C:%.*]] = alloca ptr, align 64
+; TUNIT-NEXT:    [[PTR:%.*]] = alloca i32, align 128
+; TUNIT-NEXT:    store i32 42, ptr [[B]], align 32
+; TUNIT-NEXT:    store ptr [[B]], ptr [[C]], align 64
+; TUNIT-NEXT:    call void (ptr, ptr, ptr, ...) @t1_callback_broker(ptr noundef align 4294967296 null, ptr noalias nocapture noundef nonnull align 128 dereferenceable(4) [[PTR]], ptr nocapture noundef nonnull @t1_callback_callee, ptr nocapture nonnull align 256 [[A]], i64 undef, ptr noalias nocapture nofree noundef nonnull readonly align 64 dereferenceable(8) [[C]])
+; TUNIT-NEXT:    ret void
+;
+; CGSCC-LABEL: define {{[^@]+}}@t1_caller
+; CGSCC-SAME: (ptr noalias nocapture nonnull align 256 [[A:%.*]]) {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    [[B:%.*]] = alloca i32, align 32
+; CGSCC-NEXT:    [[C:%.*]] = alloca ptr, align 64
+; CGSCC-NEXT:    [[PTR:%.*]] = alloca i32, align 128
+; CGSCC-NEXT:    store i32 42, ptr [[B]], align 32
+; CGSCC-NEXT:    store ptr [[B]], ptr [[C]], align 64
+; CGSCC-NEXT:    call void (ptr, ptr, ptr, ...) @t1_callback_broker(ptr noundef align 4294967296 null, ptr noalias nocapture noundef nonnull align 128 dereferenceable(4) [[PTR]], ptr nocapture noundef nonnull @t1_callback_callee, ptr nocapture nonnull align 256 [[A]], i64 noundef 99, ptr noalias nocapture nofree noundef nonnull readonly align 64 dereferenceable(8) [[C]])
+; CGSCC-NEXT:    ret void
+;
+entry:
+  %b = alloca i32, align 32
+  %c = alloca ptr, align 64
+  %ptr = alloca i32, align 128
+  store i32 42, ptr %b, align 4
+  store ptr %b, ptr %c, align 8
+  call void (ptr, ptr, ptr, ...) @t1_callback_broker(ptr null, ptr %ptr, ptr @t1_callback_callee, ptr %a, i64 99, ptr %c)
+  ret void
+}
+
+; Note that the first two arguments are provided by the callback_broker according to the callback in !1 below!
+; The others are annotated with alignment information, amongst others, or even replaced by the constants passed to the call.
+define internal void @t1_callback_callee(ptr %is_not_null, ptr %ptr, ptr %a, i64 %b, ptr %c) {
+;
+; TUNIT: Function Attrs: nosync
+; TUNIT-LABEL: define {{[^@]+}}@t1_callback_callee
+; TUNIT-SAME: (ptr nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], ptr nocapture nofree noundef nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], ptr nocapture nonnull align 256 [[A:%.*]], i64 [[B:%.*]], ptr noalias nocapture nofree noundef nonnull readonly align 64 dereferenceable(8) [[C:%.*]]) #[[ATTR0:[0-9]+]] {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    [[PTR_VAL:%.*]] = load i32, ptr [[PTR]], align 8
+; TUNIT-NEXT:    store i32 [[PTR_VAL]], ptr [[IS_NOT_NULL]], align 4
+; TUNIT-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[C]], align 64
+; TUNIT-NEXT:    tail call void @t1_check(ptr nocapture nonnull align 256 [[A]], i64 noundef 99, ptr nocapture nonnull align 32 [[TMP0]])
+; TUNIT-NEXT:    ret void
+;
+; CGSCC: Function Attrs: nosync
+; CGSCC-LABEL: define {{[^@]+}}@t1_callback_callee
+; CGSCC-SAME: (ptr nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], ptr nocapture nofree noundef nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], ptr nocapture nonnull align 256 [[A:%.*]], i64 [[B:%.*]], ptr noalias nocapture nofree noundef nonnull readonly align 64 dereferenceable(8) [[C:%.*]]) #[[ATTR0:[0-9]+]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    [[PTR_VAL:%.*]] = load i32, ptr [[PTR]], align 8
+; CGSCC-NEXT:    store i32 [[PTR_VAL]], ptr [[IS_NOT_NULL]], align 4
+; CGSCC-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[C]], align 64
+; CGSCC-NEXT:    tail call void @t1_check(ptr nocapture nonnull align 256 [[A]], i64 noundef 99, ptr nocapture nonnull [[TMP0]])
+; CGSCC-NEXT:    ret void
+;
+entry:
+  %ptr_val = load i32, ptr %ptr, align 8
+  store i32 %ptr_val, ptr %is_not_null
+  %0 = load ptr, ptr %c, align 8
+  tail call void @t1_check(ptr %a, i64 %b, ptr %0)
+  ret void
+}
+
+declare void @t1_check(ptr nocapture align 256, i64, ptr nocapture) nosync
+
+declare !callback !0 void @t1_callback_broker(ptr nocapture , ptr nocapture , ptr nocapture, ...)
+
+; Test 2
+;
+; Similar to test 1 but checking that the noalias is only placed if potential synchronization through @t2_check is preserved.
+
+define void @t2_caller(ptr noalias %a) {
+; TUNIT-LABEL: define {{[^@]+}}@t2_caller
+; TUNIT-SAME: (ptr noalias nocapture nonnull align 256 [[A:%.*]]) {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    [[B:%.*]] = alloca i32, align 32
+; TUNIT-NEXT:    [[C:%.*]] = alloca ptr, align 64
+; TUNIT-NEXT:    [[PTR:%.*]] = alloca i32, align 128
+; TUNIT-NEXT:    store i32 42, ptr [[B]], align 32
+; TUNIT-NEXT:    store ptr [[B]], ptr [[C]], align 64
+; TUNIT-NEXT:    call void (ptr, ptr, ptr, ...) @t2_callback_broker(ptr noundef align 4294967296 null, ptr noalias nocapture noundef nonnull align 128 dereferenceable(4) [[PTR]], ptr nocapture noundef nonnull @t2_callback_callee, ptr nocapture nonnull align 256 [[A]], i64 undef, ptr noalias nocapture nofree noundef nonnull readonly align 64 dereferenceable(8) [[C]])
+; TUNIT-NEXT:    ret void
+;
+; CGSCC-LABEL: define {{[^@]+}}@t2_caller
+; CGSCC-SAME: (ptr noalias nocapture nonnull align 256 [[A:%.*]]) {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    [[B:%.*]] = alloca i32, align 32
+; CGSCC-NEXT:    [[C:%.*]] = alloca ptr, align 64
+; CGSCC-NEXT:    [[PTR:%.*]] = alloca i32, align 128
+; CGSCC-NEXT:    store i32 42, ptr [[B]], align 32
+; CGSCC-NEXT:    store ptr [[B]], ptr [[C]], align 64
+; CGSCC-NEXT:    call void (ptr, ptr, ptr, ...) @t2_callback_broker(ptr noundef align 4294967296 null, ptr noalias nocapture noundef nonnull align 128 dereferenceable(4) [[PTR]], ptr nocapture noundef nonnull @t2_callback_callee, ptr nocapture nonnull align 256 [[A]], i64 noundef 99, ptr noalias nocapture nofree noundef nonnull readonly align 64 dereferenceable(8) [[C]])
+; CGSCC-NEXT:    ret void
+;
+entry:
+  %b = alloca i32, align 32
+  %c = alloca ptr, align 64
+  %ptr = alloca i32, align 128
+  store i32 42, ptr %b, align 4
+  store ptr %b, ptr %c, align 8
+  call void (ptr, ptr, ptr, ...) @t2_callback_broker(ptr null, ptr %ptr, ptr @t2_callback_callee, ptr %a, i64 99, ptr %c)
+  ret void
+}
+
+; Note that the first two arguments are provided by the callback_broker according to the callback in !1 below!
+; The others are annotated with alignment information, amongst others, or even replaced by the constants passed to the call.
+;
+; FIXME: We should derive noalias for %a and add a "fake use" of %a in all potentially synchronizing calls.
+define internal void @t2_callback_callee(ptr %is_not_null, ptr %ptr, ptr %a, i64 %b, ptr %c) {
+;
+; TUNIT-LABEL: define {{[^@]+}}@t2_callback_callee
+; TUNIT-SAME: (ptr nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], ptr nocapture nofree noundef nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], ptr nocapture nonnull align 256 [[A:%.*]], i64 [[B:%.*]], ptr noalias nocapture nofree noundef nonnull readonly align 64 dereferenceable(8) [[C:%.*]]) {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    [[PTR_VAL:%.*]] = load i32, ptr [[PTR]], align 8
+; TUNIT-NEXT:    store i32 [[PTR_VAL]], ptr [[IS_NOT_NULL]], align 4
+; TUNIT-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[C]], align 64
+; TUNIT-NEXT:    tail call void @t2_check(ptr nocapture nonnull align 256 [[A]], i64 noundef 99, ptr nocapture nonnull align 32 [[TMP0]])
+; TUNIT-NEXT:    ret void
+;
+; CGSCC-LABEL: define {{[^@]+}}@t2_callback_callee
+; CGSCC-SAME: (ptr nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], ptr nocapture nofree noundef nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], ptr nocapture nonnull align 256 [[A:%.*]], i64 [[B:%.*]], ptr noalias nocapture nofree noundef nonnull readonly align 64 dereferenceable(8) [[C:%.*]]) {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    [[PTR_VAL:%.*]] = load i32, ptr [[PTR]], align 8
+; CGSCC-NEXT:    store i32 [[PTR_VAL]], ptr [[IS_NOT_NULL]], align 4
+; CGSCC-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[C]], align 64
+; CGSCC-NEXT:    tail call void @t2_check(ptr nocapture nonnull align 256 [[A]], i64 noundef 99, ptr nocapture nonnull [[TMP0]])
+; CGSCC-NEXT:    ret void
+;
+entry:
+  %ptr_val = load i32, ptr %ptr, align 8
+  store i32 %ptr_val, ptr %is_not_null
+  %0 = load ptr, ptr %c, align 8
+  tail call void @t2_check(ptr %a, i64 %b, ptr %0)
+  ret void
+}
+
+declare void @t2_check(ptr nocapture align 256, i64, ptr nocapture)
+
+declare !callback !0 void @t2_callback_broker(ptr nocapture , ptr nocapture , ptr nocapture, ...)
+
+; Test 3
+;
+; Basically test 2 with the casted callback callee used twice.
+
+define void @t3_caller(ptr noalias %a) {
+; TUNIT-LABEL: define {{[^@]+}}@t3_caller
+; TUNIT-SAME: (ptr noalias nocapture nonnull align 256 [[A:%.*]]) {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    [[B:%.*]] = alloca i32, align 32
+; TUNIT-NEXT:    [[C:%.*]] = alloca ptr, align 64
+; TUNIT-NEXT:    [[PTR:%.*]] = alloca i32, align 128
+; TUNIT-NEXT:    store i32 42, ptr [[B]], align 32
+; TUNIT-NEXT:    store ptr [[B]], ptr [[C]], align 64
+; TUNIT-NEXT:    call void (ptr, ptr, ptr, ...) @t3_callback_broker(ptr noundef align 4294967296 null, ptr noalias nocapture noundef nonnull align 128 dereferenceable(4) [[PTR]], ptr nocapture noundef nonnull @t3_callback_callee, ptr nocapture nonnull align 256 [[A]], i64 undef, ptr noalias nocapture nofree noundef nonnull readonly align 64 dereferenceable(8) [[C]])
+; TUNIT-NEXT:    call void (ptr, ptr, ptr, ...) @t3_callback_broker(ptr noundef align 4294967296 null, ptr noalias nocapture noundef nonnull align 128 dereferenceable(4) [[PTR]], ptr nocapture noundef nonnull @t3_callback_callee, ptr nocapture nonnull align 256 [[A]], i64 undef, ptr noalias nocapture nofree noundef nonnull readonly align 64 dereferenceable(8) [[C]])
+; TUNIT-NEXT:    ret void
+;
+; CGSCC-LABEL: define {{[^@]+}}@t3_caller
+; CGSCC-SAME: (ptr noalias nocapture nonnull align 256 [[A:%.*]]) {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    [[B:%.*]] = alloca i32, align 32
+; CGSCC-NEXT:    [[C:%.*]] = alloca ptr, align 64
+; CGSCC-NEXT:    [[PTR:%.*]] = alloca i32, align 128
+; CGSCC-NEXT:    store i32 42, ptr [[B]], align 32
+; CGSCC-NEXT:    store ptr [[B]], ptr [[C]], align 64
+; CGSCC-NEXT:    call void (ptr, ptr, ptr, ...) @t3_callback_broker(ptr noundef align 4294967296 null, ptr noalias nocapture noundef nonnull align 128 dereferenceable(4) [[PTR]], ptr nocapture noundef nonnull @t3_callback_callee, ptr nocapture nonnull align 256 [[A]], i64 noundef 99, ptr noalias nocapture nofree noundef nonnull readonly align 64 dereferenceable(8) [[C]])
+; CGSCC-NEXT:    call void (ptr, ptr, ptr, ...) @t3_callback_broker(ptr noundef align 4294967296 null, ptr noalias nocapture noundef nonnull align 128 dereferenceable(4) [[PTR]], ptr nocapture noundef nonnull @t3_callback_callee, ptr nocapture nonnull align 256 [[A]], i64 noundef 99, ptr noalias nocapture nofree noundef nonnull readonly align 64 dereferenceable(8) [[C]])
+; CGSCC-NEXT:    ret void
+;
+entry:
+  %b = alloca i32, align 32
+  %c = alloca ptr, align 64
+  %ptr = alloca i32, align 128
+  store i32 42, ptr %b, align 4
+  store ptr %b, ptr %c, align 8
+  call void (ptr, ptr, ptr, ...) @t3_callback_broker(ptr null, ptr %ptr, ptr @t3_callback_callee, ptr %a, i64 99, ptr %c)
+  call void (ptr, ptr, ptr, ...) @t3_callback_broker(ptr null, ptr %ptr, ptr @t3_callback_callee, ptr %a, i64 99, ptr %c)
+  ret void
+}
+
+; Note that the first two arguments are provided by the callback_broker according to the callback in !1 below!
+; The others are annotated with alignment information, amongst others, or even replaced by the constants passed to the call.
+;
+; FIXME: We should derive noalias for %a and add a "fake use" of %a in all potentially synchronizing calls.
+define internal void @t3_callback_callee(ptr %is_not_null, ptr %ptr, ptr %a, i64 %b, ptr %c) {
+;
+; TUNIT-LABEL: define {{[^@]+}}@t3_callback_callee
+; TUNIT-SAME: (ptr nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], ptr nocapture nofree noundef nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], ptr nocapture nonnull align 256 [[A:%.*]], i64 [[B:%.*]], ptr noalias nocapture nofree noundef nonnull readonly align 64 dereferenceable(8) [[C:%.*]]) {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    [[PTR_VAL:%.*]] = load i32, ptr [[PTR]], align 8
+; TUNIT-NEXT:    store i32 [[PTR_VAL]], ptr [[IS_NOT_NULL]], align 4
+; TUNIT-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[C]], align 64
+; TUNIT-NEXT:    tail call void @t3_check(ptr nocapture nonnull align 256 [[A]], i64 noundef 99, ptr nocapture nonnull align 32 [[TMP0]])
+; TUNIT-NEXT:    ret void
+;
+; CGSCC-LABEL: define {{[^@]+}}@t3_callback_callee
+; CGSCC-SAME: (ptr nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], ptr nocapture nofree noundef nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], ptr nocapture nonnull align 256 [[A:%.*]], i64 [[B:%.*]], ptr noalias nocapture nofree noundef nonnull readonly align 64 dereferenceable(8) [[C:%.*]]) {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    [[PTR_VAL:%.*]] = load i32, ptr [[PTR]], align 8
+; CGSCC-NEXT:    store i32 [[PTR_VAL]], ptr [[IS_NOT_NULL]], align 4
+; CGSCC-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[C]], align 64
+; CGSCC-NEXT:    tail call void @t3_check(ptr nocapture nonnull align 256 [[A]], i64 noundef 99, ptr nocapture nonnull [[TMP0]])
+; CGSCC-NEXT:    ret void
+;
+entry:
+  %ptr_val = load i32, ptr %ptr, align 8
+  store i32 %ptr_val, ptr %is_not_null
+  %0 = load ptr, ptr %c, align 8
+  tail call void @t3_check(ptr %a, i64 %b, ptr %0)
+  ret void
+}
+
+declare void @t3_check(ptr nocapture align 256, i64, ptr nocapture)
+
+declare !callback !0 void @t3_callback_broker(ptr nocapture , ptr nocapture , ptr nocapture, ...)
+
+!0 = !{!1}
+!1 = !{i64 2, i64 -1, i64 -1, i1 true}
+;.
+; TUNIT: attributes #[[ATTR0]] = { nosync }
+;.
+; CGSCC: attributes #[[ATTR0]] = { nosync }
+;.
+; TUNIT: [[META0:![0-9]+]] = !{[[META1:![0-9]+]]}
+; TUNIT: [[META1]] = !{i64 2, i64 -1, i64 -1, i1 true}
+;.
+; CGSCC: [[META0:![0-9]+]] = !{[[META1:![0-9]+]]}
+; CGSCC: [[META1]] = !{i64 2, i64 -1, i64 -1, i1 true}
+;.
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK: {{.*}}
diff --git a/llvm/test/Transforms/Attributor/nocapture-2-dl-sentinel.ll b/llvm/test/Transforms/Attributor/nocapture-2-dl-sentinel.ll
new file mode 100755
index 0000000000000..cb9ab54b6da7c
--- /dev/null
+++ b/llvm/test/Transforms/Attributor/nocapture-2-dl-sentinel.ll
@@ -0,0 +1,892 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-attributes --check-globals --version 2
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal  -attributor-annotate-decl-cs  -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal  -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
+;
+; Test cases specifically designed for the "no-capture" argument attribute.
+; We use FIXME's to indicate problems and missing attributes.
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-z0:1-z2:neg1-z3:neg1-z5:neg1-S128"
+declare ptr @unknown()
+
+; TEST comparison against NULL
+;
+; int is_null_return(int *p) {
+;   return p == 0;
+; }
+;
+; no-capture is missing on %p because it is not dereferenceable
+define i32 @is_null_return(ptr %p) #0 {
+; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
+; CHECK-LABEL: define noundef i32 @is_null_return
+; CHECK-SAME: (ptr nocapture nofree nonnull readnone [[P:%.*]]) #[[ATTR0:[0-9]+]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    ret i32 0
+;
+entry:
+  %cmp = icmp eq ptr %p, null
+  %conv = zext i1 %cmp to i32
+  ret i32 %conv
+}
+
+; TEST comparison against NULL in control flow
+;
+; int is_null_control(int *p) {
+;   if (p == 0)
+;     return 1;
+;   if (0 == p)
+;     return 1;
+;   return 0;
+; }
+;
+; no-capture is missing on %p because it is not dereferenceable
+define i32 @is_null_control(ptr %p) #0 {
+; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
+; CHECK-LABEL: define i32 @is_null_control
+; CHECK-SAME: (ptr nocapture nofree nonnull readnone [[P:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[RETVAL:%.*]] = alloca i32, align 4
+; CHECK-NEXT:    br label [[IF_END:%.*]]
+; CHECK:       if.then:
+; CHECK-NEXT:    unreachable
+; CHECK:       if.end:
+; CHECK-NEXT:    br label [[IF_END3:%.*]]
+; CHECK:       if.then2:
+; CHECK-NEXT:    unreachable
+; CHECK:       if.end3:
+; CHECK-NEXT:    br label [[RETURN:%.*]]
+; CHECK:       return:
+; CHECK-NEXT:    ret i32 0
+;
+entry:
+  %retval = alloca i32, align 4
+  %cmp = icmp eq ptr %p, null
+  br i1 %cmp, label %if.then, label %if.end
+
+if.then:                                          ; preds = %entry
+  store i32 1, ptr %retval, align 4
+  br label %return
+
+if.end:                                           ; preds = %entry
+  %cmp1 = icmp eq ptr null, %p
+  br i1 %cmp1, label %if.then2, label %if.end3
+
+if.then2:                                         ; preds = %if.end
+  store i32 1, ptr %retval, align 4
+  br label %return
+
+if.end3:                                          ; preds = %if.end
+  store i32 0, ptr %retval, align 4
+  br label %return
+
+return:                                           ; preds = %if.end3, %if.then2, %if.then
+  %0 = load i32, ptr %retval, align 4
+  ret i32 %0
+}
+
+; TEST singleton SCC
+;
+; double *srec0(double *a) {
+;   srec0(a);
+;   return 0;
+; }
+;
+define ptr @srec0(ptr %a) #0 {
+; CHECK: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable
+; CHECK-LABEL: define noalias noundef align 4294967296 ptr @srec0
+; CHECK-SAME: (ptr nocapture nofree nonnull readnone [[A:%.*]]) #[[ATTR1:[0-9]+]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    ret ptr null
+;
+entry:
+  %call = call ptr @srec0(ptr %a)
+  ret ptr null
+}
+
+; TEST singleton SCC with lots of nested recursive calls
+;
+; int* srec16(int* a) {
+;   return srec16(srec16(srec16(srec16(
+;          srec16(srec16(srec16(srec16(
+;          srec16(srec16(srec16(srec16(
+;          srec16(srec16(srec16(srec16(
+;                        a
+;          ))))))))))))))));
+; }
+;
+; Other arguments are possible here due to the no-return behavior.
+;
+define ptr @srec16(ptr %a) #0 {
+; CHECK: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable
+; CHECK-LABEL: define noalias nonnull align 4294967296 dereferenceable(4294967295) ptr @srec16
+; CHECK-SAME: (ptr nocapture nofree nonnull readnone [[A:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    ret ptr undef
+;
+entry:
+  %call = call ptr @srec16(ptr %a)
+  %call1 = call ptr @srec16(ptr %call)
+  %call2 = call ptr @srec16(ptr %call1)
+  %call3 = call ptr @srec16(ptr %call2)
+  %call4 = call ptr @srec16(ptr %call3)
+  %call5 = call ptr @srec16(ptr %call4)
+  %call6 = call ptr @srec16(ptr %call5)
+  %call7 = call ptr @srec16(ptr %call6)
+  %call8 = call ptr @srec16(ptr %call7)
+  %call9 = call ptr @srec16(ptr %call8)
+  %call10 = call ptr @srec16(ptr %call9)
+  %call11 = call ptr @srec16(ptr %call10)
+  %call12 = call ptr @srec16(ptr %call11)
+  %call13 = call ptr @srec16(ptr %call12)
+  %call14 = call ptr @srec16(ptr %call13)
+  %call15 = call ptr @srec16(ptr %call14)
+  ret ptr %call15
+}
+
+; TEST SCC with various calls, casts, and comparisons agains NULL
+;
+; float *scc_A(int *a) {
+;   return (float*)(a ? (int*)scc_A((int*)scc_B((double*)scc_C((short*)a))) : a);
+; }
+;
+; long *scc_B(double *a) {
+;   return (long*)(a ? scc_C((short*)scc_B((double*)scc_A((int*)a))) : a);
+; }
+;
+; void *scc_C(short *a) {
+;   return scc_A((int*)(scc_A(a) ? scc_B((double*)a) : scc_C(a)));
+; }
+define ptr @scc_A(ptr dereferenceable_or_null(4) %a) {
+; CHECK: Function Attrs: mustprogress nofree noreturn nosync nounwind willreturn memory(none)
+; CHECK-LABEL: define noalias nonnull align 4294967296 dereferenceable(4294967295) ptr @scc_A
+; CHECK-SAME: (ptr nocapture nofree nonnull readnone dereferenceable(4) [[A:%.*]]) #[[ATTR2:[0-9]+]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[COND_TRUE:%.*]]
+; CHECK:       cond.true:
+; CHECK-NEXT:    unreachable
+; CHECK:       cond.false:
+; CHECK-NEXT:    unreachable
+; CHECK:       cond.end:
+; CHECK-NEXT:    unreachable
+;
+entry:
+  %tobool = icmp ne ptr %a, null
+  br i1 %tobool, label %cond.true, label %cond.false
+
+cond.true:                                        ; preds = %entry
+  %call = call ptr @scc_C(ptr %a)
+  %call1 = call ptr @scc_B(ptr %call)
+  %call2 = call ptr @scc_A(ptr %call1)
+  br label %cond.end
+
+cond.false:                                       ; preds = %entry
+  br label %cond.end
+
+cond.end:                                         ; preds = %cond.false, %cond.true
+  %cond = phi ptr [ %call2, %cond.true ], [ %a, %cond.false ]
+  ret ptr %cond
+}
+
+; FIXME: the call1 below to scc_B should return dereferenceable_or_null(8) (as the callee does). Something prevented that deduction and needs to be investigated.
+define ptr @scc_B(ptr dereferenceable_or_null(8) %a) {
+; TUNIT: Function Attrs: mustprogress nofree noreturn nosync nounwind willreturn memory(none)
+; TUNIT-LABEL: define noalias nonnull align 4294967296 dereferenceable(4294967295) ptr @scc_B
+; TUNIT-SAME: (ptr nocapture nofree nonnull readnone dereferenceable(8) [[A:%.*]]) #[[ATTR2]] {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    br label [[COND_TRUE:%.*]]
+; TUNIT:       cond.true:
+; TUNIT-NEXT:    unreachable
+; TUNIT:       cond.false:
+; TUNIT-NEXT:    unreachable
+; TUNIT:       cond.end:
+; TUNIT-NEXT:    unreachable
+;
+; CGSCC: Function Attrs: mustprogress nofree norecurse noreturn nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define noalias nonnull align 4294967296 dereferenceable(4294967295) ptr @scc_B
+; CGSCC-SAME: (ptr nocapture nofree noundef nonnull readnone dereferenceable(8) [[A:%.*]]) #[[ATTR3:[0-9]+]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    br label [[COND_TRUE:%.*]]
+; CGSCC:       cond.true:
+; CGSCC-NEXT:    unreachable
+; CGSCC:       cond.false:
+; CGSCC-NEXT:    unreachable
+; CGSCC:       cond.end:
+; CGSCC-NEXT:    unreachable
+;
+entry:
+  %tobool = icmp ne ptr %a, null
+  br i1 %tobool, label %cond.true, label %cond.false
+
+cond.true:                                        ; preds = %entry
+  %call = call ptr @scc_A(ptr %a)
+  %call1 = call ptr @scc_B(ptr %call)
+  %call2 = call ptr @scc_C(ptr %call1)
+  br label %cond.end
+
+cond.false:                                       ; preds = %entry
+  br label %cond.end
+
+cond.end:                                         ; preds = %cond.false, %cond.true
+  %cond = phi ptr [ %call2, %cond.true ], [ %a, %cond.false ]
+  ret ptr %cond
+}
+
+define ptr @scc_C(ptr dereferenceable_or_null(2) %a) {
+; TUNIT: Function Attrs: mustprogress nofree noreturn nosync nounwind willreturn memory(none)
+; TUNIT-LABEL: define noalias nonnull align 4294967296 dereferenceable(4294967295) ptr @scc_C
+; TUNIT-SAME: (ptr nocapture nofree nonnull readnone dereferenceable(4) [[A:%.*]]) #[[ATTR2]] {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    unreachable
+; TUNIT:       cond.true:
+; TUNIT-NEXT:    unreachable
+; TUNIT:       cond.false:
+; TUNIT-NEXT:    unreachable
+; TUNIT:       cond.end:
+; TUNIT-NEXT:    unreachable
+;
+; CGSCC: Function Attrs: mustprogress nofree norecurse noreturn nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define noalias nonnull align 4294967296 dereferenceable(4294967295) ptr @scc_C
+; CGSCC-SAME: (ptr nocapture nofree noundef nonnull readnone dereferenceable(4) [[A:%.*]]) #[[ATTR3]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    unreachable
+; CGSCC:       cond.true:
+; CGSCC-NEXT:    unreachable
+; CGSCC:       cond.false:
+; CGSCC-NEXT:    unreachable
+; CGSCC:       cond.end:
+; CGSCC-NEXT:    unreachable
+;
+entry:
+  %call = call ptr @scc_A(ptr %a)
+  %tobool = icmp ne ptr %call, null
+  br i1 %tobool, label %cond.true, label %cond.false
+
+cond.true:                                        ; preds = %entry
+  %call1 = call ptr @scc_B(ptr %a)
+  br label %cond.end
+
+cond.false:                                       ; preds = %entry
+  %call2 = call ptr @scc_C(ptr %a)
+  br label %cond.end
+
+cond.end:                                         ; preds = %cond.false, %cond.true
+  %cond = phi ptr [ %call1, %cond.true ], [ %call2, %cond.false ]
+  %call3 = call ptr @scc_A(ptr %cond)
+  ret ptr %call3
+}
+
+
+; TEST call to external function, marked no-capture
+;
+; void external_no_capture(int /* no-capture */ *p);
+; void test_external_no_capture(int *p) {
+;   external_no_capture(p);
+; }
+;
+declare void @external_no_capture(ptr nocapture)
+
+define void @test_external_no_capture(ptr %p) #0 {
+; TUNIT: Function Attrs: noinline nounwind uwtable
+; TUNIT-LABEL: define void @test_external_no_capture
+; TUNIT-SAME: (ptr nocapture nonnull [[P:%.*]]) #[[ATTR3:[0-9]+]] {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    call void @external_no_capture(ptr nocapture nonnull [[P]])
+; TUNIT-NEXT:    ret void
+;
+; CGSCC: Function Attrs: noinline nounwind uwtable
+; CGSCC-LABEL: define void @test_external_no_capture
+; CGSCC-SAME: (ptr nocapture nonnull [[P:%.*]]) #[[ATTR4:[0-9]+]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    call void @external_no_capture(ptr nocapture nonnull [[P]])
+; CGSCC-NEXT:    ret void
+;
+entry:
+  call void @external_no_capture(ptr %p)
+  ret void
+}
+
+; TEST call to external var-args function, marked no-capture
+;
+; void test_var_arg_call(char *p, int a) {
+;   printf(p, a);
+; }
+;
+define void @test_var_arg_call(ptr %p, i32 %a) #0 {
+; TUNIT: Function Attrs: noinline nounwind uwtable
+; TUNIT-LABEL: define void @test_var_arg_call
+; TUNIT-SAME: (ptr nocapture nonnull [[P:%.*]], i32 [[A:%.*]]) #[[ATTR3]] {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    [[CALL:%.*]] = call i32 (ptr, ...) @printf(ptr nocapture nonnull [[P]], i32 [[A]])
+; TUNIT-NEXT:    ret void
+;
+; CGSCC: Function Attrs: noinline nounwind uwtable
+; CGSCC-LABEL: define void @test_var_arg_call
+; CGSCC-SAME: (ptr nocapture nonnull [[P:%.*]], i32 [[A:%.*]]) #[[ATTR4]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    [[CALL:%.*]] = call i32 (ptr, ...) @printf(ptr nocapture nonnull [[P]], i32 [[A]])
+; CGSCC-NEXT:    ret void
+;
+entry:
+  %call = call i32 (ptr, ...) @printf(ptr %p, i32 %a)
+  ret void
+}
+
+declare i32 @printf(ptr nocapture, ...)
+
+
+; TEST "captured" only through return
+;
+; long *not_captured_but_returned_0(long *a) {
+;   *a1 = 0;
+;   return a;
+; }
+;
+; There should *not* be a no-capture attribute on %a
+define ptr @not_captured_but_returned_0(ptr %a) #0 {
+; TUNIT: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(argmem: write) uwtable
+; TUNIT-LABEL: define noundef nonnull align 8 dereferenceable(8) ptr @not_captured_but_returned_0
+; TUNIT-SAME: (ptr nofree noundef nonnull returned writeonly align 8 dereferenceable(8) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR4:[0-9]+]] {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    store i64 0, ptr [[A]], align 8
+; TUNIT-NEXT:    ret ptr [[A]]
+;
+; CGSCC: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(argmem: write) uwtable
+; CGSCC-LABEL: define noundef nonnull align 8 dereferenceable(8) ptr @not_captured_but_returned_0
+; CGSCC-SAME: (ptr nofree noundef nonnull returned writeonly align 8 dereferenceable(8) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR5:[0-9]+]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    store i64 0, ptr [[A]], align 8
+; CGSCC-NEXT:    ret ptr [[A]]
+;
+entry:
+  store i64 0, ptr %a, align 8
+  ret ptr %a
+}
+
+; TEST "captured" only through return
+;
+; long *not_captured_but_returned_1(long *a) {
+;   *(a+1) = 1;
+;   return a + 1;
+; }
+;
+; There should *not* be a no-capture attribute on %a
+define ptr @not_captured_but_returned_1(ptr %a) #0 {
+; TUNIT: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(argmem: write) uwtable
+; TUNIT-LABEL: define noundef nonnull align 8 dereferenceable(8) ptr @not_captured_but_returned_1
+; TUNIT-SAME: (ptr nofree nonnull writeonly align 8 dereferenceable(16) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR4]] {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    [[ADD_PTR:%.*]] = getelementptr inbounds i64, ptr [[A]], i64 1
+; TUNIT-NEXT:    store i64 1, ptr [[ADD_PTR]], align 8
+; TUNIT-NEXT:    ret ptr [[ADD_PTR]]
+;
+; CGSCC: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(argmem: write) uwtable
+; CGSCC-LABEL: define noundef nonnull align 8 dereferenceable(8) ptr @not_captured_but_returned_1
+; CGSCC-SAME: (ptr nofree nonnull writeonly align 8 dereferenceable(16) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR5]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    [[ADD_PTR:%.*]] = getelementptr inbounds i64, ptr [[A]], i64 1
+; CGSCC-NEXT:    store i64 1, ptr [[ADD_PTR]], align 8
+; CGSCC-NEXT:    ret ptr [[ADD_PTR]]
+;
+entry:
+  %add.ptr = getelementptr inbounds i64, ptr %a, i64 1
+  store i64 1, ptr %add.ptr, align 8
+  ret ptr %add.ptr
+}
+
+; TEST calls to "captured" only through return functions
+;
+; void test_not_captured_but_returned_calls(long *a) {
+;   not_captured_but_returned_0(a);
+;   not_captured_but_returned_1(a);
+; }
+;
+define void @test_not_captured_but_returned_calls(ptr %a) #0 {
+; TUNIT: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(argmem: write) uwtable
+; TUNIT-LABEL: define void @test_not_captured_but_returned_calls
+; TUNIT-SAME: (ptr nocapture nofree nonnull writeonly align 8 [[A:%.*]]) #[[ATTR4]] {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    [[CALL:%.*]] = call ptr @not_captured_but_returned_0(ptr nofree noundef nonnull writeonly align 8 "no-capture-maybe-returned" [[A]]) #[[ATTR12:[0-9]+]]
+; TUNIT-NEXT:    [[CALL1:%.*]] = call ptr @not_captured_but_returned_1(ptr nofree nonnull writeonly align 8 "no-capture-maybe-returned" [[A]]) #[[ATTR12]]
+; TUNIT-NEXT:    ret void
+;
+; CGSCC: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(argmem: write) uwtable
+; CGSCC-LABEL: define void @test_not_captured_but_returned_calls
+; CGSCC-SAME: (ptr nofree noundef nonnull writeonly align 8 dereferenceable(16) [[A:%.*]]) #[[ATTR6:[0-9]+]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    [[CALL:%.*]] = call ptr @not_captured_but_returned_0(ptr nofree noundef nonnull writeonly align 8 dereferenceable(16) [[A]]) #[[ATTR15:[0-9]+]]
+; CGSCC-NEXT:    [[CALL1:%.*]] = call ptr @not_captured_but_returned_1(ptr nofree noundef nonnull writeonly align 8 dereferenceable(16) [[A]]) #[[ATTR15]]
+; CGSCC-NEXT:    ret void
+;
+entry:
+  %call = call ptr @not_captured_but_returned_0(ptr %a)
+  %call1 = call ptr @not_captured_but_returned_1(ptr %a)
+  ret void
+}
+
+; TEST "captured" only through transitive return
+;
+; long* negative_test_not_captured_but_returned_call_0a(long *a) {
+;   return not_captured_but_returned_0(a);
+; }
+;
+; There should *not* be a no-capture attribute on %a
+define ptr @negative_test_not_captured_but_returned_call_0a(ptr %a) #0 {
+; TUNIT: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(argmem: write) uwtable
+; TUNIT-LABEL: define nonnull align 8 ptr @negative_test_not_captured_but_returned_call_0a
+; TUNIT-SAME: (ptr nofree nonnull returned writeonly align 8 "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR4]] {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    [[CALL:%.*]] = call ptr @not_captured_but_returned_0(ptr nofree noundef nonnull writeonly align 8 "no-capture-maybe-returned" [[A]]) #[[ATTR12]]
+; TUNIT-NEXT:    ret ptr [[A]]
+;
+; CGSCC: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(argmem: write) uwtable
+; CGSCC-LABEL: define noundef nonnull align 8 dereferenceable(8) ptr @negative_test_not_captured_but_returned_call_0a
+; CGSCC-SAME: (ptr nofree noundef nonnull writeonly align 8 dereferenceable(8) [[A:%.*]]) #[[ATTR6]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    [[CALL:%.*]] = call noundef nonnull align 8 dereferenceable(8) ptr @not_captured_but_returned_0(ptr nofree noundef nonnull writeonly align 8 dereferenceable(8) [[A]]) #[[ATTR15]]
+; CGSCC-NEXT:    ret ptr [[CALL]]
+;
+entry:
+  %call = call ptr @not_captured_but_returned_0(ptr %a)
+  ret ptr %call
+}
+
+; TEST captured through write
+;
+; void negative_test_not_captured_but_returned_call_0b(long *a) {
+;   *a = (long)not_captured_but_returned_0(a);
+; }
+;
+; There should *not* be a no-capture attribute on %a
+define void @negative_test_not_captured_but_returned_call_0b(ptr %a) #0 {
+; TUNIT: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(argmem: write) uwtable
+; TUNIT-LABEL: define void @negative_test_not_captured_but_returned_call_0b
+; TUNIT-SAME: (ptr nofree nonnull writeonly align 8 [[A:%.*]]) #[[ATTR4]] {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    [[CALL:%.*]] = call ptr @not_captured_but_returned_0(ptr nofree noundef nonnull writeonly align 8 "no-capture-maybe-returned" [[A]]) #[[ATTR12]]
+; TUNIT-NEXT:    [[TMP0:%.*]] = ptrtoint ptr [[A]] to i64
+; TUNIT-NEXT:    store i64 [[TMP0]], ptr [[A]], align 8
+; TUNIT-NEXT:    ret void
+;
+; CGSCC: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(argmem: write) uwtable
+; CGSCC-LABEL: define void @negative_test_not_captured_but_returned_call_0b
+; CGSCC-SAME: (ptr nofree noundef nonnull writeonly align 8 dereferenceable(8) [[A:%.*]]) #[[ATTR6]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    [[CALL:%.*]] = call ptr @not_captured_but_returned_0(ptr nofree noundef nonnull writeonly align 8 dereferenceable(8) [[A]]) #[[ATTR15]]
+; CGSCC-NEXT:    [[TMP0:%.*]] = ptrtoint ptr [[CALL]] to i64
+; CGSCC-NEXT:    store i64 [[TMP0]], ptr [[A]], align 8
+; CGSCC-NEXT:    ret void
+;
+entry:
+  %call = call ptr @not_captured_but_returned_0(ptr %a)
+  %0 = ptrtoint ptr %call to i64
+  store i64 %0, ptr %a, align 8
+  ret void
+}
+
+; TEST "captured" only through transitive return
+;
+; long* negative_test_not_captured_but_returned_call_1a(long *a) {
+;   return not_captured_but_returned_1(a);
+; }
+;
+; There should *not* be a no-capture attribute on %a
+define ptr @negative_test_not_captured_but_returned_call_1a(ptr %a) #0 {
+; TUNIT: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(argmem: write) uwtable
+; TUNIT-LABEL: define noundef nonnull align 8 dereferenceable(8) ptr @negative_test_not_captured_but_returned_call_1a
+; TUNIT-SAME: (ptr nofree nonnull writeonly align 8 "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR4]] {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    [[CALL:%.*]] = call noundef nonnull align 8 dereferenceable(8) ptr @not_captured_but_returned_1(ptr nofree nonnull writeonly align 8 "no-capture-maybe-returned" [[A]]) #[[ATTR12]]
+; TUNIT-NEXT:    ret ptr [[CALL]]
+;
+; CGSCC: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(argmem: write) uwtable
+; CGSCC-LABEL: define noundef nonnull align 8 dereferenceable(8) ptr @negative_test_not_captured_but_returned_call_1a
+; CGSCC-SAME: (ptr nofree noundef nonnull writeonly align 8 dereferenceable(16) [[A:%.*]]) #[[ATTR6]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    [[CALL:%.*]] = call noundef nonnull align 8 dereferenceable(8) ptr @not_captured_but_returned_1(ptr nofree noundef nonnull writeonly align 8 dereferenceable(16) [[A]]) #[[ATTR15]]
+; CGSCC-NEXT:    ret ptr [[CALL]]
+;
+entry:
+  %call = call ptr @not_captured_but_returned_1(ptr %a)
+  ret ptr %call
+}
+
+; TEST captured through write
+;
+; void negative_test_not_captured_but_returned_call_1b(long *a) {
+;   *a = (long)not_captured_but_returned_1(a);
+; }
+;
+; There should *not* be a no-capture attribute on %a
+define void @negative_test_not_captured_but_returned_call_1b(ptr %a) #0 {
+; TUNIT: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(write) uwtable
+; TUNIT-LABEL: define void @negative_test_not_captured_but_returned_call_1b
+; TUNIT-SAME: (ptr nofree nonnull writeonly align 8 [[A:%.*]]) #[[ATTR5:[0-9]+]] {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    [[CALL:%.*]] = call align 8 ptr @not_captured_but_returned_1(ptr nofree nonnull writeonly align 8 "no-capture-maybe-returned" [[A]]) #[[ATTR12]]
+; TUNIT-NEXT:    [[TMP0:%.*]] = ptrtoint ptr [[CALL]] to i64
+; TUNIT-NEXT:    store i64 [[TMP0]], ptr [[CALL]], align 8
+; TUNIT-NEXT:    ret void
+;
+; CGSCC: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(write) uwtable
+; CGSCC-LABEL: define void @negative_test_not_captured_but_returned_call_1b
+; CGSCC-SAME: (ptr nofree noundef nonnull writeonly align 8 dereferenceable(16) [[A:%.*]]) #[[ATTR7:[0-9]+]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    [[CALL:%.*]] = call align 8 ptr @not_captured_but_returned_1(ptr nofree noundef nonnull writeonly align 8 dereferenceable(16) [[A]]) #[[ATTR15]]
+; CGSCC-NEXT:    [[TMP0:%.*]] = ptrtoint ptr [[CALL]] to i64
+; CGSCC-NEXT:    store i64 [[TMP0]], ptr [[CALL]], align 8
+; CGSCC-NEXT:    ret void
+;
+entry:
+  %call = call ptr @not_captured_but_returned_1(ptr %a)
+  %0 = ptrtoint ptr %call to i64
+  store i64 %0, ptr %call, align 8
+  ret void
+}
+
+; TEST return argument or unknown call result
+;
+; int* ret_arg_or_unknown(int* b) {
+;   if (b == 0)
+;     return b;
+;   return unknown();
+; }
+;
+; Verify we do *not* assume b is returned or not captured.
+;
+
+define ptr @ret_arg_or_unknown(ptr %b) #0 {
+; TUNIT: Function Attrs: noinline nounwind uwtable
+; TUNIT-LABEL: define nonnull ptr @ret_arg_or_unknown
+; TUNIT-SAME: (ptr nofree nonnull readnone "no-capture-maybe-returned" [[B:%.*]]) #[[ATTR3]] {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    br label [[RET_UNKNOWN:%.*]]
+; TUNIT:       ret_arg:
+; TUNIT-NEXT:    unreachable
+; TUNIT:       ret_unknown:
+; TUNIT-NEXT:    [[CALL:%.*]] = call nonnull ptr @unknown()
+; TUNIT-NEXT:    ret ptr [[CALL]]
+;
+; CGSCC: Function Attrs: noinline nounwind uwtable
+; CGSCC-LABEL: define nonnull ptr @ret_arg_or_unknown
+; CGSCC-SAME: (ptr nofree nonnull readnone "no-capture-maybe-returned" [[B:%.*]]) #[[ATTR4]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    br label [[RET_UNKNOWN:%.*]]
+; CGSCC:       ret_arg:
+; CGSCC-NEXT:    unreachable
+; CGSCC:       ret_unknown:
+; CGSCC-NEXT:    [[CALL:%.*]] = call nonnull ptr @unknown()
+; CGSCC-NEXT:    ret ptr [[CALL]]
+;
+entry:
+  %cmp = icmp eq ptr %b, null
+  br i1 %cmp, label %ret_arg, label %ret_unknown
+
+ret_arg:
+  ret ptr %b
+
+ret_unknown:
+  %call = call ptr @unknown()
+  ret ptr %call
+}
+
+define ptr @ret_arg_or_unknown_through_phi(ptr %b) #0 {
+; TUNIT: Function Attrs: noinline nounwind uwtable
+; TUNIT-LABEL: define nonnull ptr @ret_arg_or_unknown_through_phi
+; TUNIT-SAME: (ptr nocapture nofree nonnull readnone [[B:%.*]]) #[[ATTR3]] {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    br label [[RET_UNKNOWN:%.*]]
+; TUNIT:       ret_arg:
+; TUNIT-NEXT:    unreachable
+; TUNIT:       ret_unknown:
+; TUNIT-NEXT:    [[CALL:%.*]] = call nonnull ptr @unknown()
+; TUNIT-NEXT:    br label [[R:%.*]]
+; TUNIT:       r:
+; TUNIT-NEXT:    ret ptr [[CALL]]
+;
+; CGSCC: Function Attrs: noinline nounwind uwtable
+; CGSCC-LABEL: define nonnull ptr @ret_arg_or_unknown_through_phi
+; CGSCC-SAME: (ptr nocapture nofree nonnull readnone [[B:%.*]]) #[[ATTR4]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    br label [[RET_UNKNOWN:%.*]]
+; CGSCC:       ret_arg:
+; CGSCC-NEXT:    unreachable
+; CGSCC:       ret_unknown:
+; CGSCC-NEXT:    [[CALL:%.*]] = call nonnull ptr @unknown()
+; CGSCC-NEXT:    br label [[R:%.*]]
+; CGSCC:       r:
+; CGSCC-NEXT:    ret ptr [[CALL]]
+;
+entry:
+  %cmp = icmp eq ptr %b, null
+  br i1 %cmp, label %ret_arg, label %ret_unknown
+
+ret_arg:
+  br label %r
+
+ret_unknown:
+  %call = call ptr @unknown()
+  br label %r
+
+r:
+  %phi = phi ptr [ %b, %ret_arg ], [ %call, %ret_unknown ]
+  ret ptr %phi
+}
+
+
+; TEST not captured by readonly external function
+;
+declare ptr @readonly_unknown(ptr, ptr) readonly
+
+define void @not_captured_by_readonly_call(ptr %b) #0 {
+; TUNIT: Function Attrs: noinline nosync nounwind memory(read) uwtable
+; TUNIT-LABEL: define void @not_captured_by_readonly_call
+; TUNIT-SAME: (ptr nocapture nonnull readonly [[B:%.*]]) #[[ATTR7:[0-9]+]] {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    [[CALL:%.*]] = call ptr @readonly_unknown(ptr nonnull readonly [[B]], ptr nonnull readonly [[B]]) #[[ATTR13:[0-9]+]]
+; TUNIT-NEXT:    ret void
+;
+; CGSCC: Function Attrs: noinline nosync nounwind memory(read) uwtable
+; CGSCC-LABEL: define void @not_captured_by_readonly_call
+; CGSCC-SAME: (ptr nocapture nonnull readonly [[B:%.*]]) #[[ATTR9:[0-9]+]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    [[CALL:%.*]] = call ptr @readonly_unknown(ptr nonnull readonly [[B]], ptr nonnull readonly [[B]]) #[[ATTR16:[0-9]+]]
+; CGSCC-NEXT:    ret void
+;
+entry:
+  %call = call ptr @readonly_unknown(ptr %b, ptr %b)
+  ret void
+}
+
+
+; TEST not captured by readonly external function if return chain is known
+;
+; Make sure the returned flag on %r is strong enough to justify nocapture on %b but **not** on %r.
+;
+define ptr @not_captured_by_readonly_call_not_returned_either1(ptr %b, ptr returned %r) {
+; TUNIT: Function Attrs: nosync nounwind memory(read)
+; TUNIT-LABEL: define nonnull ptr @not_captured_by_readonly_call_not_returned_either1
+; TUNIT-SAME: (ptr nocapture nonnull readonly [[B:%.*]], ptr nonnull readonly returned [[R:%.*]]) #[[ATTR8:[0-9]+]] {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    [[CALL:%.*]] = call ptr @readonly_unknown(ptr nonnull readonly [[B]], ptr nonnull readonly [[R]]) #[[ATTR8]]
+; TUNIT-NEXT:    ret ptr [[CALL]]
+;
+; CGSCC: Function Attrs: nosync nounwind memory(read)
+; CGSCC-LABEL: define nonnull ptr @not_captured_by_readonly_call_not_returned_either1
+; CGSCC-SAME: (ptr nocapture nonnull readonly [[B:%.*]], ptr nonnull readonly returned [[R:%.*]]) #[[ATTR10:[0-9]+]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    [[CALL:%.*]] = call ptr @readonly_unknown(ptr nonnull readonly [[B]], ptr nonnull readonly [[R]]) #[[ATTR10]]
+; CGSCC-NEXT:    ret ptr [[CALL]]
+;
+entry:
+  %call = call ptr @readonly_unknown(ptr %b, ptr %r) nounwind
+  ret ptr %call
+}
+
+declare ptr @readonly_unknown_r1a(ptr, ptr returned) readonly
+define ptr @not_captured_by_readonly_call_not_returned_either2(ptr %b, ptr %r) {
+; TUNIT: Function Attrs: nosync nounwind memory(read)
+; TUNIT-LABEL: define nonnull ptr @not_captured_by_readonly_call_not_returned_either2
+; TUNIT-SAME: (ptr nonnull readonly [[B:%.*]], ptr nonnull readonly [[R:%.*]]) #[[ATTR8]] {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    [[CALL:%.*]] = call nonnull ptr @readonly_unknown_r1a(ptr nonnull readonly [[B]], ptr nonnull readonly [[R]]) #[[ATTR8]]
+; TUNIT-NEXT:    ret ptr [[CALL]]
+;
+; CGSCC: Function Attrs: nosync nounwind memory(read)
+; CGSCC-LABEL: define nonnull ptr @not_captured_by_readonly_call_not_returned_either2
+; CGSCC-SAME: (ptr nonnull readonly [[B:%.*]], ptr nonnull readonly [[R:%.*]]) #[[ATTR10]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    [[CALL:%.*]] = call nonnull ptr @readonly_unknown_r1a(ptr nonnull readonly [[B]], ptr nonnull readonly [[R]]) #[[ATTR10]]
+; CGSCC-NEXT:    ret ptr [[CALL]]
+;
+entry:
+  %call = call ptr @readonly_unknown_r1a(ptr %b, ptr %r) nounwind
+  ret ptr %call
+}
+
+declare ptr @readonly_unknown_r1b(ptr, ptr returned) readonly nounwind
+define ptr @not_captured_by_readonly_call_not_returned_either3(ptr %b, ptr %r) {
+; TUNIT: Function Attrs: nosync nounwind memory(read)
+; TUNIT-LABEL: define nonnull ptr @not_captured_by_readonly_call_not_returned_either3
+; TUNIT-SAME: (ptr nocapture nonnull readonly [[B:%.*]], ptr nonnull readonly [[R:%.*]]) #[[ATTR8]] {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    [[CALL:%.*]] = call nonnull ptr @readonly_unknown_r1b(ptr nocapture nonnull readonly [[B]], ptr nonnull readonly [[R]]) #[[ATTR8]]
+; TUNIT-NEXT:    ret ptr [[CALL]]
+;
+; CGSCC: Function Attrs: nosync nounwind memory(read)
+; CGSCC-LABEL: define nonnull ptr @not_captured_by_readonly_call_not_returned_either3
+; CGSCC-SAME: (ptr nocapture nonnull readonly [[B:%.*]], ptr nonnull readonly [[R:%.*]]) #[[ATTR10]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    [[CALL:%.*]] = call nonnull ptr @readonly_unknown_r1b(ptr nocapture nonnull readonly [[B]], ptr nonnull readonly [[R]]) #[[ATTR10]]
+; CGSCC-NEXT:    ret ptr [[CALL]]
+;
+entry:
+  %call = call ptr @readonly_unknown_r1b(ptr %b, ptr %r)
+  ret ptr %call
+}
+
+define ptr @not_captured_by_readonly_call_not_returned_either4(ptr %b, ptr %r) nounwind {
+; TUNIT: Function Attrs: nosync nounwind memory(read)
+; TUNIT-LABEL: define nonnull ptr @not_captured_by_readonly_call_not_returned_either4
+; TUNIT-SAME: (ptr nonnull readonly [[B:%.*]], ptr nonnull readonly [[R:%.*]]) #[[ATTR8]] {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    [[CALL:%.*]] = call nonnull ptr @readonly_unknown_r1a(ptr nonnull readonly [[B]], ptr nonnull readonly [[R]]) #[[ATTR13]]
+; TUNIT-NEXT:    ret ptr [[CALL]]
+;
+; CGSCC: Function Attrs: nosync nounwind memory(read)
+; CGSCC-LABEL: define nonnull ptr @not_captured_by_readonly_call_not_returned_either4
+; CGSCC-SAME: (ptr nonnull readonly [[B:%.*]], ptr nonnull readonly [[R:%.*]]) #[[ATTR10]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    [[CALL:%.*]] = call nonnull ptr @readonly_unknown_r1a(ptr nonnull readonly [[B]], ptr nonnull readonly [[R]]) #[[ATTR16]]
+; CGSCC-NEXT:    ret ptr [[CALL]]
+;
+entry:
+  %call = call ptr @readonly_unknown_r1a(ptr %b, ptr %r)
+  ret ptr %call
+}
+
+
+declare ptr @unknown_i32p(ptr)
+define void @nocapture_is_not_subsumed_1(ptr nocapture %b) {
+; CHECK-LABEL: define void @nocapture_is_not_subsumed_1
+; CHECK-SAME: (ptr nocapture nonnull [[B:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CALL:%.*]] = call ptr @unknown_i32p(ptr nonnull [[B]])
+; CHECK-NEXT:    store i32 0, ptr [[CALL]], align 4
+; CHECK-NEXT:    ret void
+;
+entry:
+  %call = call ptr @unknown_i32p(ptr %b)
+  store i32 0, ptr %call
+  ret void
+}
+
+declare ptr @readonly_i32p(ptr) readonly
+define void @nocapture_is_not_subsumed_2(ptr nocapture %b) {
+; TUNIT: Function Attrs: nosync
+; TUNIT-LABEL: define void @nocapture_is_not_subsumed_2
+; TUNIT-SAME: (ptr nocapture nonnull [[B:%.*]]) #[[ATTR10:[0-9]+]] {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    [[CALL:%.*]] = call ptr @readonly_i32p(ptr nonnull readonly [[B]]) #[[ATTR13]]
+; TUNIT-NEXT:    store i32 0, ptr [[CALL]], align 4
+; TUNIT-NEXT:    ret void
+;
+; CGSCC: Function Attrs: nosync
+; CGSCC-LABEL: define void @nocapture_is_not_subsumed_2
+; CGSCC-SAME: (ptr nocapture nonnull [[B:%.*]]) #[[ATTR12:[0-9]+]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    [[CALL:%.*]] = call ptr @readonly_i32p(ptr nonnull readonly [[B]]) #[[ATTR16]]
+; CGSCC-NEXT:    store i32 0, ptr [[CALL]], align 4
+; CGSCC-NEXT:    ret void
+;
+entry:
+  %call = call ptr @readonly_i32p(ptr %b)
+  store i32 0, ptr %call
+  ret void
+}
+
+; Make sure %p is not not marked nocapture (Bug #64613).
+; Version a failed with the lightweight attributor, b with the full one.
+define ptr @b64613_a(ptr noundef %p) {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; TUNIT-LABEL: define noundef nonnull ptr @b64613_a
+; TUNIT-SAME: (ptr nofree noundef nonnull readnone returned "no-capture-maybe-returned" [[P:%.*]]) #[[ATTR11:[0-9]+]] {
+; TUNIT-NEXT:    [[P_ADDR:%.*]] = alloca ptr, align 1
+; TUNIT-NEXT:    store ptr [[P]], ptr [[P_ADDR]], align 1
+; TUNIT-NEXT:    ret ptr [[P]]
+;
+; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define noundef nonnull ptr @b64613_a
+; CGSCC-SAME: (ptr nofree noundef nonnull readnone returned "no-capture-maybe-returned" [[P:%.*]]) #[[ATTR13:[0-9]+]] {
+; CGSCC-NEXT:    [[P_ADDR:%.*]] = alloca ptr, align 1
+; CGSCC-NEXT:    store ptr [[P]], ptr [[P_ADDR]], align 1
+; CGSCC-NEXT:    ret ptr [[P]]
+;
+  %p.addr = alloca ptr, align 1
+  store ptr %p, ptr %p.addr, align 1
+  %r = load ptr, ptr %p.addr, align 1
+  ret ptr %r
+}
+define ptr @b64613_b(ptr noundef %p, i32 %i) {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; TUNIT-LABEL: define nonnull ptr @b64613_b
+; TUNIT-SAME: (ptr nofree noundef nonnull [[P:%.*]], i32 [[I:%.*]]) #[[ATTR11]] {
+; TUNIT-NEXT:    [[P_ADDR:%.*]] = alloca <2 x ptr>, align 1
+; TUNIT-NEXT:    [[G:%.*]] = getelementptr i8, ptr [[P_ADDR]], i32 [[I]]
+; TUNIT-NEXT:    store ptr [[P]], ptr [[G]], align 1
+; TUNIT-NEXT:    [[R:%.*]] = load ptr, ptr [[P_ADDR]], align 1
+; TUNIT-NEXT:    ret ptr [[R]]
+;
+; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define nonnull ptr @b64613_b
+; CGSCC-SAME: (ptr nofree noundef nonnull [[P:%.*]], i32 [[I:%.*]]) #[[ATTR13]] {
+; CGSCC-NEXT:    [[P_ADDR:%.*]] = alloca <2 x ptr>, align 1
+; CGSCC-NEXT:    [[G:%.*]] = getelementptr i8, ptr [[P_ADDR]], i32 [[I]]
+; CGSCC-NEXT:    store ptr [[P]], ptr [[G]], align 1
+; CGSCC-NEXT:    [[R:%.*]] = load ptr, ptr [[P_ADDR]], align 1
+; CGSCC-NEXT:    ret ptr [[R]]
+;
+  %p.addr = alloca <2 x ptr>, align 1
+  %g = getelementptr i8, ptr %p.addr, i32 %i
+  store ptr %p, ptr %g, align 1
+  %r = load ptr, ptr %p.addr, align 1
+  ret ptr %r
+}
+define void @b64613_positive(ptr noundef %p, i32 %i) {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; TUNIT-LABEL: define void @b64613_positive
+; TUNIT-SAME: (ptr nocapture nofree noundef nonnull [[P:%.*]], i32 [[I:%.*]]) #[[ATTR11]] {
+; TUNIT-NEXT:    [[P_ADDR:%.*]] = alloca <2 x ptr>, align 1
+; TUNIT-NEXT:    [[G:%.*]] = getelementptr i8, ptr [[P_ADDR]], i32 [[I]]
+; TUNIT-NEXT:    store ptr [[P]], ptr [[G]], align 1
+; TUNIT-NEXT:    ret void
+;
+; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define void @b64613_positive
+; CGSCC-SAME: (ptr nocapture nofree noundef nonnull [[P:%.*]], i32 [[I:%.*]]) #[[ATTR14:[0-9]+]] {
+; CGSCC-NEXT:    [[P_ADDR:%.*]] = alloca <2 x ptr>, align 1
+; CGSCC-NEXT:    [[G:%.*]] = getelementptr i8, ptr [[P_ADDR]], i32 [[I]]
+; CGSCC-NEXT:    store ptr [[P]], ptr [[G]], align 1
+; CGSCC-NEXT:    ret void
+;
+  %p.addr = alloca <2 x ptr>, align 1
+  %g = getelementptr i8, ptr %p.addr, i32 %i
+  store ptr %p, ptr %g, align 1
+  %r = load ptr, ptr %p.addr, align 1
+  %q = call ptr @b64613_b(ptr %r, i32 %i)
+  ret void
+}
+
+attributes #0 = { noinline nounwind uwtable }
+;.
+; TUNIT: attributes #[[ATTR0]] = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable }
+; TUNIT: attributes #[[ATTR1]] = { mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable }
+; TUNIT: attributes #[[ATTR2]] = { mustprogress nofree noreturn nosync nounwind willreturn memory(none) }
+; TUNIT: attributes #[[ATTR3]] = { noinline nounwind uwtable }
+; TUNIT: attributes #[[ATTR4]] = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(argmem: write) uwtable }
+; TUNIT: attributes #[[ATTR5]] = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(write) uwtable }
+; TUNIT: attributes #[[ATTR6:[0-9]+]] = { memory(read) }
+; TUNIT: attributes #[[ATTR7]] = { noinline nosync nounwind memory(read) uwtable }
+; TUNIT: attributes #[[ATTR8]] = { nosync nounwind memory(read) }
+; TUNIT: attributes #[[ATTR9:[0-9]+]] = { nounwind memory(read) }
+; TUNIT: attributes #[[ATTR10]] = { nosync }
+; TUNIT: attributes #[[ATTR11]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
+; TUNIT: attributes #[[ATTR12]] = { nofree nosync nounwind willreturn memory(write) }
+; TUNIT: attributes #[[ATTR13]] = { nosync memory(read) }
+;.
+; CGSCC: attributes #[[ATTR0]] = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable }
+; CGSCC: attributes #[[ATTR1]] = { mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable }
+; CGSCC: attributes #[[ATTR2]] = { mustprogress nofree noreturn nosync nounwind willreturn memory(none) }
+; CGSCC: attributes #[[ATTR3]] = { mustprogress nofree norecurse noreturn nosync nounwind willreturn memory(none) }
+; CGSCC: attributes #[[ATTR4]] = { noinline nounwind uwtable }
+; CGSCC: attributes #[[ATTR5]] = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(argmem: write) uwtable }
+; CGSCC: attributes #[[ATTR6]] = { mustprogress nofree noinline nosync nounwind willreturn memory(argmem: write) uwtable }
+; CGSCC: attributes #[[ATTR7]] = { mustprogress nofree noinline nosync nounwind willreturn memory(write) uwtable }
+; CGSCC: attributes #[[ATTR8:[0-9]+]] = { memory(read) }
+; CGSCC: attributes #[[ATTR9]] = { noinline nosync nounwind memory(read) uwtable }
+; CGSCC: attributes #[[ATTR10]] = { nosync nounwind memory(read) }
+; CGSCC: attributes #[[ATTR11:[0-9]+]] = { nounwind memory(read) }
+; CGSCC: attributes #[[ATTR12]] = { nosync }
+; CGSCC: attributes #[[ATTR13]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
+; CGSCC: attributes #[[ATTR14]] = { mustprogress nofree nosync nounwind willreturn memory(none) }
+; CGSCC: attributes #[[ATTR15]] = { nofree nounwind willreturn memory(write) }
+; CGSCC: attributes #[[ATTR16]] = { nosync memory(read) }
+;.
diff --git a/llvm/test/Transforms/Attributor/nofree-dl-sentinel.ll b/llvm/test/Transforms/Attributor/nofree-dl-sentinel.ll
new file mode 100755
index 0000000000000..de752340cc16d
--- /dev/null
+++ b/llvm/test/Transforms/Attributor/nofree-dl-sentinel.ll
@@ -0,0 +1,516 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal  -attributor-annotate-decl-cs  -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal  -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-z0:1-z2:neg1-z3:neg1-z5:neg1-S128"
+
+; Test cases specifically designed for the "nofree" function attribute.
+; We use FIXME's to indicate problems and missing attributes.
+
+; Free functions
+declare void @free(ptr nocapture) local_unnamed_addr #1
+declare noalias ptr @realloc(ptr nocapture, i64) local_unnamed_addr #0
+declare void @_ZdaPv(ptr) local_unnamed_addr #2
+
+
+; TEST 1 (positive case)
+define void @only_return() #0 {
+; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
+; CHECK-LABEL: define {{[^@]+}}@only_return
+; CHECK-SAME: () #[[ATTR3:[0-9]+]] {
+; CHECK-NEXT:    ret void
+;
+  ret void
+}
+
+
+; TEST 2 (negative case)
+; Only free
+; void only_free(char* p) {
+;    free(p);
+; }
+
+define void @only_free(ptr nocapture %0) local_unnamed_addr #0 {
+; CHECK: Function Attrs: noinline nounwind uwtable
+; CHECK-LABEL: define {{[^@]+}}@only_free
+; CHECK-SAME: (ptr nocapture nonnull [[TMP0:%.*]]) local_unnamed_addr #[[ATTR1:[0-9]+]] {
+; CHECK-NEXT:    tail call void @free(ptr nocapture nonnull [[TMP0]]) #[[ATTR0:[0-9]+]]
+; CHECK-NEXT:    ret void
+;
+  tail call void @free(ptr %0) #1
+  ret void
+}
+
+
+; TEST 3 (negative case)
+; Free occurs in same scc.
+; void free_in_scc1(char*p){
+;    free_in_scc2(p);
+; }
+; void free_in_scc2(char*p){
+;    free_in_scc1(p);
+;    free(p);
+; }
+
+
+define void @free_in_scc1(ptr nocapture %0) local_unnamed_addr #0 {
+; CHECK: Function Attrs: noinline nounwind uwtable
+; CHECK-LABEL: define {{[^@]+}}@free_in_scc1
+; CHECK-SAME: (ptr nocapture nonnull [[TMP0:%.*]]) local_unnamed_addr #[[ATTR1]] {
+; CHECK-NEXT:    tail call void @free_in_scc2(ptr nocapture nonnull [[TMP0]]) #[[ATTR0]]
+; CHECK-NEXT:    ret void
+;
+  tail call void @free_in_scc2(ptr %0) #1
+  ret void
+}
+
+
+define void @free_in_scc2(ptr nocapture %0) local_unnamed_addr #0 {
+; CHECK: Function Attrs: noinline nounwind uwtable
+; CHECK-LABEL: define {{[^@]+}}@free_in_scc2
+; CHECK-SAME: (ptr nocapture nonnull [[TMP0:%.*]]) local_unnamed_addr #[[ATTR1]] {
+; CHECK-NEXT:    br label [[CALL:%.*]]
+; CHECK:       call:
+; CHECK-NEXT:    tail call void @free(ptr nocapture nonnull [[TMP0]]) #[[ATTR0]]
+; CHECK-NEXT:    br label [[END:%.*]]
+; CHECK:       rec:
+; CHECK-NEXT:    unreachable
+; CHECK:       end:
+; CHECK-NEXT:    ret void
+;
+  %cmp = icmp eq ptr %0, null
+  br i1 %cmp, label %rec, label %call
+call:
+  tail call void @free(ptr %0) #1
+  br label %end
+rec:
+  tail call void @free_in_scc1(ptr %0)
+  br label %end
+end:
+  ret void
+}
+
+
+; TEST 4 (positive case)
+; Free doesn't occur.
+; void mutual_recursion1(){
+;    mutual_recursion2();
+; }
+; void mutual_recursion2(){
+;     mutual_recursion1();
+; }
+
+
+define void @mutual_recursion1() #0 {
+; TUNIT: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable
+; TUNIT-LABEL: define {{[^@]+}}@mutual_recursion1
+; TUNIT-SAME: () #[[ATTR4:[0-9]+]] {
+; TUNIT-NEXT:    ret void
+;
+; CGSCC: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
+; CGSCC-LABEL: define {{[^@]+}}@mutual_recursion1
+; CGSCC-SAME: () #[[ATTR3]] {
+; CGSCC-NEXT:    ret void
+;
+  call void @mutual_recursion2()
+  ret void
+}
+
+define void @mutual_recursion2() #0 {
+; TUNIT: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable
+; TUNIT-LABEL: define {{[^@]+}}@mutual_recursion2
+; TUNIT-SAME: () #[[ATTR4]] {
+; TUNIT-NEXT:    ret void
+;
+; CGSCC: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
+; CGSCC-LABEL: define {{[^@]+}}@mutual_recursion2
+; CGSCC-SAME: () #[[ATTR3]] {
+; CGSCC-NEXT:    ret void
+;
+  call void @mutual_recursion1()
+  ret void
+}
+
+
+; TEST 5
+; C++ delete operation (negative case)
+; void delete_op (char p[]){
+;     delete [] p;
+; }
+
+define void @_Z9delete_opPc(ptr %0) local_unnamed_addr #0 {
+; CHECK: Function Attrs: noinline nounwind uwtable
+; CHECK-LABEL: define {{[^@]+}}@_Z9delete_opPc
+; CHECK-SAME: (ptr nonnull [[TMP0:%.*]]) local_unnamed_addr #[[ATTR1]] {
+; CHECK-NEXT:    br label [[TMP2:%.*]]
+; CHECK:       2:
+; CHECK-NEXT:    tail call void @_ZdaPv(ptr nonnull [[TMP0]]) #[[ATTR2:[0-9]+]]
+; CHECK-NEXT:    br label [[TMP3:%.*]]
+; CHECK:       3:
+; CHECK-NEXT:    ret void
+;
+  %2 = icmp eq ptr %0, null
+  br i1 %2, label %4, label %3
+
+; <label>:3:                                      ; preds = %1
+  tail call void @_ZdaPv(ptr nonnull %0) #2
+  br label %4
+
+; <label>:4:                                      ; preds = %3, %1
+  ret void
+}
+
+
+; TEST 6 (negative case)
+; Call realloc
+define noalias ptr @call_realloc(ptr nocapture %0, i64 %1) local_unnamed_addr #0 {
+; CHECK: Function Attrs: noinline nounwind uwtable
+; CHECK-LABEL: define {{[^@]+}}@call_realloc
+; CHECK-SAME: (ptr nocapture nonnull [[TMP0:%.*]], i64 [[TMP1:%.*]]) local_unnamed_addr #[[ATTR1]] {
+; CHECK-NEXT:    [[RET:%.*]] = tail call nonnull ptr @realloc(ptr nocapture nonnull [[TMP0]], i64 [[TMP1]]) #[[ATTR2]]
+; CHECK-NEXT:    ret ptr [[RET]]
+;
+  %ret = tail call ptr @realloc(ptr %0, i64 %1) #2
+  ret ptr %ret
+}
+
+
+; TEST 7 (positive case)
+; Call function declaration with "nofree"
+
+
+; CHECK: Function Attrs:  nofree noinline nounwind memory(none) uwtable
+declare void @nofree_function() nofree readnone #0
+
+define void @call_nofree_function() #0 {
+; TUNIT: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable
+; TUNIT-LABEL: define {{[^@]+}}@call_nofree_function
+; TUNIT-SAME: () #[[ATTR4]] {
+; TUNIT-NEXT:    ret void
+;
+; CGSCC: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable
+; CGSCC-LABEL: define {{[^@]+}}@call_nofree_function
+; CGSCC-SAME: () #[[ATTR5:[0-9]+]] {
+; CGSCC-NEXT:    ret void
+;
+  tail call void @nofree_function()
+  ret void
+}
+
+; TEST 8 (negative case)
+; Call function declaration without "nofree"
+
+
+; CHECK: Function Attrs: noinline nounwind uwtable
+declare void @maybe_free() #0
+
+
+define void @call_maybe_free() #0 {
+; CHECK: Function Attrs: noinline nounwind uwtable
+; CHECK-LABEL: define {{[^@]+}}@call_maybe_free
+; CHECK-SAME: () #[[ATTR1]] {
+; CHECK-NEXT:    tail call void @maybe_free() #[[ATTR0]]
+; CHECK-NEXT:    ret void
+;
+  tail call void @maybe_free()
+  ret void
+}
+
+
+; TEST 9 (negative case)
+; Call both of above functions
+
+define void @call_both() #0 {
+; CHECK: Function Attrs: noinline nounwind uwtable
+; CHECK-LABEL: define {{[^@]+}}@call_both
+; CHECK-SAME: () #[[ATTR1]] {
+; CHECK-NEXT:    tail call void @maybe_free() #[[ATTR0]]
+; CHECK-NEXT:    ret void
+;
+  tail call void @maybe_free()
+  tail call void @nofree_function()
+  ret void
+}
+
+
+; TEST 10 (positive case)
+; Call intrinsic function
+; CHECK: Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
+declare float @llvm.floor.f32(float)
+
+define void @call_floor(float %a) #0 {
+; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
+; CHECK-LABEL: define {{[^@]+}}@call_floor
+; CHECK-SAME: (float [[A:%.*]]) #[[ATTR3]] {
+; CHECK-NEXT:    ret void
+;
+  tail call float @llvm.floor.f32(float %a)
+  ret void
+}
+
+define float @call_floor2(float %a) #0 {
+; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
+; CHECK-LABEL: define {{[^@]+}}@call_floor2
+; CHECK-SAME: (float nofpclass(sub) [[A:%.*]]) #[[ATTR3]] {
+; CHECK-NEXT:    [[C:%.*]] = tail call nofpclass(sub) float @llvm.floor.f32(float nofpclass(sub) [[A]]) #[[ATTR14:[0-9]+]]
+; CHECK-NEXT:    ret float [[C]]
+;
+  %c = tail call float @llvm.floor.f32(float %a)
+  ret float %c
+}
+
+; TEST 11 (positive case)
+; Check propagation.
+
+define void @f1() #0 {
+; TUNIT: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable
+; TUNIT-LABEL: define {{[^@]+}}@f1
+; TUNIT-SAME: () #[[ATTR4]] {
+; TUNIT-NEXT:    ret void
+;
+; CGSCC: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable
+; CGSCC-LABEL: define {{[^@]+}}@f1
+; CGSCC-SAME: () #[[ATTR5]] {
+; CGSCC-NEXT:    ret void
+;
+  tail call void @nofree_function()
+  ret void
+}
+
+define void @f2() #0 {
+; TUNIT: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable
+; TUNIT-LABEL: define {{[^@]+}}@f2
+; TUNIT-SAME: () #[[ATTR4]] {
+; TUNIT-NEXT:    ret void
+;
+; CGSCC: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable
+; CGSCC-LABEL: define {{[^@]+}}@f2
+; CGSCC-SAME: () #[[ATTR5]] {
+; CGSCC-NEXT:    ret void
+;
+  tail call void @f1()
+  ret void
+}
+
+; TEST 12 NoFree argument - positive.
+define double @test12(ptr nocapture readonly %a) {
+; CHECK: Function Attrs: nofree nounwind
+; CHECK-LABEL: define {{[^@]+}}@test12
+; CHECK-SAME: (ptr nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) [[A:%.*]]) #[[ATTR7:[0-9]+]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = load double, ptr [[A]], align 8
+; CHECK-NEXT:    [[CALL:%.*]] = tail call double @cos(double [[TMP0]]) #[[ATTR8:[0-9]+]]
+; CHECK-NEXT:    ret double [[CALL]]
+;
+entry:
+  %0 = load double, ptr %a, align 8
+  %call = tail call double @cos(double %0) #2
+  ret double %call
+}
+
+declare double @cos(double) nobuiltin nounwind nofree
+
+; FIXME: %a should be nofree.
+; TEST 13 NoFree argument - positive.
+define noalias ptr @test13(ptr nocapture readonly %a) {
+; CHECK: Function Attrs: nounwind
+; CHECK-LABEL: define {{[^@]+}}@test13
+; CHECK-SAME: (ptr nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) [[A:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = load i64, ptr [[A]], align 8
+; CHECK-NEXT:    [[CALL:%.*]] = tail call noalias nonnull ptr @malloc(i64 [[TMP0]]) #[[ATTR2]]
+; CHECK-NEXT:    ret ptr [[CALL]]
+;
+entry:
+  %0 = load i64, ptr %a, align 8
+  %call = tail call noalias ptr @malloc(i64 %0) #2
+  ret ptr %call
+}
+
+define void @test14(ptr nocapture %0, ptr nocapture %1) {
+; CHECK: Function Attrs: nounwind
+; CHECK-LABEL: define {{[^@]+}}@test14
+; CHECK-SAME: (ptr nocapture nonnull [[TMP0:%.*]], ptr nocapture nofree nonnull readnone [[TMP1:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    tail call void @free(ptr nocapture nonnull [[TMP0]]) #[[ATTR0]]
+; CHECK-NEXT:    ret void
+;
+  tail call void @free(ptr %0) #1
+  ret void
+}
+
+; UTC_ARGS: --enable
+
+define void @nonnull_assume_pos(ptr %arg1, ptr %arg2, ptr %arg3, ptr %arg4) {
+; ATTRIBUTOR-LABEL: define {{[^@]+}}@nonnull_assume_pos
+; ATTRIBUTOR-SAME: (ptr nofree [[ARG1:%.*]], ptr [[ARG2:%.*]], ptr nofree [[ARG3:%.*]], ptr [[ARG4:%.*]])
+; ATTRIBUTOR-NEXT:    call void @llvm.assume(i1 true) #11 [ "nofree"(ptr [[ARG1]]), "nofree"(ptr [[ARG3]]) ]
+; ATTRIBUTOR-NEXT:    call void @unknown(ptr nofree [[ARG1]], ptr [[ARG2]], ptr nofree [[ARG3]], ptr [[ARG4]])
+; ATTRIBUTOR-NEXT:    ret void
+;
+; CHECK-LABEL: define {{[^@]+}}@nonnull_assume_pos
+; CHECK-SAME: (ptr nofree nonnull [[ARG1:%.*]], ptr nonnull [[ARG2:%.*]], ptr nofree nonnull [[ARG3:%.*]], ptr nonnull [[ARG4:%.*]]) {
+; CHECK-NEXT:    call void @llvm.assume(i1 noundef true) #[[ATTR15:[0-9]+]] [ "nofree"(ptr [[ARG1]]), "nofree"(ptr [[ARG3]]) ]
+; CHECK-NEXT:    call void @unknown(ptr nofree nonnull [[ARG1]], ptr nonnull [[ARG2]], ptr nofree nonnull [[ARG3]], ptr nonnull [[ARG4]])
+; CHECK-NEXT:    ret void
+;
+  call void @llvm.assume(i1 true) ["nofree"(ptr %arg1), "nofree"(ptr %arg3)]
+  call void @unknown(ptr %arg1, ptr %arg2, ptr %arg3, ptr %arg4)
+  ret void
+}
+define void @nonnull_assume_neg(ptr %arg1, ptr %arg2, ptr %arg3, ptr %arg4) {
+; ATTRIBUTOR-LABEL: define {{[^@]+}}@nonnull_assume_neg
+; ATTRIBUTOR-SAME: (ptr [[ARG1:%.*]], ptr [[ARG2:%.*]], ptr [[ARG3:%.*]], ptr [[ARG4:%.*]])
+; ATTRIBUTOR-NEXT:    call void @unknown(ptr [[ARG1]], ptr [[ARG2]], ptr [[ARG3]], ptr [[ARG4]])
+; ATTRIBUTOR-NEXT:    call void @llvm.assume(i1 true) [ "nofree"(ptr [[ARG1]]), "nofree"(ptr [[ARG3]]) ]
+; ATTRIBUTOR-NEXT:    ret void
+;
+; CHECK-LABEL: define {{[^@]+}}@nonnull_assume_neg
+; CHECK-SAME: (ptr nonnull [[ARG1:%.*]], ptr nonnull [[ARG2:%.*]], ptr nonnull [[ARG3:%.*]], ptr nonnull [[ARG4:%.*]]) {
+; CHECK-NEXT:    call void @unknown(ptr nonnull [[ARG1]], ptr nonnull [[ARG2]], ptr nonnull [[ARG3]], ptr nonnull [[ARG4]])
+; CHECK-NEXT:    call void @llvm.assume(i1 noundef true) [ "nofree"(ptr [[ARG1]]), "nofree"(ptr [[ARG3]]) ]
+; CHECK-NEXT:    ret void
+;
+  call void @unknown(ptr %arg1, ptr %arg2, ptr %arg3, ptr %arg4)
+  call void @llvm.assume(i1 true) ["nofree"(ptr %arg1), "nofree"(ptr %arg3)]
+  ret void
+}
+define void @nonnull_assume_call(ptr %arg1, ptr %arg2, ptr %arg3, ptr %arg4) {
+; ATTRIBUTOR-LABEL: define {{[^@]+}}@nonnull_assume_call
+; ATTRIBUTOR-SAME: (ptr [[ARG1:%.*]], ptr [[ARG2:%.*]], ptr [[ARG3:%.*]], ptr [[ARG4:%.*]])
+; ATTRIBUTOR-NEXT:    call void @unknown(ptr [[ARG1]], ptr [[ARG2]], ptr [[ARG3]], ptr [[ARG4]])
+; ATTRIBUTOR-NEXT:    call void @use_i8_ptr(ptr noalias readnone [[ARG1]])
+; ATTRIBUTOR-NEXT:    call void @use_i8_ptr(ptr noalias readnone [[ARG2]])
+; ATTRIBUTOR-NEXT:    call void @llvm.assume(i1 true) [ "nofree"(ptr [[ARG1]]), "nofree"(ptr [[ARG3]]) ]
+; ATTRIBUTOR-NEXT:    call void @use_i8_ptr(ptr noalias nofree readnone [[ARG3]])
+; ATTRIBUTOR-NEXT:    call void @use_i8_ptr(ptr noalias readnone [[ARG4]])
+; ATTRIBUTOR-NEXT:    call void @use_i8_ptr_ret(ptr noalias nofree readnone [[ARG1]])
+; ATTRIBUTOR-NEXT:    call void @use_i8_ptr_ret(ptr noalias readnone [[ARG2]])
+; ATTRIBUTOR-NEXT:    call void @llvm.assume(i1 true) [ "nofree"(ptr [[ARG1]]), "nofree"(ptr [[ARG4]]) ]
+; ATTRIBUTOR-NEXT:    call void @use_i8_ptr_ret(ptr noalias nofree readnone [[ARG3]])
+; ATTRIBUTOR-NEXT:    call void @use_i8_ptr_ret(ptr noalias nofree readnone [[ARG4]])
+; ATTRIBUTOR-NEXT:    ret void
+;
+; CHECK-LABEL: define {{[^@]+}}@nonnull_assume_call
+; CHECK-SAME: (ptr nonnull [[ARG1:%.*]], ptr nonnull [[ARG2:%.*]], ptr nonnull [[ARG3:%.*]], ptr nonnull [[ARG4:%.*]]) {
+; CHECK-NEXT:    call void @unknown(ptr nonnull [[ARG1]], ptr nonnull [[ARG2]], ptr nonnull [[ARG3]], ptr nonnull [[ARG4]])
+; CHECK-NEXT:    call void @use_i8_ptr(ptr noalias nocapture nofree nonnull readnone [[ARG1]]) #[[ATTR0]]
+; CHECK-NEXT:    call void @use_i8_ptr(ptr noalias nocapture nofree nonnull readnone [[ARG2]]) #[[ATTR0]]
+; CHECK-NEXT:    call void @llvm.assume(i1 noundef true) [ "nofree"(ptr [[ARG1]]), "nofree"(ptr [[ARG3]]) ]
+; CHECK-NEXT:    call void @use_i8_ptr(ptr noalias nocapture nofree nonnull readnone [[ARG3]]) #[[ATTR0]]
+; CHECK-NEXT:    call void @use_i8_ptr(ptr noalias nocapture nofree nonnull readnone [[ARG4]]) #[[ATTR0]]
+; CHECK-NEXT:    call void @use_i8_ptr_ret(ptr noalias nocapture nofree nonnull readnone [[ARG1]]) #[[ATTR0]]
+; CHECK-NEXT:    call void @use_i8_ptr_ret(ptr noalias nocapture nofree nonnull readnone [[ARG2]]) #[[ATTR0]]
+; CHECK-NEXT:    call void @llvm.assume(i1 noundef true) [ "nofree"(ptr [[ARG1]]), "nofree"(ptr [[ARG4]]) ]
+; CHECK-NEXT:    call void @use_i8_ptr_ret(ptr noalias nocapture nofree nonnull readnone [[ARG3]]) #[[ATTR0]]
+; CHECK-NEXT:    call void @use_i8_ptr_ret(ptr noalias nocapture nofree nonnull readnone [[ARG4]]) #[[ATTR0]]
+; CHECK-NEXT:    ret void
+;
+  call void @unknown(ptr %arg1, ptr %arg2, ptr %arg3, ptr %arg4)
+  call void @use_i8_ptr(ptr %arg1)
+  call void @use_i8_ptr(ptr %arg2)
+  call void @llvm.assume(i1 true) ["nofree"(ptr %arg1), "nofree"(ptr %arg3)]
+  call void @use_i8_ptr(ptr %arg3)
+  call void @use_i8_ptr(ptr %arg4)
+  call void @use_i8_ptr_ret(ptr %arg1)
+  call void @use_i8_ptr_ret(ptr %arg2)
+  call void @llvm.assume(i1 true) ["nofree"(ptr %arg1), "nofree"(ptr %arg4)]
+  call void @use_i8_ptr_ret(ptr %arg3)
+  call void @use_i8_ptr_ret(ptr %arg4)
+  ret void
+}
+
+; FIXME: function is nofree
+define weak void @implied_nofree1() readnone {
+; CHECK: Function Attrs: nosync memory(none)
+; CHECK-LABEL: define {{[^@]+}}@implied_nofree1
+; CHECK-SAME: () #[[ATTR9:[0-9]+]] {
+; CHECK-NEXT:    ret void
+;
+  ret void
+}
+; FIXME: function is nofree
+define weak void @implied_nofree2() readonly {
+; CHECK: Function Attrs: nosync memory(read)
+; CHECK-LABEL: define {{[^@]+}}@implied_nofree2
+; CHECK-SAME: () #[[ATTR10:[0-9]+]] {
+; CHECK-NEXT:    ret void
+;
+  ret void
+}
+define weak void @implied_nofree3(ptr readnone %a) {
+; CHECK-LABEL: define {{[^@]+}}@implied_nofree3
+; CHECK-SAME: (ptr nofree readnone [[A:%.*]]) {
+; CHECK-NEXT:    ret void
+;
+  ret void
+}
+define weak void @implied_nofree4(ptr readonly %a) {
+; CHECK-LABEL: define {{[^@]+}}@implied_nofree4
+; CHECK-SAME: (ptr nofree readonly [[A:%.*]]) {
+; CHECK-NEXT:    ret void
+;
+  ret void
+}
+; FIXME: %a is nofree
+define weak void @implied_nofree5(ptr %a) readonly {
+; CHECK: Function Attrs: nosync memory(read)
+; CHECK-LABEL: define {{[^@]+}}@implied_nofree5
+; CHECK-SAME: (ptr [[A:%.*]]) #[[ATTR10]] {
+; CHECK-NEXT:    ret void
+;
+  ret void
+}
+define weak void @implied_nofree6(ptr %a) nofree {
+; CHECK: Function Attrs: nofree
+; CHECK-LABEL: define {{[^@]+}}@implied_nofree6
+; CHECK-SAME: (ptr nofree [[A:%.*]]) #[[ATTR11:[0-9]+]] {
+; CHECK-NEXT:    ret void
+;
+  ret void
+}
+
+declare void @llvm.assume(i1)
+declare void @unknown(ptr, ptr, ptr, ptr)
+declare void @use_i8_ptr(ptr nocapture readnone) nounwind
+declare void @use_i8_ptr_ret(ptr nocapture readnone) nounwind willreturn
+
+declare noalias ptr @malloc(i64)
+
+attributes #0 = { nounwind uwtable noinline }
+attributes #1 = { nounwind }
+attributes #2 = { nobuiltin nounwind }
+;.
+; TUNIT: attributes #[[ATTR0]] = { nounwind }
+; TUNIT: attributes #[[ATTR1]] = { noinline nounwind uwtable }
+; TUNIT: attributes #[[ATTR2]] = { nobuiltin nounwind }
+; TUNIT: attributes #[[ATTR3]] = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable }
+; TUNIT: attributes #[[ATTR4]] = { mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable }
+; TUNIT: attributes #[[ATTR5:[0-9]+]] = { nofree noinline nounwind memory(none) uwtable }
+; TUNIT: attributes #[[ATTR6:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
+; TUNIT: attributes #[[ATTR7]] = { nofree nounwind }
+; TUNIT: attributes #[[ATTR8]] = { nobuiltin nofree nounwind }
+; TUNIT: attributes #[[ATTR9]] = { nosync memory(none) }
+; TUNIT: attributes #[[ATTR10]] = { nosync memory(read) }
+; TUNIT: attributes #[[ATTR11]] = { nofree }
+; TUNIT: attributes #[[ATTR12:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: write) }
+; TUNIT: attributes #[[ATTR13:[0-9]+]] = { nounwind willreturn }
+; TUNIT: attributes #[[ATTR14]] = { nofree nosync willreturn }
+; TUNIT: attributes #[[ATTR15]] = { nofree willreturn memory(write) }
+;.
+; CGSCC: attributes #[[ATTR0]] = { nounwind }
+; CGSCC: attributes #[[ATTR1]] = { noinline nounwind uwtable }
+; CGSCC: attributes #[[ATTR2]] = { nobuiltin nounwind }
+; CGSCC: attributes #[[ATTR3]] = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable }
+; CGSCC: attributes #[[ATTR4:[0-9]+]] = { nofree noinline nounwind memory(none) uwtable }
+; CGSCC: attributes #[[ATTR5]] = { mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable }
+; CGSCC: attributes #[[ATTR6:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
+; CGSCC: attributes #[[ATTR7]] = { nofree nounwind }
+; CGSCC: attributes #[[ATTR8]] = { nobuiltin nofree nounwind }
+; CGSCC: attributes #[[ATTR9]] = { nosync memory(none) }
+; CGSCC: attributes #[[ATTR10]] = { nosync memory(read) }
+; CGSCC: attributes #[[ATTR11]] = { nofree }
+; CGSCC: attributes #[[ATTR12:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: write) }
+; CGSCC: attributes #[[ATTR13:[0-9]+]] = { nounwind willreturn }
+; CGSCC: attributes #[[ATTR14]] = { nofree nosync willreturn }
+; CGSCC: attributes #[[ATTR15]] = { nofree willreturn memory(write) }
+;.
diff --git a/llvm/test/Transforms/Attributor/read_write_returned_arguments_scc-dl-sentinel.ll b/llvm/test/Transforms/Attributor/read_write_returned_arguments_scc-dl-sentinel.ll
new file mode 100755
index 0000000000000..5c0378ebaa356
--- /dev/null
+++ b/llvm/test/Transforms/Attributor/read_write_returned_arguments_scc-dl-sentinel.ll
@@ -0,0 +1,336 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal  -attributor-annotate-decl-cs  -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal  -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
+
+;
+; This is an evolved example to stress test SCC parameter attribute propagation.
+; The SCC in this test is made up of the following six function, three of which
+; are internal and three externally visible:
+;
+; static int *internal_ret0_nw(int *n0, int *w0);
+; static int *internal_ret1_rw(int *r0, int *w0);
+; static int *internal_ret1_rrw(int *r0, int *r1, int *w0);
+;        int *external_ret2_nrw(int *n0, int *r0, int *w0);
+;        int *external_sink_ret2_nrw(int *n0, int *r0, int *w0);
+;        int *external_source_ret2_nrw(int *n0, int *r0, int *w0);
+;
+; The top four functions call each other while the "sink" function will not
+; call anything and the "source" function will not be called in this module.
+; The names of the functions define the returned parameter (X for "_retX_"),
+; as well as how the parameters are (transitively) used (n = readnone,
+; r = readonly, w = writeonly).
+;
+; What we should see is something along the lines of:
+;   1 - Number of functions marked as norecurse
+;   6 - Number of functions marked argmemonly
+;   6 - Number of functions marked as nounwind
+;  16 - Number of arguments marked nocapture
+;   4 - Number of arguments marked readnone
+;   6 - Number of arguments marked writeonly
+;   6 - Number of arguments marked readonly
+;   6 - Number of arguments marked returned
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-z0:1-z2:neg1-z3:neg1-z5:neg1-S128"
+
+define ptr @external_ret2_nrw(ptr %n0, ptr %r0, ptr %w0) {
+; TUNIT: Function Attrs: nofree nosync nounwind memory(argmem: readwrite)
+; TUNIT-LABEL: define {{[^@]+}}@external_ret2_nrw
+; TUNIT-SAME: (ptr nocapture nofree nonnull readnone [[N0:%.*]], ptr nocapture nofree nonnull readonly [[R0:%.*]], ptr nofree nonnull returned writeonly "no-capture-maybe-returned" [[W0:%.*]]) #[[ATTR0:[0-9]+]] {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    [[CALL:%.*]] = call ptr @internal_ret0_nw(ptr nocapture nofree nonnull writeonly [[W0]]) #[[ATTR4:[0-9]+]]
+; TUNIT-NEXT:    unreachable
+;
+; CGSCC: Function Attrs: nofree nosync nounwind memory(argmem: readwrite)
+; CGSCC-LABEL: define {{[^@]+}}@external_ret2_nrw
+; CGSCC-SAME: (ptr nocapture nofree nonnull readnone [[N0:%.*]], ptr nocapture nofree nonnull readonly [[R0:%.*]], ptr nofree nonnull returned [[W0:%.*]]) #[[ATTR0:[0-9]+]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    [[CALL:%.*]] = call ptr @internal_ret0_nw(ptr noalias nocapture nofree nonnull readnone [[N0]], ptr nofree nonnull [[W0]]) #[[ATTR3:[0-9]+]]
+; CGSCC-NEXT:    unreachable
+;
+entry:
+  %call = call ptr @internal_ret0_nw(ptr %n0, ptr %w0)
+  %call1 = call ptr @internal_ret1_rrw(ptr %r0, ptr %r0, ptr %w0)
+  %call2 = call ptr @external_sink_ret2_nrw(ptr %n0, ptr %r0, ptr %w0)
+  %call3 = call ptr @internal_ret1_rw(ptr %r0, ptr %w0)
+  ret ptr %call3
+}
+
+define internal ptr @internal_ret0_nw(ptr %n0, ptr %w0) {
+; TUNIT: Function Attrs: nofree noreturn nosync nounwind memory(argmem: readwrite)
+; TUNIT-LABEL: define {{[^@]+}}@internal_ret0_nw
+; TUNIT-SAME: (ptr nocapture nofree nonnull writeonly [[W0:%.*]]) #[[ATTR1:[0-9]+]] {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    [[R0:%.*]] = alloca i32, align 4
+; TUNIT-NEXT:    [[R1:%.*]] = alloca i32, align 4
+; TUNIT-NEXT:    br label [[IF_END:%.*]]
+; TUNIT:       if.then:
+; TUNIT-NEXT:    unreachable
+; TUNIT:       if.end:
+; TUNIT-NEXT:    store i32 3, ptr [[R0]], align 4
+; TUNIT-NEXT:    store i32 5, ptr [[R1]], align 4
+; TUNIT-NEXT:    store i32 1, ptr [[W0]], align 4
+; TUNIT-NEXT:    [[CALL:%.*]] = call ptr @internal_ret1_rrw(ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0]], ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R1]], ptr nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[W0]]) #[[ATTR5:[0-9]+]]
+; TUNIT-NEXT:    [[CALL1:%.*]] = call ptr @external_ret2_nrw(ptr noalias nocapture nofree nonnull readnone undef, ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0]], ptr nofree nonnull writeonly align 4 dereferenceable(4) "no-capture-maybe-returned" [[W0]]) #[[ATTR5]]
+; TUNIT-NEXT:    [[CALL2:%.*]] = call ptr @external_ret2_nrw(ptr noalias nocapture nofree nonnull readnone undef, ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R1]], ptr nofree nonnull writeonly align 4 dereferenceable(4) "no-capture-maybe-returned" [[W0]]) #[[ATTR5]]
+; TUNIT-NEXT:    [[CALL3:%.*]] = call ptr @external_sink_ret2_nrw(ptr noalias nocapture nofree nonnull readnone undef, ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0]], ptr nofree nonnull writeonly align 4 dereferenceable(4) "no-capture-maybe-returned" [[W0]]) #[[ATTR5]]
+; TUNIT-NEXT:    [[CALL4:%.*]] = call ptr @external_sink_ret2_nrw(ptr noalias nocapture nofree nonnull readnone undef, ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R1]], ptr nofree nonnull writeonly align 4 dereferenceable(4) "no-capture-maybe-returned" [[W0]]) #[[ATTR5]]
+; TUNIT-NEXT:    [[CALL5:%.*]] = call ptr @internal_ret0_nw(ptr nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[W0]]) #[[ATTR4]]
+; TUNIT-NEXT:    unreachable
+; TUNIT:       return:
+; TUNIT-NEXT:    unreachable
+;
+; CGSCC: Function Attrs: nofree noreturn nosync nounwind memory(argmem: readwrite)
+; CGSCC-LABEL: define {{[^@]+}}@internal_ret0_nw
+; CGSCC-SAME: (ptr noalias nocapture nofree nonnull readnone [[N0:%.*]], ptr nofree nonnull [[W0:%.*]]) #[[ATTR1:[0-9]+]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    [[R0:%.*]] = alloca i32, align 4
+; CGSCC-NEXT:    [[R1:%.*]] = alloca i32, align 4
+; CGSCC-NEXT:    br label [[IF_END:%.*]]
+; CGSCC:       if.then:
+; CGSCC-NEXT:    unreachable
+; CGSCC:       if.end:
+; CGSCC-NEXT:    store i32 3, ptr [[R0]], align 4
+; CGSCC-NEXT:    store i32 5, ptr [[R1]], align 4
+; CGSCC-NEXT:    store i32 1, ptr [[W0]], align 4
+; CGSCC-NEXT:    [[CALL:%.*]] = call ptr @internal_ret1_rrw(ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0]], ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R1]], ptr nofree nonnull align 4 dereferenceable(4) [[W0]]) #[[ATTR4:[0-9]+]]
+; CGSCC-NEXT:    [[CALL1:%.*]] = call ptr @external_ret2_nrw(ptr noalias nocapture nofree nonnull readnone [[N0]], ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0]], ptr nofree nonnull align 4 dereferenceable(4) [[W0]]) #[[ATTR4]]
+; CGSCC-NEXT:    [[CALL2:%.*]] = call ptr @external_ret2_nrw(ptr noalias nocapture nofree nonnull readnone [[N0]], ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R1]], ptr nofree nonnull align 4 dereferenceable(4) [[W0]]) #[[ATTR4]]
+; CGSCC-NEXT:    [[CALL3:%.*]] = call ptr @external_sink_ret2_nrw(ptr noalias nocapture nofree nonnull readnone [[N0]], ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0]], ptr nofree nonnull writeonly align 4 dereferenceable(4) [[W0]]) #[[ATTR5:[0-9]+]]
+; CGSCC-NEXT:    [[CALL4:%.*]] = call ptr @external_sink_ret2_nrw(ptr noalias nocapture nofree nonnull readnone [[N0]], ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R1]], ptr nofree nonnull writeonly align 4 dereferenceable(4) [[W0]]) #[[ATTR5]]
+; CGSCC-NEXT:    [[CALL5:%.*]] = call ptr @internal_ret0_nw(ptr noalias nocapture nofree nonnull readnone [[N0]], ptr nofree nonnull align 4 dereferenceable(4) [[W0]]) #[[ATTR3]]
+; CGSCC-NEXT:    unreachable
+; CGSCC:       return:
+; CGSCC-NEXT:    unreachable
+;
+entry:
+  %r0 = alloca i32, align 4
+  %r1 = alloca i32, align 4
+  %tobool = icmp ne ptr %n0, null
+  br i1 %tobool, label %if.end, label %if.then
+
+if.then:                                          ; preds = %entry
+  br label %return
+
+if.end:                                           ; preds = %entry
+  store i32 3, ptr %r0, align 4
+  store i32 5, ptr %r1, align 4
+  store i32 1, ptr %w0, align 4
+  %call = call ptr @internal_ret1_rrw(ptr %r0, ptr %r1, ptr %w0)
+  %call1 = call ptr @external_ret2_nrw(ptr %n0, ptr %r0, ptr %w0)
+  %call2 = call ptr @external_ret2_nrw(ptr %n0, ptr %r1, ptr %w0)
+  %call3 = call ptr @external_sink_ret2_nrw(ptr %n0, ptr %r0, ptr %w0)
+  %call4 = call ptr @external_sink_ret2_nrw(ptr %n0, ptr %r1, ptr %w0)
+  %call5 = call ptr @internal_ret0_nw(ptr %n0, ptr %w0)
+  br label %return
+
+return:                                           ; preds = %if.end, %if.then
+  %retval.0 = phi ptr [ %call5, %if.end ], [ %n0, %if.then ]
+  ret ptr %retval.0
+}
+
+define internal ptr @internal_ret1_rrw(ptr %r0, ptr %r1, ptr %w0) {
+; TUNIT: Function Attrs: nofree nosync nounwind memory(argmem: readwrite)
+; TUNIT-LABEL: define {{[^@]+}}@internal_ret1_rrw
+; TUNIT-SAME: (ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0:%.*]], ptr nocapture nofree nonnull readonly align 4 [[R1:%.*]], ptr nocapture nofree nonnull writeonly [[W0:%.*]]) #[[ATTR0]] {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    [[TMP0:%.*]] = load i32, ptr [[R0]], align 4
+; TUNIT-NEXT:    [[TOBOOL:%.*]] = icmp ne i32 [[TMP0]], 0
+; TUNIT-NEXT:    br i1 [[TOBOOL]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]
+; TUNIT:       if.then:
+; TUNIT-NEXT:    br label [[RETURN:%.*]]
+; TUNIT:       if.end:
+; TUNIT-NEXT:    [[CALL:%.*]] = call ptr @internal_ret1_rw(ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0]], ptr nofree nonnull writeonly "no-capture-maybe-returned" [[W0]]) #[[ATTR5]]
+; TUNIT-NEXT:    [[TMP1:%.*]] = load i32, ptr [[R0]], align 4
+; TUNIT-NEXT:    [[TMP2:%.*]] = load i32, ptr [[R1]], align 4
+; TUNIT-NEXT:    [[ADD:%.*]] = add nsw i32 [[TMP1]], [[TMP2]]
+; TUNIT-NEXT:    store i32 [[ADD]], ptr [[W0]], align 4
+; TUNIT-NEXT:    [[CALL1:%.*]] = call ptr @internal_ret1_rw(ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R1]], ptr nofree nonnull writeonly align 4 dereferenceable(4) "no-capture-maybe-returned" [[W0]]) #[[ATTR5]]
+; TUNIT-NEXT:    [[CALL2:%.*]] = call ptr @internal_ret0_nw(ptr nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[W0]]) #[[ATTR4]]
+; TUNIT-NEXT:    unreachable
+; TUNIT:       return:
+; TUNIT-NEXT:    ret ptr undef
+;
+; CGSCC: Function Attrs: nofree nosync nounwind memory(argmem: readwrite)
+; CGSCC-LABEL: define {{[^@]+}}@internal_ret1_rrw
+; CGSCC-SAME: (ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0:%.*]], ptr nocapture nofree nonnull readonly align 4 [[R1:%.*]], ptr nofree nonnull [[W0:%.*]]) #[[ATTR0]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    [[TMP0:%.*]] = load i32, ptr [[R0]], align 4
+; CGSCC-NEXT:    [[TOBOOL:%.*]] = icmp ne i32 [[TMP0]], 0
+; CGSCC-NEXT:    br i1 [[TOBOOL]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]
+; CGSCC:       if.then:
+; CGSCC-NEXT:    br label [[RETURN:%.*]]
+; CGSCC:       if.end:
+; CGSCC-NEXT:    [[CALL:%.*]] = call ptr @internal_ret1_rw(ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0]], ptr nofree nonnull [[W0]]) #[[ATTR4]]
+; CGSCC-NEXT:    [[TMP1:%.*]] = load i32, ptr [[R0]], align 4
+; CGSCC-NEXT:    [[TMP2:%.*]] = load i32, ptr [[R1]], align 4
+; CGSCC-NEXT:    [[ADD:%.*]] = add nsw i32 [[TMP1]], [[TMP2]]
+; CGSCC-NEXT:    store i32 [[ADD]], ptr [[W0]], align 4
+; CGSCC-NEXT:    [[CALL1:%.*]] = call ptr @internal_ret1_rw(ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R1]], ptr nofree nonnull align 4 dereferenceable(4) [[W0]]) #[[ATTR4]]
+; CGSCC-NEXT:    [[CALL2:%.*]] = call ptr @internal_ret0_nw(ptr noalias nocapture nofree noundef nonnull readnone align 4 dereferenceable(4) [[R0]], ptr nofree nonnull align 4 dereferenceable(4) [[W0]]) #[[ATTR3]]
+; CGSCC-NEXT:    unreachable
+; CGSCC:       return:
+; CGSCC-NEXT:    ret ptr undef
+;
+entry:
+  %0 = load i32, ptr %r0, align 4
+  %tobool = icmp ne i32 %0, 0
+  br i1 %tobool, label %if.end, label %if.then
+
+if.then:                                          ; preds = %entry
+  br label %return
+
+if.end:                                           ; preds = %entry
+  %call = call ptr @internal_ret1_rw(ptr %r0, ptr %w0)
+  %1 = load i32, ptr %r0, align 4
+  %2 = load i32, ptr %r1, align 4
+  %add = add nsw i32 %1, %2
+  store i32 %add, ptr %w0, align 4
+  %call1 = call ptr @internal_ret1_rw(ptr %r1, ptr %w0)
+  %call2 = call ptr @internal_ret0_nw(ptr %r0, ptr %w0)
+  %call3 = call ptr @internal_ret0_nw(ptr %w0, ptr %w0)
+  %call4 = call ptr @external_ret2_nrw(ptr %r0, ptr %r1, ptr %w0)
+  %call5 = call ptr @external_ret2_nrw(ptr %r1, ptr %r0, ptr %w0)
+  %call6 = call ptr @external_sink_ret2_nrw(ptr %r0, ptr %r1, ptr %w0)
+  %call7 = call ptr @external_sink_ret2_nrw(ptr %r1, ptr %r0, ptr %w0)
+  %call8 = call ptr @internal_ret0_nw(ptr %r1, ptr %w0)
+  br label %return
+
+return:                                           ; preds = %if.end, %if.then
+  %retval.0 = phi ptr [ %call8, %if.end ], [ %r1, %if.then ]
+  ret ptr %retval.0
+}
+
+define ptr @external_sink_ret2_nrw(ptr %n0, ptr %r0, ptr %w0) {
+; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite)
+; CHECK-LABEL: define {{[^@]+}}@external_sink_ret2_nrw
+; CHECK-SAME: (ptr nocapture nofree nonnull readnone [[N0:%.*]], ptr nocapture nofree nonnull readonly [[R0:%.*]], ptr nofree nonnull returned writeonly "no-capture-maybe-returned" [[W0:%.*]]) #[[ATTR2:[0-9]+]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[IF_END:%.*]]
+; CHECK:       if.then:
+; CHECK-NEXT:    unreachable
+; CHECK:       if.end:
+; CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr [[R0]], align 4
+; CHECK-NEXT:    store i32 [[TMP0]], ptr [[W0]], align 4
+; CHECK-NEXT:    br label [[RETURN:%.*]]
+; CHECK:       return:
+; CHECK-NEXT:    ret ptr [[W0]]
+;
+entry:
+  %tobool = icmp ne ptr %n0, null
+  br i1 %tobool, label %if.end, label %if.then
+
+if.then:                                          ; preds = %entry
+  br label %return
+
+if.end:                                           ; preds = %entry
+  %0 = load i32, ptr %r0, align 4
+  store i32 %0, ptr %w0, align 4
+  br label %return
+
+return:                                           ; preds = %if.end, %if.then
+  ret ptr %w0
+}
+
+define internal ptr @internal_ret1_rw(ptr %r0, ptr %w0) {
+; TUNIT: Function Attrs: nofree nosync nounwind memory(argmem: readwrite)
+; TUNIT-LABEL: define {{[^@]+}}@internal_ret1_rw
+; TUNIT-SAME: (ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0:%.*]], ptr nofree nonnull returned writeonly "no-capture-maybe-returned" [[W0:%.*]]) #[[ATTR0]] {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    [[TMP0:%.*]] = load i32, ptr [[R0]], align 4
+; TUNIT-NEXT:    [[TOBOOL:%.*]] = icmp ne i32 [[TMP0]], 0
+; TUNIT-NEXT:    br i1 [[TOBOOL]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]
+; TUNIT:       if.then:
+; TUNIT-NEXT:    br label [[RETURN:%.*]]
+; TUNIT:       if.end:
+; TUNIT-NEXT:    [[CALL:%.*]] = call ptr @internal_ret1_rrw(ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0]], ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0]], ptr nocapture nofree nonnull writeonly [[W0]]) #[[ATTR5]]
+; TUNIT-NEXT:    [[TMP1:%.*]] = load i32, ptr [[R0]], align 4
+; TUNIT-NEXT:    store i32 [[TMP1]], ptr [[W0]], align 4
+; TUNIT-NEXT:    [[CALL1:%.*]] = call ptr @internal_ret0_nw(ptr nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[W0]]) #[[ATTR4]]
+; TUNIT-NEXT:    unreachable
+; TUNIT:       return:
+; TUNIT-NEXT:    ret ptr [[W0]]
+;
+; CGSCC: Function Attrs: nofree nosync nounwind memory(argmem: readwrite)
+; CGSCC-LABEL: define {{[^@]+}}@internal_ret1_rw
+; CGSCC-SAME: (ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0:%.*]], ptr nofree nonnull returned [[W0:%.*]]) #[[ATTR0]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    [[TMP0:%.*]] = load i32, ptr [[R0]], align 4
+; CGSCC-NEXT:    [[TOBOOL:%.*]] = icmp ne i32 [[TMP0]], 0
+; CGSCC-NEXT:    br i1 [[TOBOOL]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]
+; CGSCC:       if.then:
+; CGSCC-NEXT:    br label [[RETURN:%.*]]
+; CGSCC:       if.end:
+; CGSCC-NEXT:    [[CALL:%.*]] = call ptr @internal_ret1_rrw(ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0]], ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0]], ptr nofree nonnull [[W0]]) #[[ATTR4]]
+; CGSCC-NEXT:    [[TMP1:%.*]] = load i32, ptr [[R0]], align 4
+; CGSCC-NEXT:    store i32 [[TMP1]], ptr [[W0]], align 4
+; CGSCC-NEXT:    [[CALL1:%.*]] = call ptr @internal_ret0_nw(ptr noalias nocapture nofree noundef nonnull readnone align 4 dereferenceable(4) [[R0]], ptr nofree nonnull align 4 dereferenceable(4) [[W0]]) #[[ATTR3]]
+; CGSCC-NEXT:    unreachable
+; CGSCC:       return:
+; CGSCC-NEXT:    ret ptr [[W0]]
+;
+entry:
+  %0 = load i32, ptr %r0, align 4
+  %tobool = icmp ne i32 %0, 0
+  br i1 %tobool, label %if.end, label %if.then
+
+if.then:                                          ; preds = %entry
+  br label %return
+
+if.end:                                           ; preds = %entry
+  %call = call ptr @internal_ret1_rrw(ptr %r0, ptr %r0, ptr %w0)
+  %1 = load i32, ptr %r0, align 4
+  store i32 %1, ptr %w0, align 4
+  %call1 = call ptr @internal_ret0_nw(ptr %r0, ptr %w0)
+  %call2 = call ptr @internal_ret0_nw(ptr %w0, ptr %w0)
+  %call3 = call ptr @external_sink_ret2_nrw(ptr %r0, ptr %r0, ptr %w0)
+  %call4 = call ptr @external_ret2_nrw(ptr %r0, ptr %r0, ptr %w0)
+  br label %return
+
+return:                                           ; preds = %if.end, %if.then
+  %retval.0 = phi ptr [ %call4, %if.end ], [ %w0, %if.then ]
+  ret ptr %retval.0
+}
+
+define ptr @external_source_ret2_nrw(ptr %n0, ptr %r0, ptr %w0) {
+; TUNIT: Function Attrs: nofree norecurse nosync nounwind memory(argmem: readwrite)
+; TUNIT-LABEL: define {{[^@]+}}@external_source_ret2_nrw
+; TUNIT-SAME: (ptr nocapture nofree nonnull readnone [[N0:%.*]], ptr nocapture nofree nonnull readonly [[R0:%.*]], ptr nofree nonnull returned writeonly "no-capture-maybe-returned" [[W0:%.*]]) #[[ATTR3:[0-9]+]] {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    [[CALL:%.*]] = call ptr @external_sink_ret2_nrw(ptr noalias nocapture nofree nonnull readnone undef, ptr nocapture nofree nonnull readonly [[R0]], ptr nofree nonnull writeonly "no-capture-maybe-returned" [[W0]]) #[[ATTR6:[0-9]+]]
+; TUNIT-NEXT:    [[CALL1:%.*]] = call ptr @external_ret2_nrw(ptr noalias nocapture nofree nonnull readnone undef, ptr nocapture nofree nonnull readonly [[R0]], ptr nofree nonnull writeonly "no-capture-maybe-returned" [[W0]]) #[[ATTR5]]
+; TUNIT-NEXT:    ret ptr [[W0]]
+;
+; CGSCC: Function Attrs: nofree nosync nounwind memory(argmem: readwrite)
+; CGSCC-LABEL: define {{[^@]+}}@external_source_ret2_nrw
+; CGSCC-SAME: (ptr nocapture nofree nonnull readnone [[N0:%.*]], ptr nocapture nofree nonnull readonly align 4 [[R0:%.*]], ptr nofree nonnull align 4 [[W0:%.*]]) #[[ATTR0]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    [[CALL:%.*]] = call ptr @external_sink_ret2_nrw(ptr noalias nocapture nofree nonnull readnone [[N0]], ptr nocapture nofree nonnull readonly align 4 [[R0]], ptr nofree nonnull writeonly align 4 [[W0]]) #[[ATTR6:[0-9]+]]
+; CGSCC-NEXT:    [[CALL1:%.*]] = call nonnull ptr @external_ret2_nrw(ptr noalias nocapture nofree nonnull readnone [[N0]], ptr nocapture nofree nonnull readonly align 4 [[R0]], ptr nofree nonnull align 4 [[W0]]) #[[ATTR7:[0-9]+]]
+; CGSCC-NEXT:    ret ptr [[CALL1]]
+;
+entry:
+  %call = call ptr @external_sink_ret2_nrw(ptr %n0, ptr %r0, ptr %w0)
+  %call1 = call ptr @external_ret2_nrw(ptr %n0, ptr %r0, ptr %w0)
+  ret ptr %call1
+}
+
+; Verify that we see only expected attribute sets, the above lines only check
+; for a subset relation.
+;.
+; TUNIT: attributes #[[ATTR0]] = { nofree nosync nounwind memory(argmem: readwrite) }
+; TUNIT: attributes #[[ATTR1]] = { nofree noreturn nosync nounwind memory(argmem: readwrite) }
+; TUNIT: attributes #[[ATTR2]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) }
+; TUNIT: attributes #[[ATTR3]] = { nofree norecurse nosync nounwind memory(argmem: readwrite) }
+; TUNIT: attributes #[[ATTR4]] = { nofree noreturn nosync nounwind }
+; TUNIT: attributes #[[ATTR5]] = { nofree nosync nounwind }
+; TUNIT: attributes #[[ATTR6]] = { nofree nosync nounwind willreturn }
+;.
+; CGSCC: attributes #[[ATTR0]] = { nofree nosync nounwind memory(argmem: readwrite) }
+; CGSCC: attributes #[[ATTR1]] = { nofree noreturn nosync nounwind memory(argmem: readwrite) }
+; CGSCC: attributes #[[ATTR2]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) }
+; CGSCC: attributes #[[ATTR3]] = { nofree noreturn nosync nounwind }
+; CGSCC: attributes #[[ATTR4]] = { nofree nosync nounwind }
+; CGSCC: attributes #[[ATTR5]] = { nofree nounwind memory(readwrite) }
+; CGSCC: attributes #[[ATTR6]] = { nofree nounwind willreturn }
+; CGSCC: attributes #[[ATTR7]] = { nofree nounwind }
+;.
diff --git a/llvm/test/Transforms/Attributor/returned-dl-sentinel.ll b/llvm/test/Transforms/Attributor/returned-dl-sentinel.ll
new file mode 100755
index 0000000000000..70e203f83542b
--- /dev/null
+++ b/llvm/test/Transforms/Attributor/returned-dl-sentinel.ll
@@ -0,0 +1,1421 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal  -attributor-annotate-decl-cs  -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal  -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
+;
+; Test cases specifically designed for the "returned" argument attribute.
+; We use FIXME's to indicate problems and missing attributes.
+;
+
+; TEST SCC test returning an integer value argument
+;
+; int scc_r1(int a, int b, int r);
+; int scc_r2(int a, int b, int r);
+;
+; __attribute__((noinline)) int sink_r0(int r) {
+;   return r;
+; }
+;
+; __attribute__((noinline)) int scc_r1(int a, int r, int b) {
+;   return scc_r2(r, a, sink_r0(r));
+; }
+;
+; __attribute__((noinline)) int scc_r2(int a, int b, int r) {
+;   if (a > b)
+;     return scc_r2(b, a, sink_r0(r));
+;   if (a < b)
+;     return scc_r1(sink_r0(b), scc_r2(scc_r1(a, b, r), scc_r1(a, scc_r2(r, r, r), r), scc_r2(a, b, r)), scc_r1(a, b, r));
+;   return a == b ? r : scc_r2(a, b, r);
+; }
+; __attribute__((noinline)) int scc_rX(int a, int b, int r) {
+;   if (a > b)
+;     return scc_r2(b, a, sink_r0(r));
+;   if (a < b)                                                                         // V Diff to scc_r2
+;     return scc_r1(sink_r0(b), scc_r2(scc_r1(a, b, r), scc_r1(a, scc_r2(r, r, r), r), scc_r1(a, b, r)), scc_r1(a, b, r));
+;   return a == b ? r : scc_r2(a, b, r);
+; }
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-z0:1-z2:neg1-z3:neg1-z5:neg1-S128"
+
+;.
+; CHECK: @G = external global i8
+; CHECK: @_ZTI1X = external dso_local constant { ptr, ptr }, align 8
+; CHECK: @_ZTI1Y = external dso_local constant { ptr, ptr, ptr }, align 8
+;.
+define i32 @sink_r0(i32 %r) #0 {
+; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
+; CHECK-LABEL: define {{[^@]+}}@sink_r0
+; CHECK-SAME: (i32 returned [[R:%.*]]) #[[ATTR0:[0-9]+]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    ret i32 [[R]]
+;
+entry:
+  ret i32 %r
+}
+
+define i32 @scc_r1(i32 %a, i32 %r, i32 %b) #0 {
+; TUNIT: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
+; TUNIT-LABEL: define {{[^@]+}}@scc_r1
+; TUNIT-SAME: (i32 [[A:%.*]], i32 returned [[R:%.*]], i32 [[B:%.*]]) #[[ATTR1:[0-9]+]] {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    [[CALL1:%.*]] = call i32 @scc_r2(i32 [[R]], i32 [[A]], i32 [[R]]) #[[ATTR8:[0-9]+]]
+; TUNIT-NEXT:    ret i32 [[R]]
+;
+; CGSCC: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
+; CGSCC-LABEL: define {{[^@]+}}@scc_r1
+; CGSCC-SAME: (i32 [[A:%.*]], i32 returned [[R:%.*]], i32 [[B:%.*]]) #[[ATTR1:[0-9]+]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    [[CALL1:%.*]] = call i32 @scc_r2(i32 [[R]], i32 [[A]], i32 [[R]]) #[[ATTR7:[0-9]+]]
+; CGSCC-NEXT:    ret i32 [[R]]
+;
+entry:
+  %call = call i32 @sink_r0(i32 %r)
+  %call1 = call i32 @scc_r2(i32 %r, i32 %a, i32 %call)
+  ret i32 %call1
+}
+
+define i32 @scc_r2(i32 %a, i32 %b, i32 %r) #0 {
+; TUNIT: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
+; TUNIT-LABEL: define {{[^@]+}}@scc_r2
+; TUNIT-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 returned [[R:%.*]]) #[[ATTR1]] {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[A]], [[B]]
+; TUNIT-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
+; TUNIT:       if.then:
+; TUNIT-NEXT:    [[CALL1:%.*]] = call i32 @scc_r2(i32 [[B]], i32 [[A]], i32 [[R]]) #[[ATTR8]]
+; TUNIT-NEXT:    br label [[RETURN:%.*]]
+; TUNIT:       if.end:
+; TUNIT-NEXT:    [[CMP2:%.*]] = icmp slt i32 [[A]], [[B]]
+; TUNIT-NEXT:    br i1 [[CMP2]], label [[IF_THEN3:%.*]], label [[IF_END12:%.*]]
+; TUNIT:       if.then3:
+; TUNIT-NEXT:    [[CALL5:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[B]], i32 undef) #[[ATTR8]]
+; TUNIT-NEXT:    [[CALL6:%.*]] = call i32 @scc_r2(i32 [[R]], i32 [[R]], i32 [[R]]) #[[ATTR8]]
+; TUNIT-NEXT:    [[CALL7:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[R]], i32 undef) #[[ATTR8]]
+; TUNIT-NEXT:    [[CALL8:%.*]] = call i32 @scc_r2(i32 [[A]], i32 [[B]], i32 [[R]]) #[[ATTR8]]
+; TUNIT-NEXT:    [[CALL9:%.*]] = call i32 @scc_r2(i32 [[B]], i32 [[R]], i32 [[R]]) #[[ATTR8]]
+; TUNIT-NEXT:    [[CALL11:%.*]] = call i32 @scc_r1(i32 [[B]], i32 [[R]], i32 undef) #[[ATTR8]]
+; TUNIT-NEXT:    br label [[RETURN]]
+; TUNIT:       if.end12:
+; TUNIT-NEXT:    [[CMP13:%.*]] = icmp eq i32 [[A]], [[B]]
+; TUNIT-NEXT:    br i1 [[CMP13]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
+; TUNIT:       cond.true:
+; TUNIT-NEXT:    br label [[COND_END:%.*]]
+; TUNIT:       cond.false:
+; TUNIT-NEXT:    [[CALL14:%.*]] = call i32 @scc_r2(i32 [[A]], i32 [[B]], i32 [[R]]) #[[ATTR8]]
+; TUNIT-NEXT:    br label [[COND_END]]
+; TUNIT:       cond.end:
+; TUNIT-NEXT:    [[COND:%.*]] = phi i32 [ [[R]], [[COND_TRUE]] ], [ [[R]], [[COND_FALSE]] ]
+; TUNIT-NEXT:    br label [[RETURN]]
+; TUNIT:       return:
+; TUNIT-NEXT:    [[RETVAL_0:%.*]] = phi i32 [ [[R]], [[IF_THEN]] ], [ [[R]], [[IF_THEN3]] ], [ [[R]], [[COND_END]] ]
+; TUNIT-NEXT:    ret i32 [[R]]
+;
+; CGSCC: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
+; CGSCC-LABEL: define {{[^@]+}}@scc_r2
+; CGSCC-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 returned [[R:%.*]]) #[[ATTR1]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[A]], [[B]]
+; CGSCC-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
+; CGSCC:       if.then:
+; CGSCC-NEXT:    [[CALL1:%.*]] = call i32 @scc_r2(i32 [[B]], i32 [[A]], i32 [[R]]) #[[ATTR7]]
+; CGSCC-NEXT:    br label [[RETURN:%.*]]
+; CGSCC:       if.end:
+; CGSCC-NEXT:    [[CMP2:%.*]] = icmp slt i32 [[A]], [[B]]
+; CGSCC-NEXT:    br i1 [[CMP2]], label [[IF_THEN3:%.*]], label [[IF_END12:%.*]]
+; CGSCC:       if.then3:
+; CGSCC-NEXT:    [[CALL5:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[B]], i32 undef) #[[ATTR7]]
+; CGSCC-NEXT:    [[CALL6:%.*]] = call i32 @scc_r2(i32 [[R]], i32 [[R]], i32 [[R]]) #[[ATTR7]]
+; CGSCC-NEXT:    [[CALL7:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[R]], i32 undef) #[[ATTR7]]
+; CGSCC-NEXT:    [[CALL8:%.*]] = call i32 @scc_r2(i32 [[A]], i32 [[B]], i32 [[R]]) #[[ATTR7]]
+; CGSCC-NEXT:    [[CALL9:%.*]] = call i32 @scc_r2(i32 [[B]], i32 [[R]], i32 [[R]]) #[[ATTR7]]
+; CGSCC-NEXT:    [[CALL11:%.*]] = call i32 @scc_r1(i32 [[B]], i32 [[R]], i32 undef) #[[ATTR7]]
+; CGSCC-NEXT:    br label [[RETURN]]
+; CGSCC:       if.end12:
+; CGSCC-NEXT:    [[CMP13:%.*]] = icmp eq i32 [[A]], [[B]]
+; CGSCC-NEXT:    br i1 [[CMP13]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
+; CGSCC:       cond.true:
+; CGSCC-NEXT:    br label [[COND_END:%.*]]
+; CGSCC:       cond.false:
+; CGSCC-NEXT:    [[CALL14:%.*]] = call i32 @scc_r2(i32 [[A]], i32 [[B]], i32 [[R]]) #[[ATTR7]]
+; CGSCC-NEXT:    br label [[COND_END]]
+; CGSCC:       cond.end:
+; CGSCC-NEXT:    [[COND:%.*]] = phi i32 [ [[R]], [[COND_TRUE]] ], [ [[R]], [[COND_FALSE]] ]
+; CGSCC-NEXT:    br label [[RETURN]]
+; CGSCC:       return:
+; CGSCC-NEXT:    [[RETVAL_0:%.*]] = phi i32 [ [[R]], [[IF_THEN]] ], [ [[R]], [[IF_THEN3]] ], [ [[R]], [[COND_END]] ]
+; CGSCC-NEXT:    ret i32 [[R]]
+;
+entry:
+  %cmp = icmp sgt i32 %a, %b
+  br i1 %cmp, label %if.then, label %if.end
+
+if.then:                                          ; preds = %entry
+  %call = call i32 @sink_r0(i32 %r)
+  %call1 = call i32 @scc_r2(i32 %b, i32 %a, i32 %call)
+  br label %return
+
+if.end:                                           ; preds = %entry
+  %cmp2 = icmp slt i32 %a, %b
+  br i1 %cmp2, label %if.then3, label %if.end12
+
+if.then3:                                         ; preds = %if.end
+  %call4 = call i32 @sink_r0(i32 %b)
+  %call5 = call i32 @scc_r1(i32 %a, i32 %b, i32 %r)
+  %call6 = call i32 @scc_r2(i32 %r, i32 %r, i32 %r)
+  %call7 = call i32 @scc_r1(i32 %a, i32 %call6, i32 %r)
+  %call8 = call i32 @scc_r2(i32 %a, i32 %b, i32 %r)
+  %call9 = call i32 @scc_r2(i32 %call5, i32 %call7, i32 %call8)
+  %call10 = call i32 @scc_r1(i32 %a, i32 %b, i32 %r)
+  %call11 = call i32 @scc_r1(i32 %call4, i32 %call9, i32 %call10)
+  br label %return
+
+if.end12:                                         ; preds = %if.end
+  %cmp13 = icmp eq i32 %a, %b
+  br i1 %cmp13, label %cond.true, label %cond.false
+
+cond.true:                                        ; preds = %if.end12
+  br label %cond.end
+
+cond.false:                                       ; preds = %if.end12
+  %call14 = call i32 @scc_r2(i32 %a, i32 %b, i32 %r)
+  br label %cond.end
+
+cond.end:                                         ; preds = %cond.false, %cond.true
+  %cond = phi i32 [ %r, %cond.true ], [ %call14, %cond.false ]
+  br label %return
+
+return:                                           ; preds = %cond.end, %if.then3, %if.then
+  %retval.0 = phi i32 [ %call1, %if.then ], [ %call11, %if.then3 ], [ %cond, %cond.end ]
+  ret i32 %retval.0
+}
+
+define i32 @scc_rX(i32 %a, i32 %b, i32 %r) #0 {
+; TUNIT: Function Attrs: nofree noinline norecurse nosync nounwind memory(none) uwtable
+; TUNIT-LABEL: define {{[^@]+}}@scc_rX
+; TUNIT-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[R:%.*]]) #[[ATTR2:[0-9]+]] {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[A]], [[B]]
+; TUNIT-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
+; TUNIT:       if.then:
+; TUNIT-NEXT:    [[CALL1:%.*]] = call i32 @scc_r2(i32 [[B]], i32 [[A]], i32 [[R]]) #[[ATTR8]]
+; TUNIT-NEXT:    br label [[RETURN:%.*]]
+; TUNIT:       if.end:
+; TUNIT-NEXT:    [[CMP2:%.*]] = icmp slt i32 [[A]], [[B]]
+; TUNIT-NEXT:    br i1 [[CMP2]], label [[IF_THEN3:%.*]], label [[IF_END12:%.*]]
+; TUNIT:       if.then3:
+; TUNIT-NEXT:    [[CALL5:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[B]], i32 undef) #[[ATTR8]]
+; TUNIT-NEXT:    [[CALL6:%.*]] = call i32 @scc_r2(i32 [[R]], i32 [[R]], i32 [[R]]) #[[ATTR8]]
+; TUNIT-NEXT:    [[CALL7:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[R]], i32 undef) #[[ATTR8]]
+; TUNIT-NEXT:    [[CALL8:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[B]], i32 undef) #[[ATTR8]]
+; TUNIT-NEXT:    [[CALL9:%.*]] = call i32 @scc_r2(i32 [[B]], i32 [[R]], i32 [[B]]) #[[ATTR8]]
+; TUNIT-NEXT:    [[CALL11:%.*]] = call i32 @scc_r1(i32 [[B]], i32 [[B]], i32 undef) #[[ATTR8]]
+; TUNIT-NEXT:    br label [[RETURN]]
+; TUNIT:       if.end12:
+; TUNIT-NEXT:    [[CMP13:%.*]] = icmp eq i32 [[A]], [[B]]
+; TUNIT-NEXT:    br i1 [[CMP13]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
+; TUNIT:       cond.true:
+; TUNIT-NEXT:    br label [[COND_END:%.*]]
+; TUNIT:       cond.false:
+; TUNIT-NEXT:    [[CALL14:%.*]] = call i32 @scc_r2(i32 [[A]], i32 [[B]], i32 [[R]]) #[[ATTR8]]
+; TUNIT-NEXT:    br label [[COND_END]]
+; TUNIT:       cond.end:
+; TUNIT-NEXT:    [[COND:%.*]] = phi i32 [ [[R]], [[COND_TRUE]] ], [ [[R]], [[COND_FALSE]] ]
+; TUNIT-NEXT:    br label [[RETURN]]
+; TUNIT:       return:
+; TUNIT-NEXT:    [[RETVAL_0:%.*]] = phi i32 [ [[R]], [[IF_THEN]] ], [ [[B]], [[IF_THEN3]] ], [ [[R]], [[COND_END]] ]
+; TUNIT-NEXT:    ret i32 [[RETVAL_0]]
+;
+; CGSCC: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
+; CGSCC-LABEL: define {{[^@]+}}@scc_rX
+; CGSCC-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[R:%.*]]) #[[ATTR1]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[A]], [[B]]
+; CGSCC-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
+; CGSCC:       if.then:
+; CGSCC-NEXT:    [[CALL1:%.*]] = call i32 @scc_r2(i32 [[B]], i32 [[A]], i32 [[R]]) #[[ATTR7]]
+; CGSCC-NEXT:    br label [[RETURN:%.*]]
+; CGSCC:       if.end:
+; CGSCC-NEXT:    [[CMP2:%.*]] = icmp slt i32 [[A]], [[B]]
+; CGSCC-NEXT:    br i1 [[CMP2]], label [[IF_THEN3:%.*]], label [[IF_END12:%.*]]
+; CGSCC:       if.then3:
+; CGSCC-NEXT:    [[CALL5:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[B]], i32 [[R]]) #[[ATTR7]]
+; CGSCC-NEXT:    [[CALL6:%.*]] = call i32 @scc_r2(i32 [[R]], i32 [[R]], i32 [[R]]) #[[ATTR7]]
+; CGSCC-NEXT:    [[CALL7:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[R]], i32 [[R]]) #[[ATTR7]]
+; CGSCC-NEXT:    [[CALL8:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[B]], i32 [[R]]) #[[ATTR7]]
+; CGSCC-NEXT:    [[CALL9:%.*]] = call i32 @scc_r2(i32 [[B]], i32 [[R]], i32 [[B]]) #[[ATTR7]]
+; CGSCC-NEXT:    [[CALL10:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[B]], i32 [[R]]) #[[ATTR7]]
+; CGSCC-NEXT:    [[CALL11:%.*]] = call i32 @scc_r1(i32 [[B]], i32 [[B]], i32 [[B]]) #[[ATTR7]]
+; CGSCC-NEXT:    br label [[RETURN]]
+; CGSCC:       if.end12:
+; CGSCC-NEXT:    [[CMP13:%.*]] = icmp eq i32 [[A]], [[B]]
+; CGSCC-NEXT:    br i1 [[CMP13]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
+; CGSCC:       cond.true:
+; CGSCC-NEXT:    br label [[COND_END:%.*]]
+; CGSCC:       cond.false:
+; CGSCC-NEXT:    [[CALL14:%.*]] = call i32 @scc_r2(i32 [[A]], i32 [[B]], i32 [[R]]) #[[ATTR7]]
+; CGSCC-NEXT:    br label [[COND_END]]
+; CGSCC:       cond.end:
+; CGSCC-NEXT:    [[COND:%.*]] = phi i32 [ [[R]], [[COND_TRUE]] ], [ [[CALL14]], [[COND_FALSE]] ]
+; CGSCC-NEXT:    br label [[RETURN]]
+; CGSCC:       return:
+; CGSCC-NEXT:    [[RETVAL_0:%.*]] = phi i32 [ [[CALL1]], [[IF_THEN]] ], [ [[CALL11]], [[IF_THEN3]] ], [ [[R]], [[COND_END]] ]
+; CGSCC-NEXT:    ret i32 [[RETVAL_0]]
+;
+entry:
+  %cmp = icmp sgt i32 %a, %b
+  br i1 %cmp, label %if.then, label %if.end
+
+if.then:                                          ; preds = %entry
+  %call = call i32 @sink_r0(i32 %r)
+  %call1 = call i32 @scc_r2(i32 %b, i32 %a, i32 %call)
+  br label %return
+
+if.end:                                           ; preds = %entry
+  %cmp2 = icmp slt i32 %a, %b
+  br i1 %cmp2, label %if.then3, label %if.end12
+
+if.then3:                                         ; preds = %if.end
+  %call4 = call i32 @sink_r0(i32 %b)
+  %call5 = call i32 @scc_r1(i32 %a, i32 %b, i32 %r)
+  %call6 = call i32 @scc_r2(i32 %r, i32 %r, i32 %r)
+  %call7 = call i32 @scc_r1(i32 %a, i32 %call6, i32 %r)
+  %call8 = call i32 @scc_r1(i32 %a, i32 %b, i32 %r)
+  %call9 = call i32 @scc_r2(i32 %call5, i32 %call7, i32 %call8)
+  %call10 = call i32 @scc_r1(i32 %a, i32 %b, i32 %r)
+  %call11 = call i32 @scc_r1(i32 %call4, i32 %call9, i32 %call10)
+  br label %return
+
+if.end12:                                         ; preds = %if.end
+  %cmp13 = icmp eq i32 %a, %b
+  br i1 %cmp13, label %cond.true, label %cond.false
+
+cond.true:                                        ; preds = %if.end12
+  br label %cond.end
+
+cond.false:                                       ; preds = %if.end12
+  %call14 = call i32 @scc_r2(i32 %a, i32 %b, i32 %r)
+  br label %cond.end
+
+cond.end:                                         ; preds = %cond.false, %cond.true
+  %cond = phi i32 [ %r, %cond.true ], [ %call14, %cond.false ]
+  br label %return
+
+return:                                           ; preds = %cond.end, %if.then3, %if.then
+  %retval.0 = phi i32 [ %call1, %if.then ], [ %call11, %if.then3 ], [ %cond, %cond.end ]
+  ret i32 %retval.0
+}
+
+
+; TEST SCC test returning a pointer value argument
+;
+; double* ptr_scc_r1(double* a, double* b, double* r);
+; double* ptr_scc_r2(double* a, double* b, double* r);
+;
+; __attribute__((noinline)) double* ptr_sink_r0(double* r) {
+;   return r;
+; }
+;
+; __attribute__((noinline)) double* ptr_scc_r1(double* a, double* r, double* b) {
+;   return ptr_scc_r2(r, a, ptr_sink_r0(r));
+; }
+;
+; __attribute__((noinline)) double* ptr_scc_r2(double* a, double* b, double* r) {
+;   if (a > b)
+;     return ptr_scc_r2(b, a, ptr_sink_r0(r));
+;   if (a < b)
+;     return ptr_scc_r1(ptr_sink_r0(b), ptr_scc_r2(ptr_scc_r1(a, b, r), ptr_scc_r1(a, ptr_scc_r2(r, r, r), r), ptr_scc_r2(a, b, r)), ptr_scc_r1(a, b, r));
+;   return a == b ? r : ptr_scc_r2(a, b, r);
+; }
+define ptr @ptr_sink_r0(ptr %r) #0 {
+; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
+; CHECK-LABEL: define {{[^@]+}}@ptr_sink_r0
+; CHECK-SAME: (ptr nofree nonnull readnone returned "no-capture-maybe-returned" [[R:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    ret ptr [[R]]
+;
+entry:
+  ret ptr %r
+}
+
+define ptr @ptr_scc_r1(ptr %a, ptr %r, ptr %b) #0 {
+; TUNIT: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
+; TUNIT-LABEL: define {{[^@]+}}@ptr_scc_r1
+; TUNIT-SAME: (ptr nocapture nofree nonnull readnone [[A:%.*]], ptr nofree nonnull readnone returned "no-capture-maybe-returned" [[R:%.*]], ptr nocapture nofree nonnull readnone [[B:%.*]]) #[[ATTR1]] {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    [[CALL1:%.*]] = call ptr @ptr_scc_r2(ptr noalias nocapture nofree nonnull readnone [[R]], ptr noalias nocapture nofree nonnull readnone [[A]], ptr noalias nofree nonnull readnone "no-capture-maybe-returned" [[R]]) #[[ATTR8]]
+; TUNIT-NEXT:    ret ptr [[R]]
+;
+; CGSCC: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
+; CGSCC-LABEL: define {{[^@]+}}@ptr_scc_r1
+; CGSCC-SAME: (ptr nocapture nofree nonnull readnone [[A:%.*]], ptr nofree nonnull readnone returned [[R:%.*]], ptr nocapture nofree nonnull readnone [[B:%.*]]) #[[ATTR1]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    [[CALL1:%.*]] = call ptr @ptr_scc_r2(ptr noalias nocapture nofree nonnull readnone [[R]], ptr noalias nocapture nofree nonnull readnone [[A]], ptr noalias nofree nonnull readnone [[R]]) #[[ATTR7]]
+; CGSCC-NEXT:    ret ptr [[R]]
+;
+entry:
+  %call = call ptr @ptr_sink_r0(ptr %r)
+  %call1 = call ptr @ptr_scc_r2(ptr %r, ptr %a, ptr %call)
+  ret ptr %call1
+}
+
+define ptr @ptr_scc_r2(ptr %a, ptr %b, ptr %r) #0 {
+; TUNIT: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
+; TUNIT-LABEL: define {{[^@]+}}@ptr_scc_r2
+; TUNIT-SAME: (ptr nocapture nofree nonnull readnone [[A:%.*]], ptr nocapture nofree nonnull readnone [[B:%.*]], ptr nofree nonnull readnone returned "no-capture-maybe-returned" [[R:%.*]]) #[[ATTR1]] {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    [[CMP:%.*]] = icmp ugt ptr [[A]], [[B]]
+; TUNIT-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
+; TUNIT:       if.then:
+; TUNIT-NEXT:    [[CALL1:%.*]] = call ptr @ptr_scc_r2(ptr noalias nocapture nofree nonnull readnone [[B]], ptr noalias nocapture nofree nonnull readnone [[A]], ptr noalias nofree nonnull readnone "no-capture-maybe-returned" [[R]]) #[[ATTR8]]
+; TUNIT-NEXT:    br label [[RETURN:%.*]]
+; TUNIT:       if.end:
+; TUNIT-NEXT:    [[CMP2:%.*]] = icmp ult ptr [[A]], [[B]]
+; TUNIT-NEXT:    br i1 [[CMP2]], label [[IF_THEN3:%.*]], label [[IF_END12:%.*]]
+; TUNIT:       if.then3:
+; TUNIT-NEXT:    [[CALL5:%.*]] = call nonnull ptr @ptr_scc_r1(ptr noalias nocapture nofree nonnull readnone [[A]], ptr noalias nofree nonnull readnone "no-capture-maybe-returned" [[B]], ptr noalias nocapture nofree nonnull readnone undef) #[[ATTR8]]
+; TUNIT-NEXT:    [[CALL6:%.*]] = call nonnull ptr @ptr_scc_r2(ptr noalias nocapture nofree nonnull readnone [[R]], ptr noalias nocapture nofree nonnull readnone [[R]], ptr noalias nofree nonnull readnone "no-capture-maybe-returned" [[R]]) #[[ATTR8]]
+; TUNIT-NEXT:    [[CALL7:%.*]] = call nonnull ptr @ptr_scc_r1(ptr noalias nocapture nofree nonnull readnone [[A]], ptr noalias nofree nonnull readnone "no-capture-maybe-returned" [[R]], ptr noalias nocapture nofree nonnull readnone undef) #[[ATTR8]]
+; TUNIT-NEXT:    [[CALL8:%.*]] = call nonnull ptr @ptr_scc_r2(ptr noalias nocapture nofree nonnull readnone [[A]], ptr noalias nocapture nofree nonnull readnone [[B]], ptr noalias nofree nonnull readnone "no-capture-maybe-returned" [[R]]) #[[ATTR8]]
+; TUNIT-NEXT:    [[CALL9:%.*]] = call nonnull ptr @ptr_scc_r2(ptr noalias nocapture nofree nonnull readnone [[B]], ptr noalias nocapture nofree nonnull readnone [[R]], ptr noalias nofree nonnull readnone "no-capture-maybe-returned" [[R]]) #[[ATTR8]]
+; TUNIT-NEXT:    [[CALL11:%.*]] = call ptr @ptr_scc_r1(ptr noalias nocapture nofree nonnull readnone [[B]], ptr noalias nofree nonnull readnone "no-capture-maybe-returned" [[R]], ptr noalias nocapture nofree nonnull readnone undef) #[[ATTR8]]
+; TUNIT-NEXT:    br label [[RETURN]]
+; TUNIT:       if.end12:
+; TUNIT-NEXT:    [[CMP13:%.*]] = icmp eq ptr [[A]], [[B]]
+; TUNIT-NEXT:    br i1 [[CMP13]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
+; TUNIT:       cond.true:
+; TUNIT-NEXT:    br label [[COND_END:%.*]]
+; TUNIT:       cond.false:
+; TUNIT-NEXT:    [[CALL14:%.*]] = call ptr @ptr_scc_r2(ptr noalias nocapture nofree nonnull readnone [[A]], ptr noalias nocapture nofree nonnull readnone [[B]], ptr noalias nofree nonnull readnone "no-capture-maybe-returned" [[R]]) #[[ATTR8]]
+; TUNIT-NEXT:    br label [[COND_END]]
+; TUNIT:       cond.end:
+; TUNIT-NEXT:    [[COND:%.*]] = phi ptr [ [[R]], [[COND_TRUE]] ], [ [[R]], [[COND_FALSE]] ]
+; TUNIT-NEXT:    br label [[RETURN]]
+; TUNIT:       return:
+; TUNIT-NEXT:    [[RETVAL_0:%.*]] = phi ptr [ [[R]], [[IF_THEN]] ], [ [[R]], [[IF_THEN3]] ], [ [[R]], [[COND_END]] ]
+; TUNIT-NEXT:    ret ptr [[R]]
+;
+; CGSCC: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
+; CGSCC-LABEL: define {{[^@]+}}@ptr_scc_r2
+; CGSCC-SAME: (ptr nocapture nofree nonnull readnone [[A:%.*]], ptr nocapture nofree nonnull readnone [[B:%.*]], ptr nofree nonnull readnone returned [[R:%.*]]) #[[ATTR1]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    [[CMP:%.*]] = icmp ugt ptr [[A]], [[B]]
+; CGSCC-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
+; CGSCC:       if.then:
+; CGSCC-NEXT:    [[CALL1:%.*]] = call ptr @ptr_scc_r2(ptr noalias nocapture nofree nonnull readnone [[B]], ptr noalias nocapture nofree nonnull readnone [[A]], ptr noalias nofree nonnull readnone [[R]]) #[[ATTR7]]
+; CGSCC-NEXT:    br label [[RETURN:%.*]]
+; CGSCC:       if.end:
+; CGSCC-NEXT:    [[CMP2:%.*]] = icmp ult ptr [[A]], [[B]]
+; CGSCC-NEXT:    br i1 [[CMP2]], label [[IF_THEN3:%.*]], label [[IF_END12:%.*]]
+; CGSCC:       if.then3:
+; CGSCC-NEXT:    [[CALL5:%.*]] = call nonnull ptr @ptr_scc_r1(ptr noalias nocapture nofree nonnull readnone [[A]], ptr noalias nofree nonnull readnone [[B]], ptr noalias nocapture nofree nonnull readnone undef) #[[ATTR7]]
+; CGSCC-NEXT:    [[CALL6:%.*]] = call nonnull ptr @ptr_scc_r2(ptr noalias nocapture nofree nonnull readnone [[R]], ptr noalias nocapture nofree nonnull readnone [[R]], ptr noalias nofree nonnull readnone [[R]]) #[[ATTR7]]
+; CGSCC-NEXT:    [[CALL7:%.*]] = call nonnull ptr @ptr_scc_r1(ptr noalias nocapture nofree nonnull readnone [[A]], ptr noalias nofree nonnull readnone [[R]], ptr noalias nocapture nofree nonnull readnone undef) #[[ATTR7]]
+; CGSCC-NEXT:    [[CALL8:%.*]] = call nonnull ptr @ptr_scc_r2(ptr noalias nocapture nofree nonnull readnone [[A]], ptr noalias nocapture nofree nonnull readnone [[B]], ptr noalias nofree nonnull readnone [[R]]) #[[ATTR7]]
+; CGSCC-NEXT:    [[CALL9:%.*]] = call nonnull ptr @ptr_scc_r2(ptr noalias nocapture nofree nonnull readnone [[B]], ptr noalias nocapture nofree nonnull readnone [[R]], ptr noalias nofree nonnull readnone [[R]]) #[[ATTR7]]
+; CGSCC-NEXT:    [[CALL11:%.*]] = call ptr @ptr_scc_r1(ptr noalias nocapture nofree nonnull readnone [[B]], ptr noalias nofree nonnull readnone [[R]], ptr noalias nocapture nofree nonnull readnone undef) #[[ATTR7]]
+; CGSCC-NEXT:    br label [[RETURN]]
+; CGSCC:       if.end12:
+; CGSCC-NEXT:    [[CMP13:%.*]] = icmp eq ptr [[A]], [[B]]
+; CGSCC-NEXT:    br i1 [[CMP13]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
+; CGSCC:       cond.true:
+; CGSCC-NEXT:    br label [[COND_END:%.*]]
+; CGSCC:       cond.false:
+; CGSCC-NEXT:    [[CALL14:%.*]] = call ptr @ptr_scc_r2(ptr noalias nocapture nofree nonnull readnone [[A]], ptr noalias nocapture nofree nonnull readnone [[B]], ptr noalias nofree nonnull readnone [[R]]) #[[ATTR7]]
+; CGSCC-NEXT:    br label [[COND_END]]
+; CGSCC:       cond.end:
+; CGSCC-NEXT:    [[COND:%.*]] = phi ptr [ [[R]], [[COND_TRUE]] ], [ [[R]], [[COND_FALSE]] ]
+; CGSCC-NEXT:    br label [[RETURN]]
+; CGSCC:       return:
+; CGSCC-NEXT:    [[RETVAL_0:%.*]] = phi ptr [ [[R]], [[IF_THEN]] ], [ [[R]], [[IF_THEN3]] ], [ [[R]], [[COND_END]] ]
+; CGSCC-NEXT:    ret ptr [[R]]
+;
+entry:
+  %cmp = icmp ugt ptr %a, %b
+  br i1 %cmp, label %if.then, label %if.end
+
+if.then:                                          ; preds = %entry
+  %call = call ptr @ptr_sink_r0(ptr %r)
+  %call1 = call ptr @ptr_scc_r2(ptr %b, ptr %a, ptr %call)
+  br label %return
+
+if.end:                                           ; preds = %entry
+  %cmp2 = icmp ult ptr %a, %b
+  br i1 %cmp2, label %if.then3, label %if.end12
+
+if.then3:                                         ; preds = %if.end
+  %call4 = call ptr @ptr_sink_r0(ptr %b)
+  %call5 = call ptr @ptr_scc_r1(ptr %a, ptr %b, ptr %r)
+  %call6 = call ptr @ptr_scc_r2(ptr %r, ptr %r, ptr %r)
+  %call7 = call ptr @ptr_scc_r1(ptr %a, ptr %call6, ptr %r)
+  %call8 = call ptr @ptr_scc_r2(ptr %a, ptr %b, ptr %r)
+  %call9 = call ptr @ptr_scc_r2(ptr %call5, ptr %call7, ptr %call8)
+  %call10 = call ptr @ptr_scc_r1(ptr %a, ptr %b, ptr %r)
+  %call11 = call ptr @ptr_scc_r1(ptr %call4, ptr %call9, ptr %call10)
+  br label %return
+
+if.end12:                                         ; preds = %if.end
+  %cmp13 = icmp eq ptr %a, %b
+  br i1 %cmp13, label %cond.true, label %cond.false
+
+cond.true:                                        ; preds = %if.end12
+  br label %cond.end
+
+cond.false:                                       ; preds = %if.end12
+  %call14 = call ptr @ptr_scc_r2(ptr %a, ptr %b, ptr %r)
+  br label %cond.end
+
+cond.end:                                         ; preds = %cond.false, %cond.true
+  %cond = phi ptr [ %r, %cond.true ], [ %call14, %cond.false ]
+  br label %return
+
+return:                                           ; preds = %cond.end, %if.then3, %if.then
+  %retval.0 = phi ptr [ %call1, %if.then ], [ %call11, %if.then3 ], [ %cond, %cond.end ]
+  ret ptr %retval.0
+}
+
+
+; TEST a no-return singleton SCC
+;
+; int* rt0(int *a) {
+;   return *a ? a : rt0(a);
+; }
+;
+define ptr @rt0(ptr %a) #0 {
+; TUNIT: Function Attrs: nofree noinline nosync nounwind memory(argmem: read) uwtable
+; TUNIT-LABEL: define {{[^@]+}}@rt0
+; TUNIT-SAME: (ptr nofree noundef nonnull readonly returned align 4 dereferenceable(4) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR3:[0-9]+]] {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    [[CALL:%.*]] = call ptr @rt0(ptr nofree noundef nonnull readonly align 4 dereferenceable(4) "no-capture-maybe-returned" [[A]]) #[[ATTR9:[0-9]+]]
+; TUNIT-NEXT:    ret ptr [[A]]
+;
+; CGSCC: Function Attrs: nofree noinline nosync nounwind memory(argmem: read) uwtable
+; CGSCC-LABEL: define {{[^@]+}}@rt0
+; CGSCC-SAME: (ptr nofree noundef nonnull readonly returned align 4 dereferenceable(4) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR2:[0-9]+]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    [[CALL:%.*]] = call ptr @rt0(ptr nofree noundef nonnull readonly align 4 dereferenceable(4) "no-capture-maybe-returned" [[A]]) #[[ATTR8:[0-9]+]]
+; CGSCC-NEXT:    ret ptr [[A]]
+;
+entry:
+  %v = load i32, ptr %a, align 4
+  %tobool = icmp ne i32 %v, 0
+  %call = call ptr @rt0(ptr %a)
+  %sel = select i1 %tobool, ptr %a, ptr %call
+  ret ptr %sel
+}
+
+; TEST a no-return singleton SCC
+;
+; int* rt1(int *a) {
+;   return *a ? undef : rt1(a);
+; }
+;
+define ptr @rt1(ptr %a) #0 {
+; TUNIT: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable
+; TUNIT-LABEL: define {{[^@]+}}@rt1
+; TUNIT-SAME: (ptr nocapture nofree nonnull readnone align 4 dereferenceable(4) [[A:%.*]]) #[[ATTR4:[0-9]+]] {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    ret ptr undef
+;
+; CGSCC: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable
+; CGSCC-LABEL: define {{[^@]+}}@rt1
+; CGSCC-SAME: (ptr nocapture nofree nonnull readnone align 4 dereferenceable(4) [[A:%.*]]) #[[ATTR3:[0-9]+]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    ret ptr undef
+;
+entry:
+  %v = load i32, ptr %a, align 4
+  %tobool = icmp ne i32 %v, 0
+  %call = call ptr @rt1(ptr %a)
+  %sel = select i1 %tobool, ptr undef, ptr %call
+  ret ptr %sel
+}
+
+; TEST another SCC test
+;
+define ptr @rt2_helper(ptr %a) #0 {
+; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
+; CHECK-LABEL: define {{[^@]+}}@rt2_helper
+; CHECK-SAME: (ptr nofree nonnull readnone returned "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    ret ptr [[A]]
+;
+entry:
+  %call = call ptr @rt2(ptr %a, ptr %a)
+  ret ptr %call
+}
+
+define ptr @rt2(ptr %a, ptr %b) #0 {
+; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
+; CHECK-LABEL: define {{[^@]+}}@rt2
+; CHECK-SAME: (ptr nocapture nofree nonnull readnone [[A:%.*]], ptr nofree nonnull readnone returned "no-capture-maybe-returned" [[B:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[IF_END:%.*]]
+; CHECK:       if.then:
+; CHECK-NEXT:    unreachable
+; CHECK:       if.end:
+; CHECK-NEXT:    ret ptr [[B]]
+;
+entry:
+  %cmp = icmp eq ptr %a, null
+  br i1 %cmp, label %if.then, label %if.end
+
+if.then:
+  %call = call ptr @rt2_helper(ptr %a)
+  br label %if.end
+
+if.end:
+  %sel = phi ptr [ %b, %entry], [%call, %if.then]
+  ret ptr %sel
+}
+
+; TEST another SCC test
+;
+define ptr @rt3_helper(ptr %a, ptr %b) #0 {
+; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
+; CHECK-LABEL: define {{[^@]+}}@rt3_helper
+; CHECK-SAME: (ptr nocapture nofree nonnull readnone [[A:%.*]], ptr nofree nonnull readnone returned "no-capture-maybe-returned" [[B:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    ret ptr [[B]]
+;
+entry:
+  %call = call ptr @rt3(ptr %a, ptr %b)
+  ret ptr %call
+}
+
+define ptr @rt3(ptr %a, ptr %b) #0 {
+; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
+; CHECK-LABEL: define {{[^@]+}}@rt3
+; CHECK-SAME: (ptr nocapture nofree nonnull readnone [[A:%.*]], ptr nofree nonnull readnone returned "no-capture-maybe-returned" [[B:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[IF_END:%.*]]
+; CHECK:       if.then:
+; CHECK-NEXT:    unreachable
+; CHECK:       if.end:
+; CHECK-NEXT:    ret ptr [[B]]
+;
+entry:
+  %cmp = icmp eq ptr %a, null
+  br i1 %cmp, label %if.then, label %if.end
+
+if.then:
+  %call = call ptr @rt3_helper(ptr %a, ptr %b)
+  br label %if.end
+
+if.end:
+  %sel = phi ptr [ %b, %entry], [%call, %if.then]
+  ret ptr %sel
+}
+
+; TEST address taken function with call to an external functions
+;
+;  void unknown_fn(void *);
+;
+;  int* calls_unknown_fn(int *r) {
+;    unknown_fn(&calls_unknown_fn);
+;    return r;
+;  }
+;
+declare void @unknown_fn(ptr) #0
+
+define ptr @calls_unknown_fn(ptr %r) #0 {
+; TUNIT: Function Attrs: noinline nounwind uwtable
+; TUNIT-LABEL: define {{[^@]+}}@calls_unknown_fn
+; TUNIT-SAME: (ptr nofree nonnull readnone returned "no-capture-maybe-returned" [[R:%.*]]) #[[ATTR5:[0-9]+]] {
+; TUNIT-NEXT:    tail call void @unknown_fn(ptr noundef nonnull @calls_unknown_fn) #[[ATTR10:[0-9]+]]
+; TUNIT-NEXT:    ret ptr [[R]]
+;
+; CGSCC: Function Attrs: noinline nounwind uwtable
+; CGSCC-LABEL: define {{[^@]+}}@calls_unknown_fn
+; CGSCC-SAME: (ptr nofree nonnull readnone returned "no-capture-maybe-returned" [[R:%.*]]) #[[ATTR4:[0-9]+]] {
+; CGSCC-NEXT:    tail call void @unknown_fn(ptr noundef nonnull @calls_unknown_fn) #[[ATTR9:[0-9]+]]
+; CGSCC-NEXT:    ret ptr [[R]]
+;
+  tail call void @unknown_fn(ptr nonnull @calls_unknown_fn)
+  ret ptr %r
+}
+
+
+; TEST call to a function that might be redifined at link time
+;
+;  int *maybe_redefined_fn(int *r) {
+;    return r;
+;  }
+;
+;  int *calls_maybe_redefined_fn(int *r) {
+;    maybe_redefined_fn(r);
+;    return r;
+;  }
+;
+; Verify the maybe-redefined function is not annotated:
+;
+define linkonce_odr ptr @maybe_redefined_fn(ptr %r) #0 {
+; TUNIT: Function Attrs: noinline nounwind uwtable
+; TUNIT-LABEL: define {{[^@]+}}@maybe_redefined_fn
+; TUNIT-SAME: (ptr [[R:%.*]]) #[[ATTR5]] {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    ret ptr [[R]]
+;
+; CGSCC: Function Attrs: noinline nounwind uwtable
+; CGSCC-LABEL: define {{[^@]+}}@maybe_redefined_fn
+; CGSCC-SAME: (ptr [[R:%.*]]) #[[ATTR4]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    ret ptr [[R]]
+;
+entry:
+  ret ptr %r
+}
+
+define ptr @calls_maybe_redefined_fn(ptr %r) #0 {
+; TUNIT: Function Attrs: noinline nounwind uwtable
+; TUNIT-LABEL: define {{[^@]+}}@calls_maybe_redefined_fn
+; TUNIT-SAME: (ptr nonnull returned [[R:%.*]]) #[[ATTR5]] {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    [[CALL:%.*]] = call ptr @maybe_redefined_fn(ptr nonnull [[R]]) #[[ATTR10]]
+; TUNIT-NEXT:    ret ptr [[R]]
+;
+; CGSCC: Function Attrs: noinline nounwind uwtable
+; CGSCC-LABEL: define {{[^@]+}}@calls_maybe_redefined_fn
+; CGSCC-SAME: (ptr nonnull returned [[R:%.*]]) #[[ATTR4]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    [[CALL:%.*]] = call ptr @maybe_redefined_fn(ptr nonnull [[R]]) #[[ATTR9]]
+; CGSCC-NEXT:    ret ptr [[R]]
+;
+entry:
+  %call = call ptr @maybe_redefined_fn(ptr %r)
+  ret ptr %r
+}
+
+; TEST return call to a function that might be redifined at link time
+;
+;  int *maybe_redefined_fn2(int *r) {
+;    return r;
+;  }
+;
+;  int *calls_maybe_redefined_fn2(int *r) {
+;    return maybe_redefined_fn2(r);
+;  }
+;
+; Verify the maybe-redefined function is not annotated:
+;
+define linkonce_odr ptr @maybe_redefined_fn2(ptr %r) #0 {
+; TUNIT: Function Attrs: noinline nounwind uwtable
+; TUNIT-LABEL: define {{[^@]+}}@maybe_redefined_fn2
+; TUNIT-SAME: (ptr [[R:%.*]]) #[[ATTR5]] {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    ret ptr [[R]]
+;
+; CGSCC: Function Attrs: noinline nounwind uwtable
+; CGSCC-LABEL: define {{[^@]+}}@maybe_redefined_fn2
+; CGSCC-SAME: (ptr [[R:%.*]]) #[[ATTR4]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    ret ptr [[R]]
+;
+entry:
+  ret ptr %r
+}
+
+define ptr @calls_maybe_redefined_fn2(ptr %r) #0 {
+; TUNIT: Function Attrs: noinline nounwind uwtable
+; TUNIT-LABEL: define {{[^@]+}}@calls_maybe_redefined_fn2
+; TUNIT-SAME: (ptr nonnull [[R:%.*]]) #[[ATTR5]] {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    [[CALL:%.*]] = call nonnull ptr @maybe_redefined_fn2(ptr nonnull [[R]]) #[[ATTR10]]
+; TUNIT-NEXT:    ret ptr [[CALL]]
+;
+; CGSCC: Function Attrs: noinline nounwind uwtable
+; CGSCC-LABEL: define {{[^@]+}}@calls_maybe_redefined_fn2
+; CGSCC-SAME: (ptr nonnull [[R:%.*]]) #[[ATTR4]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    [[CALL:%.*]] = call nonnull ptr @maybe_redefined_fn2(ptr nonnull [[R]]) #[[ATTR9]]
+; CGSCC-NEXT:    ret ptr [[CALL]]
+;
+entry:
+  %call = call ptr @maybe_redefined_fn2(ptr %r)
+  ret ptr %call
+}
+
+
+; TEST returned argument goes through select and phi
+;
+; double select_and_phi(double b) {
+;   double x = b;
+;   if (b > 0)
+;     x = b;
+;   return b == 0? b : x;
+; }
+;
+define double @select_and_phi(double %b) #0 {
+; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
+; CHECK-LABEL: define {{[^@]+}}@select_and_phi
+; CHECK-SAME: (double returned [[B:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp ogt double [[B]], 0.000000e+00
+; CHECK-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
+; CHECK:       if.then:
+; CHECK-NEXT:    br label [[IF_END]]
+; CHECK:       if.end:
+; CHECK-NEXT:    [[PHI:%.*]] = phi double [ [[B]], [[IF_THEN]] ], [ [[B]], [[ENTRY:%.*]] ]
+; CHECK-NEXT:    ret double [[B]]
+;
+entry:
+  %cmp = fcmp ogt double %b, 0.000000e+00
+  br i1 %cmp, label %if.then, label %if.end
+
+if.then:                                          ; preds = %entry
+  br label %if.end
+
+if.end:                                           ; preds = %if.then, %entry
+  %phi = phi double [ %b, %if.then ], [ %b, %entry ]
+  %cmp1 = fcmp oeq double %b, 0.000000e+00
+  %sel = select i1 %cmp1, double %b, double %phi
+  ret double %sel
+}
+
+
+; TEST returned argument goes through recursion, select, and phi
+;
+; double recursion_select_and_phi(int a, double b) {
+;   double x = b;
+;   if (a-- > 0)
+;     x = recursion_select_and_phi(a, b);
+;   return b == 0? b : x;
+; }
+;
+define double @recursion_select_and_phi(i32 %a, double %b) #0 {
+; TUNIT: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
+; TUNIT-LABEL: define {{[^@]+}}@recursion_select_and_phi
+; TUNIT-SAME: (i32 [[A:%.*]], double returned [[B:%.*]]) #[[ATTR1]] {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    [[DEC:%.*]] = add nsw i32 [[A]], -1
+; TUNIT-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[A]], 0
+; TUNIT-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
+; TUNIT:       if.then:
+; TUNIT-NEXT:    [[CALL:%.*]] = call double @recursion_select_and_phi(i32 [[DEC]], double [[B]]) #[[ATTR8]]
+; TUNIT-NEXT:    br label [[IF_END]]
+; TUNIT:       if.end:
+; TUNIT-NEXT:    [[PHI:%.*]] = phi double [ [[B]], [[IF_THEN]] ], [ [[B]], [[ENTRY:%.*]] ]
+; TUNIT-NEXT:    ret double [[B]]
+;
+; CGSCC: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
+; CGSCC-LABEL: define {{[^@]+}}@recursion_select_and_phi
+; CGSCC-SAME: (i32 [[A:%.*]], double returned [[B:%.*]]) #[[ATTR1]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    [[DEC:%.*]] = add nsw i32 [[A]], -1
+; CGSCC-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[A]], 0
+; CGSCC-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
+; CGSCC:       if.then:
+; CGSCC-NEXT:    [[CALL:%.*]] = call double @recursion_select_and_phi(i32 [[DEC]], double [[B]]) #[[ATTR7]]
+; CGSCC-NEXT:    br label [[IF_END]]
+; CGSCC:       if.end:
+; CGSCC-NEXT:    [[PHI:%.*]] = phi double [ [[B]], [[IF_THEN]] ], [ [[B]], [[ENTRY:%.*]] ]
+; CGSCC-NEXT:    ret double [[B]]
+;
+entry:
+  %dec = add nsw i32 %a, -1
+  %cmp = icmp sgt i32 %a, 0
+  br i1 %cmp, label %if.then, label %if.end
+
+if.then:                                          ; preds = %entry
+  %call = call double @recursion_select_and_phi(i32 %dec, double %b)
+  br label %if.end
+
+if.end:                                           ; preds = %if.then, %entry
+  %phi = phi double [ %call, %if.then ], [ %b, %entry ]
+  %cmp1 = fcmp oeq double %b, 0.000000e+00
+  %sel = select i1 %cmp1, double %b, double %phi
+  ret double %sel
+}
+
+
+; TEST returned argument goes through bitcasts
+;
+; double* bitcast(int* b) {
+;   return (double*)b;
+; }
+;
+define ptr @bitcast(ptr %b) #0 {
+; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
+; CHECK-LABEL: define {{[^@]+}}@bitcast
+; CHECK-SAME: (ptr nofree nonnull readnone returned "no-capture-maybe-returned" [[B:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    ret ptr [[B]]
+;
+entry:
+  ret ptr %b
+}
+
+
+; TEST returned argument goes through select and phi interleaved with bitcasts
+;
+; double* bitcasts_select_and_phi(int* b) {
+;   double* x = b;
+;   if (b == 0)
+;     x = b;
+;   return b != 0 ? b : x;
+; }
+;
+define ptr @bitcasts_select_and_phi(ptr %b) #0 {
+; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
+; CHECK-LABEL: define {{[^@]+}}@bitcasts_select_and_phi
+; CHECK-SAME: (ptr nofree nonnull readnone returned "no-capture-maybe-returned" [[B:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[IF_END:%.*]]
+; CHECK:       if.then:
+; CHECK-NEXT:    unreachable
+; CHECK:       if.end:
+; CHECK-NEXT:    ret ptr [[B]]
+;
+entry:
+  %cmp = icmp eq ptr %b, null
+  br i1 %cmp, label %if.then, label %if.end
+
+if.then:                                          ; preds = %entry
+  br label %if.end
+
+if.end:                                           ; preds = %if.then, %entry
+  %phi = phi ptr [ %b, %if.then ], [ %b, %entry ]
+  %cmp2 = icmp ne ptr %b, null
+  %sel = select i1 %cmp2, ptr %phi, ptr %b
+  ret ptr %sel
+}
+
+
+; TEST return argument or argument or undef
+;
+; double* ret_arg_arg_undef(int* b) {
+;   if (b == 0)
+;     return (double*)b;
+;   if (b == 0)
+;     return (double*)b;
+;   /* return undef */
+; }
+;
+define ptr @ret_arg_arg_undef(ptr %b) #0 {
+; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
+; CHECK-LABEL: define {{[^@]+}}@ret_arg_arg_undef
+; CHECK-SAME: (ptr nocapture nofree nonnull readnone [[B:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[IF_END:%.*]]
+; CHECK:       ret_arg0:
+; CHECK-NEXT:    unreachable
+; CHECK:       if.end:
+; CHECK-NEXT:    br label [[RET_UNDEF:%.*]]
+; CHECK:       ret_arg1:
+; CHECK-NEXT:    unreachable
+; CHECK:       ret_undef:
+; CHECK-NEXT:    ret ptr undef
+;
+entry:
+  %cmp = icmp eq ptr %b, null
+  br i1 %cmp, label %ret_arg0, label %if.end
+
+ret_arg0:
+  ret ptr %b
+
+if.end:
+  br i1 %cmp, label %ret_arg1, label %ret_undef
+
+ret_arg1:
+  ret ptr %b
+
+ret_undef:
+  ret ptr undef
+}
+
+
+; TEST return undef or argument or argument
+;
+; double* ret_undef_arg_arg(int* b) {
+;   if (b == 0)
+;     return (double*)b;
+;   if (b == 0)
+;     return (double*)b;
+;   /* return undef */
+; }
+;
+define ptr @ret_undef_arg_arg(ptr %b) #0 {
+; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
+; CHECK-LABEL: define {{[^@]+}}@ret_undef_arg_arg
+; CHECK-SAME: (ptr nofree nonnull readnone returned "no-capture-maybe-returned" [[B:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[IF_END:%.*]]
+; CHECK:       ret_undef:
+; CHECK-NEXT:    unreachable
+; CHECK:       if.end:
+; CHECK-NEXT:    br label [[RET_ARG1:%.*]]
+; CHECK:       ret_arg0:
+; CHECK-NEXT:    unreachable
+; CHECK:       ret_arg1:
+; CHECK-NEXT:    ret ptr [[B]]
+;
+entry:
+  %cmp = icmp eq ptr %b, null
+  br i1 %cmp, label %ret_undef, label %if.end
+
+ret_undef:
+  ret ptr undef
+
+if.end:
+  br i1 %cmp, label %ret_arg0, label %ret_arg1
+
+ret_arg0:
+  ret ptr %b
+
+ret_arg1:
+  ret ptr %b
+}
+
+
+; TEST return undef or argument or undef
+;
+; double* ret_undef_arg_undef(int* b) {
+;   if (b == 0)
+;     /* return undef */
+;   if (b == 0)
+;     return (double*)b;
+;   /* return undef */
+; }
+;
+define ptr @ret_undef_arg_undef(ptr %b) #0 {
+; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
+; CHECK-LABEL: define {{[^@]+}}@ret_undef_arg_undef
+; CHECK-SAME: (ptr nocapture nofree nonnull readnone [[B:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[IF_END:%.*]]
+; CHECK:       ret_undef0:
+; CHECK-NEXT:    unreachable
+; CHECK:       if.end:
+; CHECK-NEXT:    br label [[RET_UNDEF1:%.*]]
+; CHECK:       ret_arg:
+; CHECK-NEXT:    unreachable
+; CHECK:       ret_undef1:
+; CHECK-NEXT:    ret ptr undef
+;
+entry:
+  %cmp = icmp eq ptr %b, null
+  br i1 %cmp, label %ret_undef0, label %if.end
+
+ret_undef0:
+  ret ptr undef
+
+if.end:
+  br i1 %cmp, label %ret_arg, label %ret_undef1
+
+ret_arg:
+  ret ptr %b
+
+ret_undef1:
+  ret ptr undef
+}
+
+; TEST return argument or unknown call result
+;
+; int* ret_arg_or_unknown(int* b) {
+;   if (b == 0)
+;     return b;
+;   return unknown();
+; }
+;
+; Verify we do not assume b is returned
+;
+declare ptr @unknown(ptr)
+
+define ptr @ret_arg_or_unknown(ptr %b) #0 {
+; TUNIT: Function Attrs: noinline nounwind uwtable
+; TUNIT-LABEL: define {{[^@]+}}@ret_arg_or_unknown
+; TUNIT-SAME: (ptr nonnull [[B:%.*]]) #[[ATTR5]] {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    br label [[RET_UNKNOWN:%.*]]
+; TUNIT:       ret_arg:
+; TUNIT-NEXT:    unreachable
+; TUNIT:       ret_unknown:
+; TUNIT-NEXT:    [[CALL:%.*]] = call nonnull ptr @unknown(ptr nonnull [[B]])
+; TUNIT-NEXT:    ret ptr [[CALL]]
+;
+; CGSCC: Function Attrs: noinline nounwind uwtable
+; CGSCC-LABEL: define {{[^@]+}}@ret_arg_or_unknown
+; CGSCC-SAME: (ptr nonnull [[B:%.*]]) #[[ATTR4]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    br label [[RET_UNKNOWN:%.*]]
+; CGSCC:       ret_arg:
+; CGSCC-NEXT:    unreachable
+; CGSCC:       ret_unknown:
+; CGSCC-NEXT:    [[CALL:%.*]] = call nonnull ptr @unknown(ptr nonnull [[B]])
+; CGSCC-NEXT:    ret ptr [[CALL]]
+;
+entry:
+  %cmp = icmp eq ptr %b, null
+  br i1 %cmp, label %ret_arg, label %ret_unknown
+
+ret_arg:
+  ret ptr %b
+
+ret_unknown:
+  %call = call ptr @unknown(ptr %b)
+  ret ptr %call
+}
+
+define ptr @ret_arg_or_unknown_through_phi(ptr %b) #0 {
+; TUNIT: Function Attrs: noinline nounwind uwtable
+; TUNIT-LABEL: define {{[^@]+}}@ret_arg_or_unknown_through_phi
+; TUNIT-SAME: (ptr nonnull [[B:%.*]]) #[[ATTR5]] {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    br label [[RET_UNKNOWN:%.*]]
+; TUNIT:       ret_arg:
+; TUNIT-NEXT:    unreachable
+; TUNIT:       ret_unknown:
+; TUNIT-NEXT:    [[CALL:%.*]] = call nonnull ptr @unknown(ptr nonnull [[B]])
+; TUNIT-NEXT:    br label [[R:%.*]]
+; TUNIT:       r:
+; TUNIT-NEXT:    ret ptr [[CALL]]
+;
+; CGSCC: Function Attrs: noinline nounwind uwtable
+; CGSCC-LABEL: define {{[^@]+}}@ret_arg_or_unknown_through_phi
+; CGSCC-SAME: (ptr nonnull [[B:%.*]]) #[[ATTR4]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    br label [[RET_UNKNOWN:%.*]]
+; CGSCC:       ret_arg:
+; CGSCC-NEXT:    unreachable
+; CGSCC:       ret_unknown:
+; CGSCC-NEXT:    [[CALL:%.*]] = call nonnull ptr @unknown(ptr nonnull [[B]])
+; CGSCC-NEXT:    br label [[R:%.*]]
+; CGSCC:       r:
+; CGSCC-NEXT:    ret ptr [[CALL]]
+;
+entry:
+  %cmp = icmp eq ptr %b, null
+  br i1 %cmp, label %ret_arg, label %ret_unknown
+
+ret_arg:
+  br label %r
+
+ret_unknown:
+  %call = call ptr @unknown(ptr %b)
+  br label %r
+
+r:
+  %phi = phi ptr [ %b, %ret_arg ], [ %call, %ret_unknown ]
+  ret ptr %phi
+}
+
+; TEST inconsistent IR in dead code.
+;
+define i32 @deadblockcall1(i32 %A) #0 {
+; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
+; CHECK-LABEL: define {{[^@]+}}@deadblockcall1
+; CHECK-SAME: (i32 returned [[A:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    ret i32 [[A]]
+; CHECK:       unreachableblock:
+; CHECK-NEXT:    unreachable
+;
+entry:
+  ret i32 %A
+unreachableblock:
+  %B = call i32 @deadblockcall1(i32 %B)
+  ret i32 %B
+}
+
+declare i32 @deadblockcall_helper(i32 returned %A);
+
+define i32 @deadblockcall2(i32 %A) #0 {
+; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
+; CHECK-LABEL: define {{[^@]+}}@deadblockcall2
+; CHECK-SAME: (i32 returned [[A:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    ret i32 [[A]]
+; CHECK:       unreachableblock1:
+; CHECK-NEXT:    unreachable
+; CHECK:       unreachableblock2:
+; CHECK-NEXT:    unreachable
+;
+entry:
+  ret i32 %A
+unreachableblock1:
+  %B = call i32 @deadblockcall_helper(i32 %B)
+  ret i32 %B
+unreachableblock2:
+  %C = call i32 @deadblockcall1(i32 %C)
+  ret i32 %C
+}
+
+define i32 @deadblockphi1(i32 %A) #0 {
+; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
+; CHECK-LABEL: define {{[^@]+}}@deadblockphi1
+; CHECK-SAME: (i32 returned [[A:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[R:%.*]]
+; CHECK:       unreachableblock1:
+; CHECK-NEXT:    unreachable
+; CHECK:       unreachableblock2:
+; CHECK-NEXT:    unreachable
+; CHECK:       r:
+; CHECK-NEXT:    ret i32 [[A]]
+;
+entry:
+  br label %r
+unreachableblock1:
+  %B = call i32 @deadblockcall_helper(i32 %B)
+  ret i32 %B
+unreachableblock2:
+  %C = call i32 @deadblockcall1(i32 %C)
+  br label %r
+r:
+  %PHI = phi i32 [%A, %entry], [%C, %unreachableblock2]
+  ret i32 %PHI
+}
+
+define i32 @deadblockphi2(i32 %A) #0 {
+; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
+; CHECK-LABEL: define {{[^@]+}}@deadblockphi2
+; CHECK-SAME: (i32 returned [[A:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[R:%.*]]
+; CHECK:       unreachableblock1:
+; CHECK-NEXT:    unreachable
+; CHECK:       unreachableblock2:
+; CHECK-NEXT:    unreachable
+; CHECK:       unreachableblock3:
+; CHECK-NEXT:    unreachable
+; CHECK:       r:
+; CHECK-NEXT:    ret i32 [[A]]
+;
+entry:
+  br label %r
+unreachableblock1:
+  %B = call i32 @deadblockcall_helper(i32 %B)
+  br label %unreachableblock3
+unreachableblock2:
+  %C = call i32 @deadblockcall1(i32 %C)
+  br label %unreachableblock3
+unreachableblock3:
+  %PHI1 = phi i32 [%B, %unreachableblock1], [%C, %unreachableblock2]
+  br label %r
+r:
+  %PHI2 = phi i32 [%A, %entry], [%PHI1, %unreachableblock3]
+  ret i32 %PHI2
+}
+
+declare void @noreturn() noreturn;
+
+define i32 @deadblockphi3(i32 %A, i1 %c) #0 {
+; TUNIT: Function Attrs: noinline nounwind uwtable
+; TUNIT-LABEL: define {{[^@]+}}@deadblockphi3
+; TUNIT-SAME: (i32 returned [[A:%.*]], i1 noundef [[C:%.*]]) #[[ATTR5]] {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    br i1 [[C]], label [[R:%.*]], label [[UNREACHABLECALL:%.*]]
+; TUNIT:       unreachablecall:
+; TUNIT-NEXT:    call void @noreturn() #[[ATTR6:[0-9]+]]
+; TUNIT-NEXT:    unreachable
+; TUNIT:       unreachableblock2:
+; TUNIT-NEXT:    unreachable
+; TUNIT:       unreachableblock3:
+; TUNIT-NEXT:    unreachable
+; TUNIT:       r:
+; TUNIT-NEXT:    ret i32 [[A]]
+;
+; CGSCC: Function Attrs: noinline nounwind uwtable
+; CGSCC-LABEL: define {{[^@]+}}@deadblockphi3
+; CGSCC-SAME: (i32 returned [[A:%.*]], i1 noundef [[C:%.*]]) #[[ATTR4]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    br i1 [[C]], label [[R:%.*]], label [[UNREACHABLECALL:%.*]]
+; CGSCC:       unreachablecall:
+; CGSCC-NEXT:    call void @noreturn() #[[ATTR5:[0-9]+]]
+; CGSCC-NEXT:    unreachable
+; CGSCC:       unreachableblock2:
+; CGSCC-NEXT:    unreachable
+; CGSCC:       unreachableblock3:
+; CGSCC-NEXT:    unreachable
+; CGSCC:       r:
+; CGSCC-NEXT:    ret i32 [[A]]
+;
+entry:
+  br i1 %c, label %r, label %unreachablecall
+unreachablecall:
+  call void @noreturn();
+  %B = call i32 @deadblockcall_helper(i32 0)
+  br label %unreachableblock3
+unreachableblock2:
+  %C = call i32 @deadblockcall1(i32 %C)
+  br label %unreachableblock3
+unreachableblock3:
+  %PHI1 = phi i32 [%B, %unreachablecall], [%C, %unreachableblock2]
+  br label %r
+r:
+  %PHI2 = phi i32 [%A, %entry], [%PHI1, %unreachableblock3]
+  ret i32 %PHI2
+}
+
+define weak_odr i32 @non_exact_0() {
+; CHECK-LABEL: define {{[^@]+}}@non_exact_0() {
+; CHECK-NEXT:    ret i32 0
+;
+  ret i32 0
+}
+define weak_odr i32 @non_exact_1(i32 %a) {
+; CHECK-LABEL: define {{[^@]+}}@non_exact_1
+; CHECK-SAME: (i32 [[A:%.*]]) {
+; CHECK-NEXT:    ret i32 [[A]]
+;
+  ret i32 %a
+}
+define weak_odr i32 @non_exact_2(i32 returned %a) {
+; CHECK-LABEL: define {{[^@]+}}@non_exact_2
+; CHECK-SAME: (i32 returned [[A:%.*]]) {
+; CHECK-NEXT:    ret i32 [[A]]
+;
+  ret i32 %a
+}
+define weak_odr align 16 ptr @non_exact_3(ptr align 32 returned %a) {
+; CHECK-LABEL: define {{[^@]+}}@non_exact_3
+; CHECK-SAME: (ptr returned align 32 [[A:%.*]]) {
+; CHECK-NEXT:    ret ptr [[A]]
+;
+  ret ptr %a
+}
+define weak_odr align 16 ptr @non_exact_4(ptr align 32 %a) {
+; CHECK-LABEL: define {{[^@]+}}@non_exact_4
+; CHECK-SAME: (ptr align 32 [[A:%.*]]) {
+; CHECK-NEXT:    ret ptr [[A]]
+;
+  ret ptr %a
+}
+; We can use the alignment information of the weak function non_exact_3 argument
+; because it was given to us and not derived.
+; We can use the return information of the weak function non_exact_4.
+; %c2 and %c3 should be replaced but not %c0 or %c1!
+define i32 @exact(ptr align 8 %a, ptr align 8 %b) {
+; CHECK-LABEL: define {{[^@]+}}@exact
+; CHECK-SAME: (ptr nonnull align 8 [[A:%.*]], ptr nonnull align 8 [[B:%.*]]) {
+; CHECK-NEXT:    [[C0:%.*]] = call i32 @non_exact_0()
+; CHECK-NEXT:    [[C1:%.*]] = call i32 @non_exact_1(i32 noundef 1)
+; CHECK-NEXT:    [[C2:%.*]] = call i32 @non_exact_2(i32 noundef 2)
+; CHECK-NEXT:    [[C3:%.*]] = call align 32 ptr @non_exact_3(ptr nonnull align 32 [[A]])
+; CHECK-NEXT:    [[C4:%.*]] = call align 16 ptr @non_exact_4(ptr nonnull align 32 [[B]])
+; CHECK-NEXT:    [[C3L:%.*]] = load i32, ptr [[A]], align 32
+; CHECK-NEXT:    [[C4L:%.*]] = load i32, ptr [[C4]], align 16
+; CHECK-NEXT:    [[ADD1:%.*]] = add i32 [[C0]], [[C1]]
+; CHECK-NEXT:    [[ADD2:%.*]] = add i32 [[ADD1]], 2
+; CHECK-NEXT:    [[ADD3:%.*]] = add i32 [[ADD2]], [[C3L]]
+; CHECK-NEXT:    [[ADD4:%.*]] = add i32 [[ADD3]], [[C4L]]
+; CHECK-NEXT:    ret i32 [[ADD4]]
+;
+  %c0 = call i32 @non_exact_0()
+  %c1 = call i32 @non_exact_1(i32 1)
+  %c2 = call i32 @non_exact_2(i32 2)
+  %c3 = call ptr @non_exact_3(ptr %a)
+  %c4 = call ptr @non_exact_4(ptr %b)
+  %c3l = load i32, ptr %c3
+  %c4l = load i32, ptr %c4
+  %add1 = add i32 %c0, %c1
+  %add2 = add i32 %add1, %c2
+  %add3 = add i32 %add2, %c3l
+  %add4 = add i32 %add3, %c4l
+  ret i32 %add4
+}
+
+ at G = external global i8
+define ptr @ret_const() #0 {
+; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
+; CHECK-LABEL: define {{[^@]+}}@ret_const
+; CHECK-SAME: () #[[ATTR0]] {
+; CHECK-NEXT:    ret ptr @G
+;
+  ret ptr @G
+}
+define ptr @use_const() #0 {
+; TUNIT: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
+; TUNIT-LABEL: define {{[^@]+}}@use_const
+; TUNIT-SAME: () #[[ATTR0]] {
+; TUNIT-NEXT:    ret ptr @G
+;
+; CGSCC: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable
+; CGSCC-LABEL: define {{[^@]+}}@use_const
+; CGSCC-SAME: () #[[ATTR3]] {
+; CGSCC-NEXT:    [[C:%.*]] = call noundef nonnull dereferenceable(1) ptr @ret_const() #[[ATTR10:[0-9]+]]
+; CGSCC-NEXT:    ret ptr [[C]]
+;
+  %c = call ptr @ret_const()
+  ret ptr %c
+}
+define ptr @dont_use_const() #0 {
+; TUNIT: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
+; TUNIT-LABEL: define {{[^@]+}}@dont_use_const
+; TUNIT-SAME: () #[[ATTR0]] {
+; TUNIT-NEXT:    ret ptr @G
+;
+; CGSCC: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable
+; CGSCC-LABEL: define {{[^@]+}}@dont_use_const
+; CGSCC-SAME: () #[[ATTR3]] {
+; CGSCC-NEXT:    [[C:%.*]] = musttail call noundef nonnull dereferenceable(1) ptr @ret_const() #[[ATTR10]]
+; CGSCC-NEXT:    ret ptr [[C]]
+;
+  %c = musttail call ptr @ret_const()
+  ret ptr %c
+}
+
+; UTC_ARGS: --disable
+;
+; Verify we do not derive constraints for @_Z3fooP1X as if it was returning `null`.
+;
+; CHEKC-NOT: noalias
+; CHECK-NOT: align 536870912
+
+%struct.Y = type { %struct.X }
+%struct.X = type { ptr }
+
+ at _ZTI1X = external dso_local constant { ptr, ptr }, align 8
+ at _ZTI1Y = external dso_local constant { ptr, ptr, ptr }, align 8
+
+define internal ptr @_ZN1Y3barEv(ptr %this) align 2 {
+entry:
+  ret ptr %this
+}
+
+define dso_local ptr @_Z3fooP1X(ptr %x) {
+entry:
+  %0 = icmp eq ptr %x, null
+  br i1 %0, label %dynamic_cast.null, label %dynamic_cast.notnull
+
+dynamic_cast.notnull:                             ; preds = %entry
+  %1 = call ptr @__dynamic_cast(ptr %x, ptr @_ZTI1X, ptr @_ZTI1Y, i64 0) #2
+  br label %dynamic_cast.end
+
+dynamic_cast.null:                                ; preds = %entry
+  br label %dynamic_cast.end
+
+dynamic_cast.end:                                 ; preds = %dynamic_cast.null, %dynamic_cast.notnull
+  %QQ5 = phi ptr [ %1, %dynamic_cast.notnull ], [ null, %dynamic_cast.null ]
+  %call = call ptr @_ZN1Y3barEv(ptr %QQ5)
+  ret ptr %call
+}
+
+declare dso_local ptr @__dynamic_cast(ptr, ptr, ptr, i64)
+
+; UTC_ARGS: --enable
+
+attributes #0 = { noinline nounwind uwtable }
+;.
+; TUNIT: attributes #[[ATTR0]] = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable }
+; TUNIT: attributes #[[ATTR1]] = { nofree noinline nosync nounwind memory(none) uwtable }
+; TUNIT: attributes #[[ATTR2]] = { nofree noinline norecurse nosync nounwind memory(none) uwtable }
+; TUNIT: attributes #[[ATTR3]] = { nofree noinline nosync nounwind memory(argmem: read) uwtable }
+; TUNIT: attributes #[[ATTR4]] = { mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable }
+; TUNIT: attributes #[[ATTR5]] = { noinline nounwind uwtable }
+; TUNIT: attributes #[[ATTR6]] = { noreturn }
+; TUNIT: attributes #[[ATTR7:[0-9]+]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
+; TUNIT: attributes #[[ATTR8]] = { nofree nosync nounwind memory(none) }
+; TUNIT: attributes #[[ATTR9]] = { nofree nosync nounwind memory(read) }
+; TUNIT: attributes #[[ATTR10]] = { nounwind }
+; TUNIT: attributes #[[ATTR11:[0-9]+]] = { nounwind memory(none) }
+;.
+; CGSCC: attributes #[[ATTR0]] = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable }
+; CGSCC: attributes #[[ATTR1]] = { nofree noinline nosync nounwind memory(none) uwtable }
+; CGSCC: attributes #[[ATTR2]] = { nofree noinline nosync nounwind memory(argmem: read) uwtable }
+; CGSCC: attributes #[[ATTR3]] = { mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable }
+; CGSCC: attributes #[[ATTR4]] = { noinline nounwind uwtable }
+; CGSCC: attributes #[[ATTR5]] = { noreturn }
+; CGSCC: attributes #[[ATTR6:[0-9]+]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
+; CGSCC: attributes #[[ATTR7]] = { nofree nosync nounwind memory(none) }
+; CGSCC: attributes #[[ATTR8]] = { nofree nosync nounwind memory(read) }
+; CGSCC: attributes #[[ATTR9]] = { nounwind }
+; CGSCC: attributes #[[ATTR10]] = { nofree nosync willreturn }
+;.
diff --git a/llvm/test/Transforms/Attributor/value-simplify-dl-sentinel.ll b/llvm/test/Transforms/Attributor/value-simplify-dl-sentinel.ll
new file mode 100755
index 0000000000000..c01c4418ffb85
--- /dev/null
+++ b/llvm/test/Transforms/Attributor/value-simplify-dl-sentinel.ll
@@ -0,0 +1,1732 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal  -attributor-annotate-decl-cs  -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal  -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
+
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-z0:1-z2:neg1-z3:neg1-z5:neg1-S128"
+declare void @f(i32)
+declare token @llvm.call.preallocated.setup(i32)
+declare ptr @llvm.call.preallocated.arg(token, i32)
+
+ at str = private unnamed_addr addrspace(4) constant [1 x i8] c"\00", align 1
+ at ConstAS3Ptr = addrspace(3) global i32 0, align 4
+ at ConstPtr = constant i32 0, align 4
+ at ConstWeakPtr = weak constant i32 0, align 4
+ at ConstWeakODRPtr = weak_odr constant i32 0, align 4
+
+;.
+; CHECK: @str = private unnamed_addr addrspace(4) constant [1 x i8] zeroinitializer, align 1
+; CHECK: @ConstAS3Ptr = addrspace(3) global i32 0, align 4
+; CHECK: @ConstPtr = constant i32 0, align 4
+; CHECK: @ConstWeakPtr = weak constant i32 0, align 4
+; CHECK: @ConstWeakODRPtr = weak_odr constant i32 0, align 4
+; CHECK: @S = external global %struct.X
+; CHECK: @g = internal constant { [2 x ptr] } { [2 x ptr] [ptr @f1, ptr @f2] }
+; CHECK: @x = external global i32
+;.
+define internal ptr addrspace(3) @const_ptr_return_as3() {
+; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@const_ptr_return_as3
+; CGSCC-SAME: () #[[ATTR1:[0-9]+]] {
+; CGSCC-NEXT:    ret ptr addrspace(3) @ConstAS3Ptr
+;
+  ret ptr addrspace(3) @ConstAS3Ptr
+}
+define internal ptr @const_ptr_return() {
+; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@const_ptr_return
+; CGSCC-SAME: () #[[ATTR1]] {
+; CGSCC-NEXT:    ret ptr addrspacecast (ptr addrspace(3) @ConstAS3Ptr to ptr)
+;
+  ret ptr addrspacecast (ptr addrspace(3) @ConstAS3Ptr to ptr)
+}
+
+; Test1: Replace argument with constant
+define internal void @test1(i32 %a) {
+; TUNIT: Function Attrs: memory(readwrite, argmem: none)
+; TUNIT-LABEL: define {{[^@]+}}@test1
+; TUNIT-SAME: () #[[ATTR1:[0-9]+]] {
+; TUNIT-NEXT:    tail call void @f(i32 noundef 1)
+; TUNIT-NEXT:    ret void
+;
+; CGSCC: Function Attrs: memory(readwrite, argmem: none)
+; CGSCC-LABEL: define {{[^@]+}}@test1
+; CGSCC-SAME: () #[[ATTR2:[0-9]+]] {
+; CGSCC-NEXT:    tail call void @f(i32 noundef 1)
+; CGSCC-NEXT:    ret void
+;
+  tail call void @f(i32 %a)
+  ret void
+}
+
+define void @test1_helper() {
+; CHECK-LABEL: define {{[^@]+}}@test1_helper() {
+; CHECK-NEXT:    tail call void @test1()
+; CHECK-NEXT:    ret void
+;
+  tail call void @test1(i32 1)
+  ret void
+}
+
+; TEST 2 : Simplify return value
+define i32 @return0() {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; TUNIT-LABEL: define {{[^@]+}}@return0
+; TUNIT-SAME: () #[[ATTR2:[0-9]+]] {
+; TUNIT-NEXT:    ret i32 0
+;
+; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@return0
+; CGSCC-SAME: () #[[ATTR1]] {
+; CGSCC-NEXT:    ret i32 0
+;
+  ret i32 0
+}
+
+define i32 @return1() {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; TUNIT-LABEL: define {{[^@]+}}@return1
+; TUNIT-SAME: () #[[ATTR2]] {
+; TUNIT-NEXT:    ret i32 1
+;
+; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@return1
+; CGSCC-SAME: () #[[ATTR1]] {
+; CGSCC-NEXT:    ret i32 1
+;
+  ret i32 1
+}
+
+define i32 @test2_1(i1 %c) {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; TUNIT-LABEL: define {{[^@]+}}@test2_1
+; TUNIT-SAME: (i1 noundef [[C:%.*]]) #[[ATTR2]] {
+; TUNIT-NEXT:    br i1 [[C]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
+; TUNIT:       if.true:
+; TUNIT-NEXT:    [[RET0:%.*]] = add i32 0, 1
+; TUNIT-NEXT:    br label [[END:%.*]]
+; TUNIT:       if.false:
+; TUNIT-NEXT:    br label [[END]]
+; TUNIT:       end:
+; TUNIT-NEXT:    [[RET:%.*]] = phi i32 [ [[RET0]], [[IF_TRUE]] ], [ 1, [[IF_FALSE]] ]
+; TUNIT-NEXT:    ret i32 1
+;
+; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@test2_1
+; CGSCC-SAME: (i1 noundef [[C:%.*]]) #[[ATTR3:[0-9]+]] {
+; CGSCC-NEXT:    br i1 [[C]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
+; CGSCC:       if.true:
+; CGSCC-NEXT:    [[CALL:%.*]] = tail call i32 @return0() #[[ATTR12:[0-9]+]]
+; CGSCC-NEXT:    [[RET0:%.*]] = add i32 [[CALL]], 1
+; CGSCC-NEXT:    br label [[END:%.*]]
+; CGSCC:       if.false:
+; CGSCC-NEXT:    [[RET1:%.*]] = tail call i32 @return1() #[[ATTR12]]
+; CGSCC-NEXT:    br label [[END]]
+; CGSCC:       end:
+; CGSCC-NEXT:    [[RET:%.*]] = phi i32 [ [[RET0]], [[IF_TRUE]] ], [ [[RET1]], [[IF_FALSE]] ]
+; CGSCC-NEXT:    ret i32 1
+;
+  br i1 %c, label %if.true, label %if.false
+if.true:
+  %call = tail call i32 @return0()
+  %ret0 = add i32 %call, 1
+  br label %end
+if.false:
+  %ret1 = tail call i32 @return1()
+  br label %end
+end:
+
+  %ret = phi i32 [ %ret0, %if.true ], [ %ret1, %if.false ]
+
+  ret i32 1
+}
+
+
+
+define i32 @test2_2(i1 %c) {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; TUNIT-LABEL: define {{[^@]+}}@test2_2
+; TUNIT-SAME: (i1 [[C:%.*]]) #[[ATTR2]] {
+; TUNIT-NEXT:    ret i32 1
+;
+; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@test2_2
+; CGSCC-SAME: (i1 noundef [[C:%.*]]) #[[ATTR3]] {
+; CGSCC-NEXT:    [[RET:%.*]] = tail call noundef i32 @test2_1(i1 noundef [[C]]) #[[ATTR12]]
+; CGSCC-NEXT:    ret i32 [[RET]]
+;
+  %ret = tail call i32 @test2_1(i1 %c)
+  ret i32 %ret
+}
+
+declare void @use(i32)
+define void @test3(i1 %c) {
+; TUNIT-LABEL: define {{[^@]+}}@test3
+; TUNIT-SAME: (i1 noundef [[C:%.*]]) {
+; TUNIT-NEXT:    br i1 [[C]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
+; TUNIT:       if.true:
+; TUNIT-NEXT:    br label [[END:%.*]]
+; TUNIT:       if.false:
+; TUNIT-NEXT:    br label [[END]]
+; TUNIT:       end:
+; TUNIT-NEXT:    [[R:%.*]] = phi i32 [ 1, [[IF_TRUE]] ], [ 1, [[IF_FALSE]] ]
+; TUNIT-NEXT:    tail call void @use(i32 noundef 1)
+; TUNIT-NEXT:    ret void
+;
+; CGSCC-LABEL: define {{[^@]+}}@test3
+; CGSCC-SAME: (i1 noundef [[C:%.*]]) {
+; CGSCC-NEXT:    br i1 [[C]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
+; CGSCC:       if.true:
+; CGSCC-NEXT:    br label [[END:%.*]]
+; CGSCC:       if.false:
+; CGSCC-NEXT:    [[RET1:%.*]] = tail call i32 @return1() #[[ATTR13:[0-9]+]]
+; CGSCC-NEXT:    br label [[END]]
+; CGSCC:       end:
+; CGSCC-NEXT:    [[R:%.*]] = phi i32 [ 1, [[IF_TRUE]] ], [ [[RET1]], [[IF_FALSE]] ]
+; CGSCC-NEXT:    tail call void @use(i32 noundef [[R]])
+; CGSCC-NEXT:    ret void
+;
+  br i1 %c, label %if.true, label %if.false
+if.true:
+  br label %end
+if.false:
+  %ret1 = tail call i32 @return1()
+  br label %end
+end:
+
+  %r = phi i32 [ 1, %if.true ], [ %ret1, %if.false ]
+
+  tail call void @use(i32 %r)
+  ret void
+}
+
+define void @test-select-phi(i1 %c) {
+; CHECK-LABEL: define {{[^@]+}}@test-select-phi
+; CHECK-SAME: (i1 [[C:%.*]]) {
+; CHECK-NEXT:    tail call void @use(i32 noundef 1)
+; CHECK-NEXT:    [[SELECT_NOT_SAME:%.*]] = select i1 [[C]], i32 1, i32 0
+; CHECK-NEXT:    tail call void @use(i32 noundef [[SELECT_NOT_SAME]])
+; CHECK-NEXT:    br i1 [[C]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
+; CHECK:       if-true:
+; CHECK-NEXT:    br label [[END:%.*]]
+; CHECK:       if-false:
+; CHECK-NEXT:    br label [[END]]
+; CHECK:       end:
+; CHECK-NEXT:    [[PHI_SAME:%.*]] = phi i32 [ 1, [[IF_TRUE]] ], [ 1, [[IF_FALSE]] ]
+; CHECK-NEXT:    [[PHI_NOT_SAME:%.*]] = phi i32 [ 0, [[IF_TRUE]] ], [ 1, [[IF_FALSE]] ]
+; CHECK-NEXT:    [[PHI_SAME_PROP:%.*]] = phi i32 [ 1, [[IF_TRUE]] ], [ 1, [[IF_FALSE]] ]
+; CHECK-NEXT:    [[PHI_SAME_UNDEF:%.*]] = phi i32 [ 1, [[IF_TRUE]] ], [ undef, [[IF_FALSE]] ]
+; CHECK-NEXT:    [[SELECT_NOT_SAME_UNDEF:%.*]] = select i1 [[C]], i32 [[PHI_NOT_SAME]], i32 undef
+; CHECK-NEXT:    tail call void @use(i32 noundef 1)
+; CHECK-NEXT:    tail call void @use(i32 noundef [[PHI_NOT_SAME]])
+; CHECK-NEXT:    tail call void @use(i32 noundef 1)
+; CHECK-NEXT:    tail call void @use(i32 1)
+; CHECK-NEXT:    tail call void @use(i32 [[SELECT_NOT_SAME_UNDEF]])
+; CHECK-NEXT:    ret void
+;
+  %select-same = select i1 %c, i32 1, i32 1
+  tail call void @use(i32 %select-same)
+
+  %select-not-same = select i1 %c, i32 1, i32 0
+  tail call void @use(i32 %select-not-same)
+  br i1 %c, label %if-true, label %if-false
+if-true:
+  br label %end
+if-false:
+  br label %end
+end:
+  %phi-same = phi i32 [ 1, %if-true ], [ 1, %if-false ]
+  %phi-not-same = phi i32 [ 0, %if-true ], [ 1, %if-false ]
+  %phi-same-prop = phi i32 [ 1, %if-true ], [ %select-same, %if-false ]
+  %phi-same-undef = phi i32 [ 1, %if-true ], [ undef, %if-false ]
+  %select-not-same-undef = select i1 %c, i32 %phi-not-same, i32 undef
+
+
+  tail call void @use(i32 %phi-same)
+
+  tail call void @use(i32 %phi-not-same)
+
+  tail call void @use(i32 %phi-same-prop)
+
+  tail call void @use(i32 %phi-same-undef)
+
+  tail call void @use(i32 %select-not-same-undef)
+
+  ret void
+
+}
+
+define i32 @ipccp1(i32 %a) {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; TUNIT-LABEL: define {{[^@]+}}@ipccp1
+; TUNIT-SAME: (i32 returned [[A:%.*]]) #[[ATTR2]] {
+; TUNIT-NEXT:    br i1 true, label [[T:%.*]], label [[F:%.*]]
+; TUNIT:       t:
+; TUNIT-NEXT:    ret i32 [[A]]
+; TUNIT:       f:
+; TUNIT-NEXT:    unreachable
+;
+; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@ipccp1
+; CGSCC-SAME: (i32 returned [[A:%.*]]) #[[ATTR1]] {
+; CGSCC-NEXT:    br i1 true, label [[T:%.*]], label [[F:%.*]]
+; CGSCC:       t:
+; CGSCC-NEXT:    ret i32 [[A]]
+; CGSCC:       f:
+; CGSCC-NEXT:    unreachable
+;
+  br i1 true, label %t, label %f
+t:
+  ret i32 %a
+f:
+  %r = call i32 @ipccp1(i32 5)
+  ret i32 %r
+}
+
+define internal i1 @ipccp2i(i1 %a) {
+; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@ipccp2i
+; CGSCC-SAME: () #[[ATTR1]] {
+; CGSCC-NEXT:    br label [[T:%.*]]
+; CGSCC:       t:
+; CGSCC-NEXT:    ret i1 true
+; CGSCC:       f:
+; CGSCC-NEXT:    unreachable
+;
+  br i1 %a, label %t, label %f
+t:
+  ret i1 %a
+f:
+  %r = call i1 @ipccp2i(i1 false)
+  ret i1 %r
+}
+
+define i1 @ipccp2() {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; TUNIT-LABEL: define {{[^@]+}}@ipccp2
+; TUNIT-SAME: () #[[ATTR2]] {
+; TUNIT-NEXT:    ret i1 true
+;
+; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@ipccp2
+; CGSCC-SAME: () #[[ATTR3]] {
+; CGSCC-NEXT:    [[R:%.*]] = call noundef i1 @ipccp2i() #[[ATTR12]]
+; CGSCC-NEXT:    ret i1 [[R]]
+;
+  %r = call i1 @ipccp2i(i1 true)
+  ret i1 %r
+}
+
+define internal i1 @ipccp2ib(i1 %a) {
+; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@ipccp2ib
+; CGSCC-SAME: () #[[ATTR1]] {
+; CGSCC-NEXT:    br label [[T:%.*]]
+; CGSCC:       t:
+; CGSCC-NEXT:    ret i1 true
+; CGSCC:       f:
+; CGSCC-NEXT:    unreachable
+;
+  br i1 %a, label %t, label %f
+t:
+  ret i1 true
+f:
+  %r = call i1 @ipccp2ib(i1 false)
+  ret i1 %r
+}
+
+define i1 @ipccp2b() {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; TUNIT-LABEL: define {{[^@]+}}@ipccp2b
+; TUNIT-SAME: () #[[ATTR2]] {
+; TUNIT-NEXT:    ret i1 true
+;
+; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@ipccp2b
+; CGSCC-SAME: () #[[ATTR3]] {
+; CGSCC-NEXT:    [[R:%.*]] = call noundef i1 @ipccp2ib() #[[ATTR12]]
+; CGSCC-NEXT:    ret i1 [[R]]
+;
+  %r = call i1 @ipccp2ib(i1 true)
+  ret i1 %r
+}
+
+define internal i32 @ipccp3i(i32 %a) {
+; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@ipccp3i
+; CGSCC-SAME: () #[[ATTR1]] {
+; CGSCC-NEXT:    br label [[T:%.*]]
+; CGSCC:       t:
+; CGSCC-NEXT:    ret i32 7
+; CGSCC:       f:
+; CGSCC-NEXT:    unreachable
+;
+  %c = icmp eq i32 %a, 7
+  br i1 %c, label %t, label %f
+t:
+  ret i32 %a
+f:
+  %r = call i32 @ipccp3i(i32 5)
+  ret i32 %r
+}
+
+define i32 @ipccp3() {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; TUNIT-LABEL: define {{[^@]+}}@ipccp3
+; TUNIT-SAME: () #[[ATTR2]] {
+; TUNIT-NEXT:    ret i32 7
+;
+; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@ipccp3
+; CGSCC-SAME: () #[[ATTR3]] {
+; CGSCC-NEXT:    [[R:%.*]] = call noundef i32 @ipccp3i() #[[ATTR12]]
+; CGSCC-NEXT:    ret i32 [[R]]
+;
+  %r = call i32 @ipccp3i(i32 7)
+  ret i32 %r
+}
+
+define internal i32 @ipccp4ia(i1 %c) {
+; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@ipccp4ia
+; CGSCC-SAME: (i1 noundef [[C:%.*]]) #[[ATTR1]] {
+; CGSCC-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
+; CGSCC:       t:
+; CGSCC-NEXT:    ret i32 0
+; CGSCC:       f:
+; CGSCC-NEXT:    ret i32 1
+;
+  br i1 %c, label %t, label %f
+t:
+  ret i32 0
+f:
+  ret i32 1
+}
+define internal i32 @ipccp4ib(i32 %a) {
+; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@ipccp4ib
+; CGSCC-SAME: () #[[ATTR3]] {
+; CGSCC-NEXT:    br label [[T:%.*]]
+; CGSCC:       t:
+; CGSCC-NEXT:    [[R:%.*]] = call noundef i32 @ipccp4ia(i1 noundef true) #[[ATTR12]]
+; CGSCC-NEXT:    ret i32 [[R]]
+; CGSCC:       f:
+; CGSCC-NEXT:    unreachable
+;
+  %c = icmp eq i32 %a, 7
+  br i1 %c, label %t, label %f
+t:
+  %r = call i32 @ipccp4ia(i1 %c)
+  ret i32 %r
+f:
+  ret i32 1
+}
+
+define i32 @ipccp4(i1 %c) {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; TUNIT-LABEL: define {{[^@]+}}@ipccp4
+; TUNIT-SAME: (i1 noundef [[C:%.*]]) #[[ATTR2]] {
+; TUNIT-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
+; TUNIT:       t:
+; TUNIT-NEXT:    br label [[F]]
+; TUNIT:       f:
+; TUNIT-NEXT:    ret i32 0
+;
+; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@ipccp4
+; CGSCC-SAME: (i1 noundef [[C:%.*]]) #[[ATTR3]] {
+; CGSCC-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
+; CGSCC:       t:
+; CGSCC-NEXT:    br label [[F]]
+; CGSCC:       f:
+; CGSCC-NEXT:    [[R:%.*]] = call noundef i32 @ipccp4ib() #[[ATTR12]]
+; CGSCC-NEXT:    ret i32 [[R]]
+;
+  br i1 %c, label %t, label %f
+t:
+  %q = call i32 @ipccp4ia(i1 undef)
+  br label %f
+f:
+  %r = call i32 @ipccp4ib(i32 7)
+  ret i32 %r
+}
+
+; Do not touch complicated arguments (for now)
+%struct.X = type { ptr }
+define internal ptr @test_inalloca(ptr inalloca(i32) %a) {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; TUNIT-LABEL: define {{[^@]+}}@test_inalloca
+; TUNIT-SAME: (ptr noalias nofree nonnull returned writeonly inalloca(i32) dereferenceable(4) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR2]] {
+; TUNIT-NEXT:    ret ptr [[A]]
+;
+; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@test_inalloca
+; CGSCC-SAME: (ptr noalias nofree noundef nonnull returned writeonly inalloca(i32) dereferenceable(4) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR1]] {
+; CGSCC-NEXT:    ret ptr [[A]]
+;
+  ret ptr %a
+}
+define ptr @complicated_args_inalloca(ptr %arg) {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; TUNIT-LABEL: define {{[^@]+}}@complicated_args_inalloca
+; TUNIT-SAME: (ptr nofree nonnull readnone "no-capture-maybe-returned" [[ARG:%.*]]) #[[ATTR2]] {
+; TUNIT-NEXT:    [[CALL:%.*]] = call nonnull dereferenceable(4) ptr @test_inalloca(ptr noalias nofree nonnull writeonly inalloca(i32) "no-capture-maybe-returned" [[ARG]]) #[[ATTR9:[0-9]+]]
+; TUNIT-NEXT:    ret ptr [[CALL]]
+;
+; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@complicated_args_inalloca
+; CGSCC-SAME: (ptr nofree noundef nonnull readnone dereferenceable(4) [[ARG:%.*]]) #[[ATTR3]] {
+; CGSCC-NEXT:    [[CALL:%.*]] = call noalias noundef nonnull dereferenceable(4) ptr @test_inalloca(ptr noalias nofree noundef nonnull writeonly inalloca(i32) dereferenceable(4) [[ARG]]) #[[ATTR12]]
+; CGSCC-NEXT:    ret ptr [[CALL]]
+;
+  %call = call ptr @test_inalloca(ptr inalloca(i32) %arg)
+  ret ptr %call
+}
+
+define internal ptr @test_preallocated(ptr preallocated(i32) %a) {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; TUNIT-LABEL: define {{[^@]+}}@test_preallocated
+; TUNIT-SAME: (ptr noalias nofree noundef nonnull returned writeonly preallocated(i32) align 4294967296 dereferenceable(4) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR2]] {
+; TUNIT-NEXT:    ret ptr [[A]]
+;
+; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@test_preallocated
+; CGSCC-SAME: (ptr noalias nofree noundef nonnull returned writeonly preallocated(i32) align 4294967296 dereferenceable(4) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR1]] {
+; CGSCC-NEXT:    ret ptr [[A]]
+;
+  ret ptr %a
+}
+define ptr @complicated_args_preallocated() {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn
+; TUNIT-LABEL: define {{[^@]+}}@complicated_args_preallocated
+; TUNIT-SAME: () #[[ATTR3:[0-9]+]] {
+; TUNIT-NEXT:    [[C:%.*]] = call token @llvm.call.preallocated.setup(i32 noundef 1) #[[ATTR10:[0-9]+]]
+; TUNIT-NEXT:    [[CALL:%.*]] = call noundef nonnull align 4294967296 dereferenceable(4) ptr @test_preallocated(ptr nofree noundef writeonly preallocated(i32) align 4294967296 null) #[[ATTR9]] [ "preallocated"(token [[C]]) ]
+; TUNIT-NEXT:    ret ptr [[CALL]]
+;
+; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn
+; CGSCC-LABEL: define {{[^@]+}}@complicated_args_preallocated
+; CGSCC-SAME: () #[[ATTR4:[0-9]+]] {
+; CGSCC-NEXT:    [[C:%.*]] = call token @llvm.call.preallocated.setup(i32 noundef 1) #[[ATTR13]]
+; CGSCC-NEXT:    [[CALL:%.*]] = call ptr @test_preallocated(ptr nofree noundef writeonly preallocated(i32) align 4294967296 null) #[[ATTR14:[0-9]+]] [ "preallocated"(token [[C]]) ]
+; CGSCC-NEXT:    unreachable
+;
+  %c = call token @llvm.call.preallocated.setup(i32 1)
+  %call = call ptr @test_preallocated(ptr preallocated(i32) null) ["preallocated"(token %c)]
+  ret ptr %call
+}
+
+define internal void @test_sret(ptr sret(%struct.X) %a, ptr %b) {
+;
+; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
+; CGSCC-LABEL: define {{[^@]+}}@test_sret
+; CGSCC-SAME: (ptr noalias nofree noundef nonnull writeonly sret([[STRUCT_X:%.*]]) align 4294967296 dereferenceable(8) [[A:%.*]], ptr nocapture nofree noundef nonnull writeonly align 8 dereferenceable(8) [[B:%.*]]) #[[ATTR5:[0-9]+]] {
+; CGSCC-NEXT:    store ptr [[A]], ptr [[B]], align 8
+; CGSCC-NEXT:    ret void
+;
+  store ptr %a, ptr %b
+  ret void
+}
+; FIXME: Alignment and dereferenceability are not propagated to the argument
+define void @complicated_args_sret(ptr %b) {
+;
+;
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
+; TUNIT-LABEL: define {{[^@]+}}@complicated_args_sret
+; TUNIT-SAME: (ptr nocapture nofree nonnull writeonly [[B:%.*]]) #[[ATTR4:[0-9]+]] {
+; TUNIT-NEXT:    unreachable
+;
+; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(argmem: write)
+; CGSCC-LABEL: define {{[^@]+}}@complicated_args_sret
+; CGSCC-SAME: (ptr nocapture nofree noundef nonnull writeonly align 8 dereferenceable(8) [[B:%.*]]) #[[ATTR6:[0-9]+]] {
+; CGSCC-NEXT:    unreachable
+;
+  call void @test_sret(ptr sret(%struct.X) null, ptr %b)
+  ret void
+}
+
+define internal ptr @test_nest(ptr nest %a) {
+; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@test_nest
+; CGSCC-SAME: (ptr nest noalias nocapture nofree nonnull readnone align 4294967296 [[A:%.*]]) #[[ATTR1]] {
+; CGSCC-NEXT:    unreachable
+;
+  ret ptr %a
+}
+define ptr @complicated_args_nest() {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; TUNIT-LABEL: define {{[^@]+}}@complicated_args_nest
+; TUNIT-SAME: () #[[ATTR2]] {
+; TUNIT-NEXT:    unreachable
+;
+; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@complicated_args_nest
+; CGSCC-SAME: () #[[ATTR3]] {
+; CGSCC-NEXT:    unreachable
+;
+  %call = call ptr @test_nest(ptr null)
+  ret ptr %call
+}
+
+ at S = external global %struct.X
+define internal void @test_byval(ptr byval(%struct.X) %a) {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
+; TUNIT-LABEL: define {{[^@]+}}@test_byval
+; TUNIT-SAME: (ptr [[TMP0:%.*]]) #[[ATTR4]] {
+; TUNIT-NEXT:    [[A_PRIV:%.*]] = alloca [[STRUCT_X:%.*]], align 8
+; TUNIT-NEXT:    store ptr [[TMP0]], ptr [[A_PRIV]], align 8
+; TUNIT-NEXT:    store ptr null, ptr [[A_PRIV]], align 8
+; TUNIT-NEXT:    ret void
+;
+; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
+; CGSCC-LABEL: define {{[^@]+}}@test_byval
+; CGSCC-SAME: (ptr nofree nonnull [[TMP0:%.*]]) #[[ATTR5]] {
+; CGSCC-NEXT:    [[A_PRIV:%.*]] = alloca [[STRUCT_X:%.*]], align 8
+; CGSCC-NEXT:    store ptr [[TMP0]], ptr [[A_PRIV]], align 8
+; CGSCC-NEXT:    store ptr null, ptr [[A_PRIV]], align 8
+; CGSCC-NEXT:    ret void
+;
+  store ptr null, ptr %a
+  ret void
+}
+define void @complicated_args_byval() {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write)
+; TUNIT-LABEL: define {{[^@]+}}@complicated_args_byval
+; TUNIT-SAME: () #[[ATTR5:[0-9]+]] {
+; TUNIT-NEXT:    [[TMP1:%.*]] = load ptr, ptr @S, align 8
+; TUNIT-NEXT:    call void @test_byval(ptr [[TMP1]]) #[[ATTR11:[0-9]+]]
+; TUNIT-NEXT:    ret void
+;
+; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn
+; CGSCC-LABEL: define {{[^@]+}}@complicated_args_byval
+; CGSCC-SAME: () #[[ATTR4]] {
+; CGSCC-NEXT:    [[TMP1:%.*]] = load ptr, ptr @S, align 8
+; CGSCC-NEXT:    call void @test_byval(ptr nofree nonnull writeonly [[TMP1]]) #[[ATTR15:[0-9]+]]
+; CGSCC-NEXT:    ret void
+;
+  call void @test_byval(ptr byval(%struct.X) @S)
+  ret void
+}
+
+declare void @sync()
+; Make sure we *do not* load @S here!
+define internal ptr @test_byval2(ptr byval(%struct.X) %a) {
+; TUNIT-LABEL: define {{[^@]+}}@test_byval2
+; TUNIT-SAME: (ptr [[TMP0:%.*]]) {
+; TUNIT-NEXT:    [[A_PRIV:%.*]] = alloca [[STRUCT_X:%.*]], align 8
+; TUNIT-NEXT:    store ptr [[TMP0]], ptr [[A_PRIV]], align 8
+; TUNIT-NEXT:    call void @sync()
+; TUNIT-NEXT:    [[L:%.*]] = load ptr, ptr [[A_PRIV]], align 8
+; TUNIT-NEXT:    ret ptr [[L]]
+;
+; CGSCC-LABEL: define {{[^@]+}}@test_byval2
+; CGSCC-SAME: (ptr nonnull [[TMP0:%.*]]) {
+; CGSCC-NEXT:    [[A_PRIV:%.*]] = alloca [[STRUCT_X:%.*]], align 8
+; CGSCC-NEXT:    store ptr [[TMP0]], ptr [[A_PRIV]], align 8
+; CGSCC-NEXT:    call void @sync()
+; CGSCC-NEXT:    [[L:%.*]] = load ptr, ptr [[A_PRIV]], align 8
+; CGSCC-NEXT:    ret ptr [[L]]
+;
+  call void @sync()
+  %l = load ptr, ptr %a
+  ret ptr %l
+}
+define ptr @complicated_args_byval2() {
+;
+; TUNIT-LABEL: define {{[^@]+}}@complicated_args_byval2() {
+; TUNIT-NEXT:    [[TMP1:%.*]] = load ptr, ptr @S, align 8
+; TUNIT-NEXT:    [[C:%.*]] = call nonnull ptr @test_byval2(ptr [[TMP1]])
+; TUNIT-NEXT:    ret ptr [[C]]
+;
+; CGSCC-LABEL: define {{[^@]+}}@complicated_args_byval2() {
+; CGSCC-NEXT:    [[TMP1:%.*]] = load ptr, ptr @S, align 8
+; CGSCC-NEXT:    [[C:%.*]] = call nonnull ptr @test_byval2(ptr nonnull [[TMP1]])
+; CGSCC-NEXT:    ret ptr [[C]]
+;
+  %c = call ptr @test_byval2(ptr byval(%struct.X) @S)
+  ret ptr %c
+}
+
+define void @fixpoint_changed(ptr %p) {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
+; TUNIT-LABEL: define {{[^@]+}}@fixpoint_changed
+; TUNIT-SAME: (ptr nocapture nofree nonnull writeonly [[P:%.*]]) #[[ATTR4]] {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    br label [[FOR_COND:%.*]]
+; TUNIT:       for.cond:
+; TUNIT-NEXT:    [[J_0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[SW_EPILOG:%.*]] ]
+; TUNIT-NEXT:    [[CMP:%.*]] = icmp slt i32 [[J_0]], 30
+; TUNIT-NEXT:    br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]]
+; TUNIT:       for.body:
+; TUNIT-NEXT:    switch i32 [[J_0]], label [[SW_EPILOG]] [
+; TUNIT-NEXT:      i32 1, label [[SW_BB:%.*]]
+; TUNIT-NEXT:    ]
+; TUNIT:       sw.bb:
+; TUNIT-NEXT:    br label [[SW_EPILOG]]
+; TUNIT:       sw.epilog:
+; TUNIT-NEXT:    [[X_0:%.*]] = phi i32 [ 255, [[FOR_BODY]] ], [ 253, [[SW_BB]] ]
+; TUNIT-NEXT:    store i32 [[X_0]], ptr [[P]], align 4
+; TUNIT-NEXT:    [[INC]] = add nsw i32 [[J_0]], 1
+; TUNIT-NEXT:    br label [[FOR_COND]]
+; TUNIT:       for.end:
+; TUNIT-NEXT:    ret void
+;
+; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
+; CGSCC-LABEL: define {{[^@]+}}@fixpoint_changed
+; CGSCC-SAME: (ptr nocapture nofree nonnull writeonly [[P:%.*]]) #[[ATTR5]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    br label [[FOR_COND:%.*]]
+; CGSCC:       for.cond:
+; CGSCC-NEXT:    [[J_0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[SW_EPILOG:%.*]] ]
+; CGSCC-NEXT:    [[CMP:%.*]] = icmp slt i32 [[J_0]], 30
+; CGSCC-NEXT:    br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]]
+; CGSCC:       for.body:
+; CGSCC-NEXT:    switch i32 [[J_0]], label [[SW_EPILOG]] [
+; CGSCC-NEXT:      i32 1, label [[SW_BB:%.*]]
+; CGSCC-NEXT:    ]
+; CGSCC:       sw.bb:
+; CGSCC-NEXT:    br label [[SW_EPILOG]]
+; CGSCC:       sw.epilog:
+; CGSCC-NEXT:    [[X_0:%.*]] = phi i32 [ 255, [[FOR_BODY]] ], [ 253, [[SW_BB]] ]
+; CGSCC-NEXT:    store i32 [[X_0]], ptr [[P]], align 4
+; CGSCC-NEXT:    [[INC]] = add nsw i32 [[J_0]], 1
+; CGSCC-NEXT:    br label [[FOR_COND]]
+; CGSCC:       for.end:
+; CGSCC-NEXT:    ret void
+;
+entry:
+  br label %for.cond
+
+for.cond:
+  %j.0 = phi i32 [ 0, %entry ], [ %inc, %sw.epilog ]
+  %cmp = icmp slt i32 %j.0, 30
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:
+  switch i32 %j.0, label %sw.epilog [
+  i32 1, label %sw.bb
+  ]
+
+sw.bb:
+  br label %sw.epilog
+
+sw.epilog:
+  %x.0 = phi i32 [ 255, %for.body ], [ 253, %sw.bb ]
+  store i32 %x.0, ptr %p
+  %inc = add nsw i32 %j.0, 1
+  br label %for.cond
+
+for.end:
+  ret void
+}
+
+; Check we merge undef and a constant properly.
+define i8 @caller0() {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; TUNIT-LABEL: define {{[^@]+}}@caller0
+; TUNIT-SAME: () #[[ATTR2]] {
+; TUNIT-NEXT:    ret i8 49
+;
+; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@caller0
+; CGSCC-SAME: () #[[ATTR3]] {
+; CGSCC-NEXT:    [[C:%.*]] = call noundef i8 @callee() #[[ATTR12]]
+; CGSCC-NEXT:    ret i8 [[C]]
+;
+  %c = call i8 @callee(i8 undef)
+  ret i8 %c
+}
+define i8 @caller1() {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; TUNIT-LABEL: define {{[^@]+}}@caller1
+; TUNIT-SAME: () #[[ATTR2]] {
+; TUNIT-NEXT:    ret i8 49
+;
+; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@caller1
+; CGSCC-SAME: () #[[ATTR3]] {
+; CGSCC-NEXT:    [[C:%.*]] = call noundef i8 @callee() #[[ATTR12]]
+; CGSCC-NEXT:    ret i8 [[C]]
+;
+  %c = call i8 @callee(i8 undef)
+  ret i8 %c
+}
+define i8 @caller2() {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; TUNIT-LABEL: define {{[^@]+}}@caller2
+; TUNIT-SAME: () #[[ATTR2]] {
+; TUNIT-NEXT:    ret i8 49
+;
+; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@caller2
+; CGSCC-SAME: () #[[ATTR3]] {
+; CGSCC-NEXT:    [[C:%.*]] = call noundef i8 @callee() #[[ATTR12]]
+; CGSCC-NEXT:    ret i8 [[C]]
+;
+  %c = call i8 @callee(i8 undef)
+  ret i8 %c
+}
+define i8 @caller_middle() {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; TUNIT-LABEL: define {{[^@]+}}@caller_middle
+; TUNIT-SAME: () #[[ATTR2]] {
+; TUNIT-NEXT:    ret i8 49
+;
+; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@caller_middle
+; CGSCC-SAME: () #[[ATTR3]] {
+; CGSCC-NEXT:    [[C:%.*]] = call noundef i8 @callee() #[[ATTR12]]
+; CGSCC-NEXT:    ret i8 [[C]]
+;
+  %c = call i8 @callee(i8 42)
+  ret i8 %c
+}
+define i8 @caller3() {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; TUNIT-LABEL: define {{[^@]+}}@caller3
+; TUNIT-SAME: () #[[ATTR2]] {
+; TUNIT-NEXT:    ret i8 49
+;
+; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@caller3
+; CGSCC-SAME: () #[[ATTR3]] {
+; CGSCC-NEXT:    [[C:%.*]] = call noundef i8 @callee() #[[ATTR12]]
+; CGSCC-NEXT:    ret i8 [[C]]
+;
+  %c = call i8 @callee(i8 undef)
+  ret i8 %c
+}
+define i8 @caller4() {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; TUNIT-LABEL: define {{[^@]+}}@caller4
+; TUNIT-SAME: () #[[ATTR2]] {
+; TUNIT-NEXT:    ret i8 49
+;
+; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@caller4
+; CGSCC-SAME: () #[[ATTR3]] {
+; CGSCC-NEXT:    [[C:%.*]] = call noundef i8 @callee() #[[ATTR12]]
+; CGSCC-NEXT:    ret i8 [[C]]
+;
+  %c = call i8 @callee(i8 undef)
+  ret i8 %c
+}
+define internal i8 @callee(i8 %a) {
+; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@callee
+; CGSCC-SAME: () #[[ATTR1]] {
+; CGSCC-NEXT:    ret i8 49
+;
+  %c = add i8 %a, 7
+  ret i8 %c
+}
+
+define void @user_as3() {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write)
+; TUNIT-LABEL: define {{[^@]+}}@user_as3
+; TUNIT-SAME: () #[[ATTR5]] {
+; TUNIT-NEXT:    store i32 0, ptr addrspace(3) @ConstAS3Ptr, align 4
+; TUNIT-NEXT:    ret void
+;
+; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(write)
+; CGSCC-LABEL: define {{[^@]+}}@user_as3
+; CGSCC-SAME: () #[[ATTR7:[0-9]+]] {
+; CGSCC-NEXT:    [[CALL:%.*]] = call fastcc align 4 ptr addrspace(3) @const_ptr_return_as3() #[[ATTR12]]
+; CGSCC-NEXT:    store i32 0, ptr addrspace(3) [[CALL]], align 4
+; CGSCC-NEXT:    ret void
+;
+  %call = call fastcc ptr addrspace(3) @const_ptr_return_as3()
+  store i32 0, ptr addrspace(3) %call
+  ret void
+}
+define void @user() {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write)
+; TUNIT-LABEL: define {{[^@]+}}@user
+; TUNIT-SAME: () #[[ATTR5]] {
+; TUNIT-NEXT:    [[TMP1:%.*]] = addrspacecast ptr addrspacecast (ptr addrspace(3) @ConstAS3Ptr to ptr) to ptr addrspace(3)
+; TUNIT-NEXT:    store i32 0, ptr addrspace(3) [[TMP1]], align 4
+; TUNIT-NEXT:    ret void
+;
+; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(write)
+; CGSCC-LABEL: define {{[^@]+}}@user
+; CGSCC-SAME: () #[[ATTR7]] {
+; CGSCC-NEXT:    [[CALL:%.*]] = call fastcc align 4 ptr @const_ptr_return() #[[ATTR12]]
+; CGSCC-NEXT:    store i32 0, ptr [[CALL]], align 4
+; CGSCC-NEXT:    ret void
+;
+  %call = call fastcc ptr @const_ptr_return()
+  store i32 0, ptr %call
+  ret void
+}
+
+
+define i1 @test_merge_with_undef_values_ptr(i1 %c) {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; TUNIT-LABEL: define {{[^@]+}}@test_merge_with_undef_values_ptr
+; TUNIT-SAME: (i1 [[C:%.*]]) #[[ATTR2]] {
+; TUNIT-NEXT:    ret i1 false
+;
+; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@test_merge_with_undef_values_ptr
+; CGSCC-SAME: (i1 [[C:%.*]]) #[[ATTR3]] {
+; CGSCC-NEXT:    [[R1:%.*]] = call i1 @undef_then_null(i1 [[C]]) #[[ATTR12]]
+; CGSCC-NEXT:    ret i1 [[R1]]
+;
+  %r1 = call i1 @undef_then_null(i1 %c, ptr undef, ptr undef)
+  ret i1 %r1
+}
+define internal i1 @undef_then_null(i1 %c, ptr %i32Aptr, ptr %i32Bptr) {
+; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@undef_then_null
+; CGSCC-SAME: (i1 [[C:%.*]]) #[[ATTR3]] {
+; CGSCC-NEXT:    [[OR:%.*]] = or i1 false, [[C]]
+; CGSCC-NEXT:    br i1 [[OR]], label [[A:%.*]], label [[B:%.*]]
+; CGSCC:       a:
+; CGSCC-NEXT:    ret i1 false
+; CGSCC:       b:
+; CGSCC-NEXT:    ret i1 false
+;
+  %cmp1 = icmp eq ptr %i32Aptr, %i32Bptr
+  %cmp2 = icmp eq i1 %cmp1, false
+  %or = or i1 %cmp2, %c
+  br i1 %or, label %a, label %b
+a:
+  %r2 = call i1 @undef_then_null(i1 false, ptr null, ptr null)
+  ret i1 %r2
+b:
+  ret i1 %cmp2
+}
+
+define i1 @test_merge_with_undef_values(i1 %c) {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; TUNIT-LABEL: define {{[^@]+}}@test_merge_with_undef_values
+; TUNIT-SAME: (i1 [[C:%.*]]) #[[ATTR2]] {
+; TUNIT-NEXT:    ret i1 false
+;
+; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@test_merge_with_undef_values
+; CGSCC-SAME: (i1 [[C:%.*]]) #[[ATTR3]] {
+; CGSCC-NEXT:    [[R1:%.*]] = call i1 @undef_then_1(i1 [[C]]) #[[ATTR12]]
+; CGSCC-NEXT:    ret i1 [[R1]]
+;
+  %r1 = call i1 @undef_then_1(i1 %c, i32 undef, i32 undef)
+  ret i1 %r1
+}
+define internal i1 @undef_then_1(i1 %c, i32 %i32A, i32 %i32B) {
+;
+; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@undef_then_1
+; CGSCC-SAME: (i1 [[C:%.*]]) #[[ATTR3]] {
+; CGSCC-NEXT:    [[OR:%.*]] = or i1 false, [[C]]
+; CGSCC-NEXT:    br i1 [[OR]], label [[A:%.*]], label [[B:%.*]]
+; CGSCC:       a:
+; CGSCC-NEXT:    ret i1 false
+; CGSCC:       b:
+; CGSCC-NEXT:    ret i1 false
+;
+  %cmp1 = icmp eq i32 %i32A, %i32B
+  %cmp2 = icmp eq i1 %cmp1, false
+  %or = or i1 %cmp2, %c
+  br i1 %or, label %a, label %b
+a:
+  %r2 = call i1 @undef_then_1(i1 false, i32 1, i32 1)
+  ret i1 %r2
+b:
+  ret i1 %cmp2
+}
+
+define i32 @test_select(i32 %c) {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; TUNIT-LABEL: define {{[^@]+}}@test_select
+; TUNIT-SAME: (i32 [[C:%.*]]) #[[ATTR2]] {
+; TUNIT-NEXT:    ret i32 42
+;
+; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@test_select
+; CGSCC-SAME: (i32 [[C:%.*]]) #[[ATTR3]] {
+; CGSCC-NEXT:    [[CALL:%.*]] = call noundef i32 @select() #[[ATTR12]]
+; CGSCC-NEXT:    ret i32 [[CALL]]
+;
+  %call = call i32 @select(i1 1, i32 42, i32 %c)
+  ret i32 %call
+}
+
+define internal i32 @select(i1 %a, i32 %b, i32 %c) {
+; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@select
+; CGSCC-SAME: () #[[ATTR1]] {
+; CGSCC-NEXT:    ret i32 42
+;
+  %s = select i1 %a, i32 %b, i32 %c
+  ret i32 %s
+}
+
+define i1 @icmp() {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; TUNIT-LABEL: define {{[^@]+}}@icmp
+; TUNIT-SAME: () #[[ATTR2]] {
+; TUNIT-NEXT:    ret i1 true
+;
+; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@icmp
+; CGSCC-SAME: () #[[ATTR1]] {
+; CGSCC-NEXT:    ret i1 true
+;
+  %c = icmp eq ptr null, null
+  ret i1 %c
+}
+
+define void @test_callee_is_undef(ptr %fn) {
+; TUNIT-LABEL: define {{[^@]+}}@test_callee_is_undef
+; TUNIT-SAME: (ptr nocapture nofree nonnull [[FN:%.*]]) {
+; TUNIT-NEXT:    call void @unknown_calle_arg_is_undef(ptr nocapture nofree noundef nonnull [[FN]])
+; TUNIT-NEXT:    ret void
+;
+; CGSCC-LABEL: define {{[^@]+}}@test_callee_is_undef
+; CGSCC-SAME: (ptr nocapture nofree noundef nonnull [[FN:%.*]]) {
+; CGSCC-NEXT:    call void @unknown_calle_arg_is_undef(ptr nocapture nofree noundef nonnull [[FN]])
+; CGSCC-NEXT:    ret void
+;
+  call void @callee_is_undef(ptr undef)
+  call void @unknown_calle_arg_is_undef(ptr %fn, i32 undef)
+  ret void
+}
+define internal void @callee_is_undef(ptr %fn) {
+;
+; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@callee_is_undef
+; CGSCC-SAME: () #[[ATTR1]] {
+; CGSCC-NEXT:    unreachable
+;
+  call void %fn()
+  ret void
+}
+define internal void @unknown_calle_arg_is_undef(ptr %fn, i32 %arg) {
+;
+; CHECK-LABEL: define {{[^@]+}}@unknown_calle_arg_is_undef
+; CHECK-SAME: (ptr nocapture nofree noundef nonnull [[FN:%.*]]) {
+; CHECK-NEXT:    call void [[FN]](i32 undef)
+; CHECK-NEXT:    ret void
+;
+  call void %fn(i32 %arg)
+  ret void
+}
+
+; Taken from 50683
+; {{{
+
+ at g = internal constant { [2 x ptr] } { [2 x ptr] [ptr @f1, ptr @f2] }
+
+define internal void @f1(ptr %a) {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
+; TUNIT-LABEL: define {{[^@]+}}@f1
+; TUNIT-SAME: (ptr nocapture nofree noundef nonnull writeonly align 8 dereferenceable(8) [[A:%.*]]) #[[ATTR4]] {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    store ptr @g, ptr [[A]], align 8
+; TUNIT-NEXT:    ret void
+;
+; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
+; CGSCC-LABEL: define {{[^@]+}}@f1
+; CGSCC-SAME: (ptr nocapture nofree noundef nonnull writeonly align 8 dereferenceable(8) [[A:%.*]]) #[[ATTR5]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    store ptr @g, ptr [[A]], align 8
+; CGSCC-NEXT:    ret void
+;
+entry:
+  store ptr @g , ptr %a, align 8
+  ret void
+}
+
+define internal void @f2(ptr %a) {
+; CHECK-LABEL: define {{[^@]+}}@f2
+; CHECK-SAME: (ptr nonnull [[A:%.*]]) {
+; CHECK-NEXT:  cont461:
+; CHECK-NEXT:    call void @f3(ptr nonnull [[A]], ptr nocapture nofree nonnull [[A]])
+; CHECK-NEXT:    ret void
+;
+cont461:
+  call void @f3(ptr %a, ptr %a)
+  ret void
+}
+
+define internal void @f3(ptr %a1, ptr %a) {
+; CHECK-LABEL: define {{[^@]+}}@f3
+; CHECK-SAME: (ptr nonnull [[A1:%.*]], ptr nocapture nofree nonnull [[A:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CALL20:%.*]] = call i1 @f9()
+; CHECK-NEXT:    br i1 [[CALL20]], label [[LAND_LHS_TRUE:%.*]], label [[IF_END40:%.*]]
+; CHECK:       land.lhs.true:
+; CHECK-NEXT:    [[TMP0:%.*]] = call i1 [[A]](ptr [[A1]])
+; CHECK-NEXT:    br label [[IF_END40]]
+; CHECK:       if.end40:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %call20 = call i1 @f9()
+  br i1 %call20, label %land.lhs.true, label %if.end40
+
+land.lhs.true:
+  call i1 %a(ptr %a1)
+  br label %if.end40
+
+if.end40:
+  ret void
+}
+
+define linkonce_odr i1 @f9() {
+; CHECK-LABEL: define {{[^@]+}}@f9() {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    ret i1 false
+;
+entry:
+  ret i1 false
+}
+
+; }}}
+
+
+define i1 @test_cmp_null_after_cast() {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; TUNIT-LABEL: define {{[^@]+}}@test_cmp_null_after_cast
+; TUNIT-SAME: () #[[ATTR2]] {
+; TUNIT-NEXT:    ret i1 true
+;
+; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@test_cmp_null_after_cast
+; CGSCC-SAME: () #[[ATTR3]] {
+; CGSCC-NEXT:    [[C:%.*]] = call noundef i1 @cmp_null_after_cast() #[[ATTR12]]
+; CGSCC-NEXT:    ret i1 [[C]]
+;
+  %c = call i1 @cmp_null_after_cast(i32 0, i8 0)
+  ret i1 %c
+}
+define internal i1 @cmp_null_after_cast(i32 %a, i8 %b) {
+; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@cmp_null_after_cast
+; CGSCC-SAME: () #[[ATTR1]] {
+; CGSCC-NEXT:    ret i1 true
+;
+  %t = trunc i32 %a to i8
+  %c = icmp eq i8 %t, %b
+  ret i1 %c
+}
+
+
+declare ptr @m()
+
+define i32 @test(i1 %c) {
+; TUNIT-LABEL: define {{[^@]+}}@test
+; TUNIT-SAME: (i1 [[C:%.*]]) {
+; TUNIT-NEXT:    [[R1:%.*]] = call i32 @ctx_test1(i1 noundef [[C]])
+; TUNIT-NEXT:    [[R2:%.*]] = call i32 @ctx_test2(i1 noundef [[C]]), !range [[RNG0:![0-9]+]]
+; TUNIT-NEXT:    [[ADD:%.*]] = add i32 [[R1]], [[R2]]
+; TUNIT-NEXT:    ret i32 [[ADD]]
+;
+; CGSCC-LABEL: define {{[^@]+}}@test
+; CGSCC-SAME: (i1 noundef [[C:%.*]]) {
+; CGSCC-NEXT:    [[R1:%.*]] = call i32 @ctx_test1(i1 noundef [[C]])
+; CGSCC-NEXT:    [[R2:%.*]] = call i32 @ctx_test2(i1 noundef [[C]])
+; CGSCC-NEXT:    [[ADD:%.*]] = add i32 [[R1]], [[R2]]
+; CGSCC-NEXT:    ret i32 [[ADD]]
+;
+  %r1 = call i32 @ctx_test1(i1 %c)
+  %r2 = call i32 @ctx_test2(i1 %c)
+  %add = add i32 %r1, %r2
+  ret i32 %add
+}
+
+define internal i32 @ctx_test1(i1 %c) {
+; CHECK-LABEL: define {{[^@]+}}@ctx_test1
+; CHECK-SAME: (i1 noundef [[C:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br i1 [[C]], label [[THEN:%.*]], label [[JOIN:%.*]]
+; CHECK:       then:
+; CHECK-NEXT:    [[M:%.*]] = tail call ptr @m()
+; CHECK-NEXT:    [[I:%.*]] = ptrtoint ptr [[M]] to i64
+; CHECK-NEXT:    br label [[JOIN]]
+; CHECK:       join:
+; CHECK-NEXT:    [[PHI:%.*]] = phi i64 [ [[I]], [[THEN]] ], [ undef, [[ENTRY:%.*]] ]
+; CHECK-NEXT:    [[RET:%.*]] = trunc i64 [[PHI]] to i32
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+entry:
+  br i1 %c, label %then, label %join
+
+then:
+  %m = tail call ptr @m()
+  %i = ptrtoint ptr %m to i64
+  br label %join
+
+join:
+  %phi = phi i64 [ %i, %then ], [ undef, %entry ]
+  %ret = trunc i64 %phi to i32
+  ret i32 %ret
+}
+
+define internal i32 @ctx_test2(i1 %c) {
+; CHECK-LABEL: define {{[^@]+}}@ctx_test2
+; CHECK-SAME: (i1 noundef [[C:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br i1 [[C]], label [[THEN:%.*]], label [[JOIN:%.*]]
+; CHECK:       then:
+; CHECK-NEXT:    [[M:%.*]] = tail call ptr @m()
+; CHECK-NEXT:    [[I:%.*]] = ptrtoint ptr [[M]] to i32
+; CHECK-NEXT:    br label [[JOIN]]
+; CHECK:       join:
+; CHECK-NEXT:    [[PHI:%.*]] = phi i32 [ [[I]], [[THEN]] ], [ undef, [[ENTRY:%.*]] ]
+; CHECK-NEXT:    [[RET:%.*]] = lshr i32 [[PHI]], 1
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+entry:
+  br i1 %c, label %then, label %join
+
+then:
+  %m = tail call ptr @m()
+  %i = ptrtoint ptr %m to i32
+  br label %join
+
+join:
+  %phi = phi i32 [ %i, %then ], [ undef, %entry ]
+  %ret = lshr i32 %phi, 1
+  ret i32 %ret
+
+  uselistorder label %join, { 1, 0 }
+}
+
+define i1 @test_liveness(i1 %c) {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; TUNIT-LABEL: define {{[^@]+}}@test_liveness
+; TUNIT-SAME: (i1 noundef [[C:%.*]]) #[[ATTR2]] {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
+; TUNIT:       t:
+; TUNIT-NEXT:    br label [[F]]
+; TUNIT:       f:
+; TUNIT-NEXT:    ret i1 false
+;
+; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@test_liveness
+; CGSCC-SAME: (i1 noundef [[C:%.*]]) #[[ATTR3]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
+; CGSCC:       t:
+; CGSCC-NEXT:    br label [[F]]
+; CGSCC:       f:
+; CGSCC-NEXT:    [[P:%.*]] = phi i1 [ true, [[ENTRY:%.*]] ], [ false, [[T]] ]
+; CGSCC-NEXT:    [[RC1:%.*]] = call noundef i1 @ret(i1 noundef [[P]]) #[[ATTR12]]
+; CGSCC-NEXT:    ret i1 [[RC1]]
+;
+entry:
+  br i1 %c, label %t, label %f
+t:
+  br label %f
+f:
+  %p = phi i1 [true, %entry], [false, %t]
+  %rc1 = call i1 @ret(i1 %p)
+  ret i1 %rc1
+}
+
+define internal i1 @ret(i1 %c) {
+; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@ret
+; CGSCC-SAME: (i1 noundef [[C:%.*]]) #[[ATTR1]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
+; CGSCC:       t:
+; CGSCC-NEXT:    br label [[F]]
+; CGSCC:       f:
+; CGSCC-NEXT:    [[P:%.*]] = phi i1 [ [[C]], [[ENTRY:%.*]] ], [ false, [[T]] ]
+; CGSCC-NEXT:    ret i1 false
+;
+entry:
+  br i1 %c, label %t, label %f
+t:
+  br label %f
+f:
+  %p = phi i1 [%c, %entry], [false, %t]
+  ret i1 %p
+}
+
+declare ptr @unknown()
+define internal i8 @dead_ret() {
+; CHECK-LABEL: define {{[^@]+}}@dead_ret() {
+; CHECK-NEXT:    [[R:%.*]] = call ptr @unknown()
+; CHECK-NEXT:    ret i8 undef
+;
+  %r = call ptr @unknown()
+  %l = load i8, ptr %r
+  ret i8 %l
+}
+
+define void @dead_ret_caller() {
+; CHECK-LABEL: define {{[^@]+}}@dead_ret_caller() {
+; CHECK-NEXT:    [[R:%.*]] = call i8 @dead_ret()
+; CHECK-NEXT:    ret void
+;
+  %r = call i8 @dead_ret()
+  ret void
+}
+
+declare void @llvm.memcpy(ptr %dest, ptr %src, i32 %len, i1 %isvolatile)
+define internal i8 @memcpy_uses_store(i8 %arg) {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; TUNIT-LABEL: define {{[^@]+}}@memcpy_uses_store
+; TUNIT-SAME: (i8 [[ARG:%.*]]) #[[ATTR2]] {
+; TUNIT-NEXT:    [[SRC:%.*]] = alloca i8, align 1
+; TUNIT-NEXT:    [[DST:%.*]] = alloca i8, align 1
+; TUNIT-NEXT:    store i8 [[ARG]], ptr [[SRC]], align 1
+; TUNIT-NEXT:    call void @llvm.memcpy.p0.p0.i32(ptr noalias nocapture nofree noundef nonnull writeonly dereferenceable(1) [[DST]], ptr noalias nocapture nofree noundef nonnull readonly dereferenceable(1) [[SRC]], i32 noundef 1, i1 noundef false) #[[ATTR12:[0-9]+]]
+; TUNIT-NEXT:    [[L:%.*]] = load i8, ptr [[DST]], align 1
+; TUNIT-NEXT:    ret i8 [[L]]
+;
+; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@memcpy_uses_store
+; CGSCC-SAME: (i8 [[ARG:%.*]]) #[[ATTR1]] {
+; CGSCC-NEXT:    [[SRC:%.*]] = alloca i8, align 1
+; CGSCC-NEXT:    [[DST:%.*]] = alloca i8, align 1
+; CGSCC-NEXT:    store i8 [[ARG]], ptr [[SRC]], align 1
+; CGSCC-NEXT:    call void @llvm.memcpy.p0.p0.i32(ptr noalias nocapture nofree noundef nonnull writeonly dereferenceable(1) [[DST]], ptr noalias nocapture nofree noundef nonnull readonly dereferenceable(1) [[SRC]], i32 noundef 1, i1 noundef false) #[[ATTR16:[0-9]+]]
+; CGSCC-NEXT:    [[L:%.*]] = load i8, ptr [[DST]], align 1
+; CGSCC-NEXT:    ret i8 [[L]]
+;
+  %src = alloca i8
+  %dst = alloca i8
+  store i8 %arg, ptr %src
+  call void @llvm.memcpy(ptr %dst, ptr %src, i32 1, i1 false)
+  %l = load i8, ptr %dst
+  ret i8 %l
+}
+
+define i8 @memcpy_uses_store_caller(i8 %arg) {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; TUNIT-LABEL: define {{[^@]+}}@memcpy_uses_store_caller
+; TUNIT-SAME: (i8 [[ARG:%.*]]) #[[ATTR2]] {
+; TUNIT-NEXT:    [[R:%.*]] = call i8 @memcpy_uses_store(i8 [[ARG]]) #[[ATTR13:[0-9]+]]
+; TUNIT-NEXT:    ret i8 [[R]]
+;
+; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@memcpy_uses_store_caller
+; CGSCC-SAME: (i8 [[ARG:%.*]]) #[[ATTR3]] {
+; CGSCC-NEXT:    [[R:%.*]] = call i8 @memcpy_uses_store(i8 [[ARG]]) #[[ATTR12]]
+; CGSCC-NEXT:    ret i8 [[R]]
+;
+  %r = call i8 @memcpy_uses_store(i8 %arg)
+  ret i8 %r
+}
+
+
+declare i32 @speculatable() speculatable readnone
+
+define i32 @test_speculatable_expr() norecurse {
+; TUNIT: Function Attrs: norecurse nosync memory(none)
+; TUNIT-LABEL: define {{[^@]+}}@test_speculatable_expr
+; TUNIT-SAME: () #[[ATTR7:[0-9]+]] {
+; TUNIT-NEXT:    [[STACK:%.*]] = alloca i32, align 4
+; TUNIT-NEXT:    [[SPEC_RESULT:%.*]] = call i32 @speculatable() #[[ATTR14:[0-9]+]]
+; TUNIT-NEXT:    [[PLUS1:%.*]] = add i32 [[SPEC_RESULT]], 1
+; TUNIT-NEXT:    store i32 [[PLUS1]], ptr [[STACK]], align 4
+; TUNIT-NEXT:    [[TMP1:%.*]] = load i32, ptr [[STACK]], align 4
+; TUNIT-NEXT:    [[RSPEC:%.*]] = call i32 @ret_speculatable_expr(i32 [[TMP1]]) #[[ATTR15:[0-9]+]]
+; TUNIT-NEXT:    ret i32 [[RSPEC]]
+;
+; CGSCC: Function Attrs: norecurse nosync memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@test_speculatable_expr
+; CGSCC-SAME: () #[[ATTR9:[0-9]+]] {
+; CGSCC-NEXT:    [[STACK:%.*]] = alloca i32, align 4
+; CGSCC-NEXT:    [[SPEC_RESULT:%.*]] = call i32 @speculatable() #[[ATTR17:[0-9]+]]
+; CGSCC-NEXT:    [[PLUS1:%.*]] = add i32 [[SPEC_RESULT]], 1
+; CGSCC-NEXT:    store i32 [[PLUS1]], ptr [[STACK]], align 4
+; CGSCC-NEXT:    [[RSPEC:%.*]] = call i32 @ret_speculatable_expr(i32 [[PLUS1]]) #[[ATTR17]]
+; CGSCC-NEXT:    ret i32 [[RSPEC]]
+;
+  %stack = alloca i32
+  %spec_result = call i32 @speculatable()
+  %plus1 = add i32 %spec_result, 1
+  store i32 %plus1, ptr %stack
+  %rspec = call i32 @ret_speculatable_expr(ptr %stack, i32 13)
+  ret i32 %rspec
+}
+
+define internal i32 @ret_speculatable_expr(ptr %mem, i32 %a2) {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; TUNIT-LABEL: define {{[^@]+}}@ret_speculatable_expr
+; TUNIT-SAME: (i32 [[TMP0:%.*]]) #[[ATTR2]] {
+; TUNIT-NEXT:    [[MEM_PRIV:%.*]] = alloca i32, align 4
+; TUNIT-NEXT:    store i32 [[TMP0]], ptr [[MEM_PRIV]], align 4
+; TUNIT-NEXT:    [[L:%.*]] = load i32, ptr [[MEM_PRIV]], align 4
+; TUNIT-NEXT:    [[MUL:%.*]] = mul i32 [[L]], 13
+; TUNIT-NEXT:    [[ADD:%.*]] = add i32 [[MUL]], 7
+; TUNIT-NEXT:    ret i32 [[ADD]]
+;
+; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@ret_speculatable_expr
+; CGSCC-SAME: (i32 [[TMP0:%.*]]) #[[ATTR1]] {
+; CGSCC-NEXT:    [[MEM_PRIV:%.*]] = alloca i32, align 4
+; CGSCC-NEXT:    store i32 [[TMP0]], ptr [[MEM_PRIV]], align 4
+; CGSCC-NEXT:    [[L:%.*]] = load i32, ptr [[MEM_PRIV]], align 4
+; CGSCC-NEXT:    [[MUL:%.*]] = mul i32 [[L]], 13
+; CGSCC-NEXT:    [[ADD:%.*]] = add i32 [[MUL]], 7
+; CGSCC-NEXT:    ret i32 [[ADD]]
+;
+  %l = load i32, ptr %mem
+  %mul = mul i32 %l, %a2
+  %add = add i32 %mul, 7
+  ret i32 %add
+}
+
+define internal void @not_called1() {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; TUNIT-LABEL: define {{[^@]+}}@not_called1
+; TUNIT-SAME: () #[[ATTR2]] {
+; TUNIT-NEXT:    ret void
+;
+; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@not_called1
+; CGSCC-SAME: () #[[ATTR1]] {
+; CGSCC-NEXT:    ret void
+;
+  ret void
+}
+define internal void @not_called2() {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; TUNIT-LABEL: define {{[^@]+}}@not_called2
+; TUNIT-SAME: () #[[ATTR2]] {
+; TUNIT-NEXT:    ret void
+;
+; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@not_called2
+; CGSCC-SAME: () #[[ATTR1]] {
+; CGSCC-NEXT:    ret void
+;
+  ret void
+}
+define internal void @not_called3() {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; TUNIT-LABEL: define {{[^@]+}}@not_called3
+; TUNIT-SAME: () #[[ATTR2]] {
+; TUNIT-NEXT:    ret void
+;
+; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@not_called3
+; CGSCC-SAME: () #[[ATTR1]] {
+; CGSCC-NEXT:    ret void
+;
+  ret void
+}
+declare void @useFnDecl(ptr addrspace(42));
+define void @useFnDef(ptr addrspace(42) %arg) {
+; CHECK-LABEL: define {{[^@]+}}@useFnDef
+; CHECK-SAME: (ptr addrspace(42) [[ARG:%.*]]) {
+; CHECK-NEXT:    call void @useFnDecl(ptr addrspace(42) [[ARG]])
+; CHECK-NEXT:    ret void
+;
+  call void @useFnDecl(ptr addrspace(42) %arg)
+  ret void
+}
+define i1 @user_of_not_called() {
+; CHECK-LABEL: define {{[^@]+}}@user_of_not_called() {
+; CHECK-NEXT:    call void @useFnDecl(ptr addrspace(42) noundef nonnull addrspacecast (ptr @not_called1 to ptr addrspace(42)))
+; CHECK-NEXT:    call void @useFnDef(ptr addrspace(42) noundef nonnull addrspacecast (ptr @not_called2 to ptr addrspace(42)))
+; CHECK-NEXT:    ret i1 icmp eq (ptr addrspace(42) addrspacecast (ptr @not_called3 to ptr addrspace(42)), ptr addrspace(42) null)
+;
+  call void @useFnDecl(ptr addrspace(42) addrspacecast (ptr @not_called1 to ptr addrspace(42)))
+  call void @useFnDef(ptr addrspace(42) addrspacecast (ptr @not_called2 to ptr addrspace(42)))
+  %cmp = icmp eq ptr addrspace(42) addrspacecast (ptr @not_called3 to ptr addrspace(42)), null
+  ret i1 %cmp
+}
+
+ at x = external global i32
+define internal void @indirect() {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write)
+; TUNIT-LABEL: define {{[^@]+}}@indirect
+; TUNIT-SAME: () #[[ATTR5]] {
+; TUNIT-NEXT:    store i32 0, ptr @x, align 4
+; TUNIT-NEXT:    ret void
+;
+; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write)
+; CGSCC-LABEL: define {{[^@]+}}@indirect
+; CGSCC-SAME: () #[[ATTR10:[0-9]+]] {
+; CGSCC-NEXT:    store i32 0, ptr @x, align 4
+; CGSCC-NEXT:    ret void
+;
+  store i32 0, ptr @x
+  ret void
+}
+
+define internal void @broker(ptr %ptr) {
+; TUNIT: Function Attrs: memory(readwrite, argmem: none)
+; TUNIT-LABEL: define {{[^@]+}}@broker
+; TUNIT-SAME: () #[[ATTR1]] {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    call void @indirect() #[[ATTR16:[0-9]+]]
+; TUNIT-NEXT:    call void @unknown()
+; TUNIT-NEXT:    ret void
+;
+; CGSCC: Function Attrs: memory(readwrite, argmem: none)
+; CGSCC-LABEL: define {{[^@]+}}@broker
+; CGSCC-SAME: () #[[ATTR2]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    call void @indirect() #[[ATTR18:[0-9]+]]
+; CGSCC-NEXT:    call void @unknown()
+; CGSCC-NEXT:    ret void
+;
+entry:
+  call void %ptr()
+  call void @unknown()
+  ret void
+}
+
+define void @entry() {
+; CHECK-LABEL: define {{[^@]+}}@entry() {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    call void @broker()
+; CHECK-NEXT:    ret void
+;
+entry:
+  call void @broker(ptr @indirect)
+  ret void
+}
+
+define i1 @constexpr_icmp1() {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; TUNIT-LABEL: define {{[^@]+}}@constexpr_icmp1
+; TUNIT-SAME: () #[[ATTR2]] {
+; TUNIT-NEXT:    ret i1 icmp ne (ptr addrspacecast (ptr addrspace(4) @str to ptr), ptr null)
+;
+; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@constexpr_icmp1
+; CGSCC-SAME: () #[[ATTR1]] {
+; CGSCC-NEXT:    ret i1 icmp ne (ptr addrspacecast (ptr addrspace(4) @str to ptr), ptr null)
+;
+  ret i1 icmp ne (ptr addrspacecast (ptr addrspace(4) @str to ptr), ptr null)
+}
+
+define i1 @constexpr_icmp2() {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; TUNIT-LABEL: define {{[^@]+}}@constexpr_icmp2
+; TUNIT-SAME: () #[[ATTR2]] {
+; TUNIT-NEXT:    ret i1 icmp eq (ptr addrspacecast (ptr addrspace(4) @str to ptr), ptr null)
+;
+; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@constexpr_icmp2
+; CGSCC-SAME: () #[[ATTR1]] {
+; CGSCC-NEXT:    ret i1 icmp eq (ptr addrspacecast (ptr addrspace(4) @str to ptr), ptr null)
+;
+  ret i1 icmp eq (ptr addrspacecast (ptr addrspace(4) @str to ptr), ptr null)
+}
+
+define i8 @switch(i1 %c1, i1 %c2) {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; TUNIT-LABEL: define {{[^@]+}}@switch
+; TUNIT-SAME: (i1 noundef [[C1:%.*]], i1 [[C2:%.*]]) #[[ATTR2]] {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    br i1 [[C1]], label [[T:%.*]], label [[F:%.*]]
+; TUNIT:       t:
+; TUNIT-NEXT:    br label [[M:%.*]]
+; TUNIT:       f:
+; TUNIT-NEXT:    br label [[M]]
+; TUNIT:       m:
+; TUNIT-NEXT:    [[J:%.*]] = phi i32 [ 0, [[T]] ], [ 4, [[F]] ]
+; TUNIT-NEXT:    switch i32 [[J]], label [[DEFAULT1:%.*]] [
+; TUNIT-NEXT:      i32 1, label [[DEAD1:%.*]]
+; TUNIT-NEXT:      i32 2, label [[DEAD2:%.*]]
+; TUNIT-NEXT:      i32 3, label [[DEAD3:%.*]]
+; TUNIT-NEXT:      i32 4, label [[ALIVE1:%.*]]
+; TUNIT-NEXT:    ]
+; TUNIT:       default1:
+; TUNIT-NEXT:    br label [[ALIVE1]]
+; TUNIT:       alive1:
+; TUNIT-NEXT:    [[K:%.*]] = phi i32 [ 1, [[M]] ], [ 4, [[DEFAULT1]] ]
+; TUNIT-NEXT:    switch i32 [[K]], label [[DEAD4:%.*]] [
+; TUNIT-NEXT:      i32 1, label [[END1:%.*]]
+; TUNIT-NEXT:      i32 2, label [[DEAD5:%.*]]
+; TUNIT-NEXT:      i32 4, label [[END2:%.*]]
+; TUNIT-NEXT:    ]
+; TUNIT:       end1:
+; TUNIT-NEXT:    ret i8 -1
+; TUNIT:       end2:
+; TUNIT-NEXT:    ret i8 -2
+; TUNIT:       dead1:
+; TUNIT-NEXT:    unreachable
+; TUNIT:       dead2:
+; TUNIT-NEXT:    unreachable
+; TUNIT:       dead3:
+; TUNIT-NEXT:    unreachable
+; TUNIT:       dead4:
+; TUNIT-NEXT:    unreachable
+; TUNIT:       dead5:
+; TUNIT-NEXT:    unreachable
+;
+; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@switch
+; CGSCC-SAME: (i1 noundef [[C1:%.*]], i1 [[C2:%.*]]) #[[ATTR1]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    br i1 [[C1]], label [[T:%.*]], label [[F:%.*]]
+; CGSCC:       t:
+; CGSCC-NEXT:    br label [[M:%.*]]
+; CGSCC:       f:
+; CGSCC-NEXT:    br label [[M]]
+; CGSCC:       m:
+; CGSCC-NEXT:    [[J:%.*]] = phi i32 [ 0, [[T]] ], [ 4, [[F]] ]
+; CGSCC-NEXT:    switch i32 [[J]], label [[DEFAULT1:%.*]] [
+; CGSCC-NEXT:      i32 1, label [[DEAD1:%.*]]
+; CGSCC-NEXT:      i32 2, label [[DEAD2:%.*]]
+; CGSCC-NEXT:      i32 3, label [[DEAD3:%.*]]
+; CGSCC-NEXT:      i32 4, label [[ALIVE1:%.*]]
+; CGSCC-NEXT:    ]
+; CGSCC:       default1:
+; CGSCC-NEXT:    br label [[ALIVE1]]
+; CGSCC:       alive1:
+; CGSCC-NEXT:    [[K:%.*]] = phi i32 [ 1, [[M]] ], [ 4, [[DEFAULT1]] ]
+; CGSCC-NEXT:    switch i32 [[K]], label [[DEAD4:%.*]] [
+; CGSCC-NEXT:      i32 1, label [[END1:%.*]]
+; CGSCC-NEXT:      i32 2, label [[DEAD5:%.*]]
+; CGSCC-NEXT:      i32 4, label [[END2:%.*]]
+; CGSCC-NEXT:    ]
+; CGSCC:       end1:
+; CGSCC-NEXT:    ret i8 -1
+; CGSCC:       end2:
+; CGSCC-NEXT:    ret i8 -2
+; CGSCC:       dead1:
+; CGSCC-NEXT:    unreachable
+; CGSCC:       dead2:
+; CGSCC-NEXT:    unreachable
+; CGSCC:       dead3:
+; CGSCC-NEXT:    unreachable
+; CGSCC:       dead4:
+; CGSCC-NEXT:    unreachable
+; CGSCC:       dead5:
+; CGSCC-NEXT:    unreachable
+;
+entry:
+  br i1 %c1, label %t, label %f
+
+t:
+  br label %m
+
+f:
+  br label %m
+
+m:
+  %j = phi i32 [ 0, %t ], [ 4, %f ]
+  switch i32 %j, label %default1 [
+  i32 1, label %dead1
+  i32 2, label %dead2
+  i32 3, label %dead3
+  i32 4, label %alive1
+  ]
+
+default1:
+  br label %alive1
+
+alive1:
+  %k = phi i32 [ 1, %m ], [ 4, %default1 ]
+  switch i32 %k, label %dead4 [
+  i32 1, label %end1
+  i32 2, label %dead5
+  i32 4, label %end2
+  ]
+
+end1:
+  ret i8 -1
+end2:
+  ret i8 -2
+dead1:
+  ret i8 1
+dead2:
+  ret i8 2
+dead3:
+  ret i8 3
+dead4:
+  ret i8 4
+dead5:
+  ret i8 5
+}
+
+define i32 @readConst() {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; TUNIT-LABEL: define {{[^@]+}}@readConst
+; TUNIT-SAME: () #[[ATTR2]] {
+; TUNIT-NEXT:    ret i32 0
+;
+; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@readConst
+; CGSCC-SAME: () #[[ATTR1]] {
+; CGSCC-NEXT:    ret i32 0
+;
+  %l = load i32, ptr @ConstPtr
+  ret i32 %l
+}
+
+define i32 @readWeakConst() {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; TUNIT-LABEL: define {{[^@]+}}@readWeakConst
+; TUNIT-SAME: () #[[ATTR2]] {
+; TUNIT-NEXT:    [[L:%.*]] = load i32, ptr @ConstWeakPtr, align 4
+; TUNIT-NEXT:    ret i32 [[L]]
+;
+; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@readWeakConst
+; CGSCC-SAME: () #[[ATTR1]] {
+; CGSCC-NEXT:    [[L:%.*]] = load i32, ptr @ConstWeakPtr, align 4
+; CGSCC-NEXT:    ret i32 [[L]]
+;
+  %l = load i32, ptr @ConstWeakPtr
+  ret i32 %l
+}
+
+define i32 @readWeakOdrConst() {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; TUNIT-LABEL: define {{[^@]+}}@readWeakOdrConst
+; TUNIT-SAME: () #[[ATTR2]] {
+; TUNIT-NEXT:    ret i32 0
+;
+; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@readWeakOdrConst
+; CGSCC-SAME: () #[[ATTR1]] {
+; CGSCC-NEXT:    ret i32 0
+;
+  %l = load i32, ptr @ConstWeakODRPtr
+  ret i32 %l
+}
+
+;.
+; TUNIT: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nosync nounwind willreturn }
+; TUNIT: attributes #[[ATTR1]] = { memory(readwrite, argmem: none) }
+; TUNIT: attributes #[[ATTR2]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
+; TUNIT: attributes #[[ATTR3]] = { mustprogress nofree norecurse nosync nounwind willreturn }
+; TUNIT: attributes #[[ATTR4]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) }
+; TUNIT: attributes #[[ATTR5]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(write) }
+; TUNIT: attributes #[[ATTR6:[0-9]+]] = { speculatable memory(none) }
+; TUNIT: attributes #[[ATTR7]] = { norecurse nosync memory(none) }
+; TUNIT: attributes #[[ATTR8:[0-9]+]] = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }
+; TUNIT: attributes #[[ATTR9]] = { nofree nosync nounwind willreturn memory(none) }
+; TUNIT: attributes #[[ATTR10]] = { nofree willreturn }
+; TUNIT: attributes #[[ATTR11]] = { nofree nosync nounwind willreturn memory(write) }
+; TUNIT: attributes #[[ATTR12]] = { nofree willreturn memory(readwrite) }
+; TUNIT: attributes #[[ATTR13]] = { nofree nosync nounwind willreturn }
+; TUNIT: attributes #[[ATTR14]] = { nosync }
+; TUNIT: attributes #[[ATTR15]] = { nosync nounwind memory(read) }
+; TUNIT: attributes #[[ATTR16]] = { nounwind memory(write) }
+;.
+; TUNIT: [[RNG0]] = !{i32 0, i32 -2147483648}
+;.
+; CGSCC: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nosync nounwind willreturn }
+; CGSCC: attributes #[[ATTR1]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
+; CGSCC: attributes #[[ATTR2]] = { memory(readwrite, argmem: none) }
+; CGSCC: attributes #[[ATTR3]] = { mustprogress nofree nosync nounwind willreturn memory(none) }
+; CGSCC: attributes #[[ATTR4]] = { mustprogress nofree nosync nounwind willreturn }
+; CGSCC: attributes #[[ATTR5]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) }
+; CGSCC: attributes #[[ATTR6]] = { mustprogress nofree nosync nounwind willreturn memory(argmem: write) }
+; CGSCC: attributes #[[ATTR7]] = { mustprogress nofree nosync nounwind willreturn memory(write) }
+; CGSCC: attributes #[[ATTR8:[0-9]+]] = { speculatable memory(none) }
+; CGSCC: attributes #[[ATTR9]] = { norecurse nosync memory(none) }
+; CGSCC: attributes #[[ATTR10]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(write) }
+; CGSCC: attributes #[[ATTR11:[0-9]+]] = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }
+; CGSCC: attributes #[[ATTR12]] = { nofree nosync willreturn }
+; CGSCC: attributes #[[ATTR13]] = { nofree willreturn }
+; CGSCC: attributes #[[ATTR14]] = { nofree nounwind willreturn }
+; CGSCC: attributes #[[ATTR15]] = { nofree nounwind willreturn memory(write) }
+; CGSCC: attributes #[[ATTR16]] = { nofree willreturn memory(readwrite) }
+; CGSCC: attributes #[[ATTR17]] = { nosync }
+; CGSCC: attributes #[[ATTR18]] = { nounwind }
+;.
diff --git a/llvm/test/Transforms/InstCombine/alloca-cast-debuginfo-dl-sentinel.ll b/llvm/test/Transforms/InstCombine/alloca-cast-debuginfo-dl-sentinel.ll
new file mode 100755
index 0000000000000..3a763cde2f0d1
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/alloca-cast-debuginfo-dl-sentinel.ll
@@ -0,0 +1,88 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -S -passes=instcombine -instcombine-lower-dbg-declare=0 | FileCheck %s
+
+; In this example, instcombine wants to turn "local" into an i64, since that's
+; how it is stored. It should keep the debug info referring to the alloca when
+; it does the replacement.
+
+; C source:
+; struct Foo {
+;   int x, y;
+; };
+; void escape(const ptr);
+; void f(struct Foo *p) {
+;   struct Foo local;
+;   *(__int64 *)&local = *(__int64 *)p;
+;   escape(&local);
+; }
+
+; ModuleID = '<stdin>'
+source_filename = "t.c"
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-z0:1-z2:neg1-z3:neg1-z5:neg1-S128"
+target triple = "x86_64-pc-windows-msvc19.11.25508"
+
+%struct.Foo = type { i32, i32 }
+
+define void @f(ptr %p) !dbg !11 {
+; CHECK-LABEL: @f(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[LOCAL:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4
+; CHECK-NEXT:    tail call void @llvm.dbg.declare(metadata ptr [[LOCAL]], metadata [[META22:![0-9]+]], metadata !DIExpression()), !dbg [[DBG23:![0-9]+]]
+; CHECK-NEXT:    [[TMP0:%.*]] = load i64, ptr [[P:%.*]], align 8, !dbg [[DBG24:![0-9]+]], !tbaa [[TBAA25:![0-9]+]]
+; CHECK-NEXT:    store i64 [[TMP0]], ptr [[LOCAL]], align 4, !dbg [[DBG29:![0-9]+]], !tbaa [[TBAA25]]
+; CHECK-NEXT:    call void @escape(ptr nonnull [[LOCAL]]), !dbg [[DBG30:![0-9]+]]
+; CHECK-NEXT:    ret void, !dbg [[DBG31:![0-9]+]]
+;
+entry:
+  %local = alloca %struct.Foo, align 4
+  call void @llvm.dbg.declare(metadata ptr %local, metadata !22, metadata !DIExpression()), !dbg !25
+  %0 = load i64, ptr %p, align 8, !dbg !26, !tbaa !27
+  store i64 %0, ptr %local, align 4, !dbg !32, !tbaa !27
+  call void @escape(ptr %local), !dbg !34
+  ret void, !dbg !35
+}
+
+declare void @llvm.dbg.declare(metadata, metadata, metadata)
+
+declare void @escape(ptr)
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!6, !7, !8, !9}
+!llvm.ident = !{!10}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 6.0.0 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3)
+!1 = !DIFile(filename: "t.c", directory: "C:\5Csrc\5Cllvm-project\5Cbuild", checksumkind: CSK_MD5, checksum: "d7473625866433067a75fd7d03d2abf7")
+!2 = !{}
+!3 = !{!4}
+!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64)
+!5 = !DIBasicType(name: "long long int", size: 64, encoding: DW_ATE_signed)
+!6 = !{i32 2, !"CodeView", i32 1}
+!7 = !{i32 2, !"Debug Info Version", i32 3}
+!8 = !{i32 1, !"wchar_size", i32 2}
+!9 = !{i32 7, !"PIC Level", i32 2}
+!10 = !{!"clang version 6.0.0 "}
+!11 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 5, type: !12, isLocal: false, isDefinition: true, scopeLine: 5, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !20)
+!12 = !DISubroutineType(types: !13)
+!13 = !{null, !14}
+!14 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !15, size: 64)
+!15 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Foo", file: !1, line: 1, size: 64, elements: !16)
+!16 = !{!17, !19}
+!17 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !15, file: !1, line: 2, baseType: !18, size: 32)
+!18 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!19 = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: !15, file: !1, line: 2, baseType: !18, size: 32, offset: 32)
+!20 = !{!21, !22}
+!21 = !DILocalVariable(name: "p", arg: 1, scope: !11, file: !1, line: 5, type: !14)
+!22 = !DILocalVariable(name: "local", scope: !11, file: !1, line: 6, type: !15)
+!23 = !DILocation(line: 5, column: 20, scope: !11)
+!24 = !DILocation(line: 6, column: 3, scope: !11)
+!25 = !DILocation(line: 6, column: 14, scope: !11)
+!26 = !DILocation(line: 7, column: 24, scope: !11)
+!27 = !{!28, !28, i64 0}
+!28 = !{!"long long", !29, i64 0}
+!29 = !{!"omnipotent char", !30, i64 0}
+!30 = !{!"Simple C/C++ TBAA"}
+!31 = !DILocation(line: 7, column: 3, scope: !11)
+!32 = !DILocation(line: 7, column: 22, scope: !11)
+!33 = !DILocation(line: 8, column: 10, scope: !11)
+!34 = !DILocation(line: 8, column: 3, scope: !11)
+!35 = !DILocation(line: 9, column: 1, scope: !11)
diff --git a/llvm/test/Transforms/InstCombine/alloca-in-non-alloca-as-sentinel.ll b/llvm/test/Transforms/InstCombine/alloca-in-non-alloca-as-sentinel.ll
new file mode 100755
index 0000000000000..d495881f8c2ca
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/alloca-in-non-alloca-as-sentinel.ll
@@ -0,0 +1,65 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+; Gracefully handle the alloca that is not in the alloca AS (=5)
+
+target datalayout = "e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32-p7:160:256:256:32-p8:128:128-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-z0:1-z2:neg1-z3:neg1-z5:neg1-S32-A5-G1-ni:7:8:9"
+target triple = "amdgcn-amd-amdhsa"
+
+declare void @use(ptr)
+declare void @use2(ptr, ptr)
+
+define weak amdgpu_kernel void @__omp_offloading_802_ea0109_main_l8(ptr %a) {
+; CHECK-LABEL: @__omp_offloading_802_ea0109_main_l8(
+; CHECK-NEXT:  .master:
+; CHECK-NEXT:    [[TMP0:%.*]] = alloca [8 x i8], align 1
+; CHECK-NEXT:    call void @use2(ptr nonnull [[TMP0]], ptr nonnull [[TMP0]])
+; CHECK-NEXT:    ret void
+;
+.master:
+  %0 = alloca i8, i64 8, align 1
+  store ptr undef, ptr %0, align 8
+  call void @use2(ptr %0, ptr %0)
+  ret void
+}
+
+%struct.widget = type { [8 x i8] }
+
+define void @spam(ptr %arg1) {
+; CHECK-LABEL: @spam(
+; CHECK-NEXT:  bb:
+; CHECK-NEXT:    [[ALLOCA1:%.*]] = alloca [0 x [30 x %struct.widget]], align 16
+; CHECK-NEXT:    call void @zot(ptr nonnull [[ALLOCA1]])
+; CHECK-NEXT:    ret void
+;
+bb:
+  %alloca = alloca [30 x %struct.widget], i32 0, align 16
+  call void @zot(ptr %alloca)
+  ret void
+}
+
+define i1 @alloca_addrspace_0_nonnull() {
+; CHECK-LABEL: @alloca_addrspace_0_nonnull(
+; CHECK-NEXT:    [[ALLOCA:%.*]] = alloca i8, align 1
+; CHECK-NEXT:    call void @use(ptr nonnull [[ALLOCA]])
+; CHECK-NEXT:    ret i1 true
+;
+  %alloca = alloca i8
+  call void @use(ptr %alloca)
+  %cmp = icmp ne ptr %alloca, null
+  ret i1 %cmp
+}
+
+define i1 @alloca_addrspace_5_nonnull() {
+; CHECK-LABEL: @alloca_addrspace_5_nonnull(
+; CHECK-NEXT:    [[ALLOCA:%.*]] = alloca i8, align 1, addrspace(5)
+; CHECK-NEXT:    call void @use(ptr addrspace(5) nonnull [[ALLOCA]])
+; CHECK-NEXT:    ret i1 true
+;
+  %alloca = alloca i8, addrspace(5)
+  call void @use(ptr addrspace(5) %alloca)
+  %cmp = icmp ne ptr addrspace(5) %alloca, null
+  ret i1 %cmp
+}
+
+declare hidden void @zot(ptr)
diff --git a/llvm/test/Transforms/InstCombine/assume-dl-sentinel.ll b/llvm/test/Transforms/InstCombine/assume-dl-sentinel.ll
new file mode 100755
index 0000000000000..3f8ed71b2eacf
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/assume-dl-sentinel.ll
@@ -0,0 +1,944 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -passes=instcombine -S | FileCheck --check-prefixes=CHECK,DEFAULT %s
+; RUN: opt < %s -passes=instcombine --enable-knowledge-retention -S | FileCheck --check-prefixes=CHECK,BUNDLES %s
+
+; RUN: opt < %s -passes=instcombine -S --try-experimental-debuginfo-iterators | FileCheck --check-prefixes=CHECK,DEFAULT %s
+; RUN: opt < %s -passes=instcombine --enable-knowledge-retention -S --try-experimental-debuginfo-iterators | FileCheck --check-prefixes=CHECK,BUNDLES %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-z0:1-z2:neg1-z3:neg1-z5:neg1-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare void @llvm.assume(i1) #1
+
+; Check that the assume has not been removed:
+
+define i32 @foo1(ptr %a) #0 {
+; DEFAULT-LABEL: @foo1(
+; DEFAULT-NEXT:    [[T0:%.*]] = load i32, ptr [[A:%.*]], align 4
+; DEFAULT-NEXT:    [[PTRINT:%.*]] = ptrtoint ptr [[A]] to i64
+; DEFAULT-NEXT:    [[MASKEDPTR:%.*]] = and i64 [[PTRINT]], 31
+; DEFAULT-NEXT:    [[MASKCOND:%.*]] = icmp eq i64 [[MASKEDPTR]], 0
+; DEFAULT-NEXT:    tail call void @llvm.assume(i1 [[MASKCOND]])
+; DEFAULT-NEXT:    ret i32 [[T0]]
+;
+; BUNDLES-LABEL: @foo1(
+; BUNDLES-NEXT:    [[T0:%.*]] = load i32, ptr [[A:%.*]], align 4
+; BUNDLES-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[A]], i64 32) ]
+; BUNDLES-NEXT:    ret i32 [[T0]]
+;
+  %t0 = load i32, ptr %a, align 4
+  %ptrint = ptrtoint ptr %a to i64
+  %maskedptr = and i64 %ptrint, 31
+  %maskcond = icmp eq i64 %maskedptr, 0
+  tail call void @llvm.assume(i1 %maskcond)
+  ret i32 %t0
+}
+
+; Same check as in @foo1, but make sure it works if the assume is first too.
+
+define i32 @foo2(ptr %a) #0 {
+; DEFAULT-LABEL: @foo2(
+; DEFAULT-NEXT:    [[PTRINT:%.*]] = ptrtoint ptr [[A:%.*]] to i64
+; DEFAULT-NEXT:    [[MASKEDPTR:%.*]] = and i64 [[PTRINT]], 31
+; DEFAULT-NEXT:    [[MASKCOND:%.*]] = icmp eq i64 [[MASKEDPTR]], 0
+; DEFAULT-NEXT:    tail call void @llvm.assume(i1 [[MASKCOND]])
+; DEFAULT-NEXT:    [[T0:%.*]] = load i32, ptr [[A]], align 4
+; DEFAULT-NEXT:    ret i32 [[T0]]
+;
+; BUNDLES-LABEL: @foo2(
+; BUNDLES-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[A:%.*]], i64 32) ]
+; BUNDLES-NEXT:    [[T0:%.*]] = load i32, ptr [[A]], align 4
+; BUNDLES-NEXT:    ret i32 [[T0]]
+;
+  %ptrint = ptrtoint ptr %a to i64
+  %maskedptr = and i64 %ptrint, 31
+  %maskcond = icmp eq i64 %maskedptr, 0
+  tail call void @llvm.assume(i1 %maskcond)
+  %t0 = load i32, ptr %a, align 4
+  ret i32 %t0
+}
+
+define i32 @simple(i32 %a) #1 {
+; CHECK-LABEL: @simple(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[A:%.*]], 4
+; CHECK-NEXT:    tail call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    ret i32 [[A]]
+;
+  %cmp = icmp eq i32 %a, 4
+  tail call void @llvm.assume(i1 %cmp)
+  ret i32 %a
+}
+
+define i32 @can1(i1 %a, i1 %b, i1 %c) {
+; CHECK-LABEL: @can1(
+; CHECK-NEXT:    call void @llvm.assume(i1 [[A:%.*]])
+; CHECK-NEXT:    call void @llvm.assume(i1 [[B:%.*]])
+; CHECK-NEXT:    call void @llvm.assume(i1 [[C:%.*]])
+; CHECK-NEXT:    ret i32 5
+;
+  %and1 = and i1 %a, %b
+  %and  = and i1 %and1, %c
+  tail call void @llvm.assume(i1 %and)
+  ret i32 5
+}
+
+define i32 @can1_logical(i1 %a, i1 %b, i1 %c) {
+; CHECK-LABEL: @can1_logical(
+; CHECK-NEXT:    call void @llvm.assume(i1 [[A:%.*]])
+; CHECK-NEXT:    call void @llvm.assume(i1 [[B:%.*]])
+; CHECK-NEXT:    call void @llvm.assume(i1 [[C:%.*]])
+; CHECK-NEXT:    ret i32 5
+;
+  %and1 = select i1 %a, i1 %b, i1 false
+  %and  = select i1 %and1, i1 %c, i1 false
+  tail call void @llvm.assume(i1 %and)
+  ret i32 5
+}
+
+define i32 @can2(i1 %a, i1 %b, i1 %c) {
+; CHECK-LABEL: @can2(
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i1 [[A:%.*]], true
+; CHECK-NEXT:    call void @llvm.assume(i1 [[TMP1]])
+; CHECK-NEXT:    [[TMP2:%.*]] = xor i1 [[B:%.*]], true
+; CHECK-NEXT:    call void @llvm.assume(i1 [[TMP2]])
+; CHECK-NEXT:    ret i32 5
+;
+  %v = or i1 %a, %b
+  %w = xor i1 %v, 1
+  tail call void @llvm.assume(i1 %w)
+  ret i32 5
+}
+
+define i32 @can2_logical(i1 %a, i1 %b, i1 %c) {
+; CHECK-LABEL: @can2_logical(
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i1 [[A:%.*]], true
+; CHECK-NEXT:    call void @llvm.assume(i1 [[TMP1]])
+; CHECK-NEXT:    [[TMP2:%.*]] = xor i1 [[B:%.*]], true
+; CHECK-NEXT:    call void @llvm.assume(i1 [[TMP2]])
+; CHECK-NEXT:    ret i32 5
+;
+  %v = select i1 %a, i1 true, i1 %b
+  %w = xor i1 %v, 1
+  tail call void @llvm.assume(i1 %w)
+  ret i32 5
+}
+
+define i32 @bar1(i32 %a) #0 {
+; CHECK-LABEL: @bar1(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[A:%.*]], 7
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[AND]], 1
+; CHECK-NEXT:    tail call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    ret i32 1
+;
+  %and1 = and i32 %a, 3
+  %and = and i32 %a, 7
+  %cmp = icmp eq i32 %and, 1
+  tail call void @llvm.assume(i1 %cmp)
+  ret i32 %and1
+}
+
+define i32 @bar2(i32 %a) #0 {
+; CHECK-LABEL: @bar2(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[A:%.*]], 7
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[AND]], 1
+; CHECK-NEXT:    tail call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    ret i32 1
+;
+  %and = and i32 %a, 7
+  %cmp = icmp eq i32 %and, 1
+  tail call void @llvm.assume(i1 %cmp)
+  %and1 = and i32 %a, 3
+  ret i32 %and1
+}
+
+define i32 @bar3(i32 %a, i1 %x, i1 %y) #0 {
+; CHECK-LABEL: @bar3(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    tail call void @llvm.assume(i1 [[X:%.*]])
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[A:%.*]], 7
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[AND]], 1
+; CHECK-NEXT:    tail call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    tail call void @llvm.assume(i1 [[Y:%.*]])
+; CHECK-NEXT:    ret i32 1
+;
+entry:
+  %and1 = and i32 %a, 3
+
+; Don't be fooled by other assumes around.
+
+  tail call void @llvm.assume(i1 %x)
+
+  %and = and i32 %a, 7
+  %cmp = icmp eq i32 %and, 1
+  tail call void @llvm.assume(i1 %cmp)
+
+  tail call void @llvm.assume(i1 %y)
+
+  ret i32 %and1
+}
+
+; If we allow recursive known bits queries based on
+; assumptions, we could do better here:
+; a == b and a & 7 == 1, so b & 7 == 1, so b & 3 == 1, so return 1.
+
+define i32 @known_bits_recursion_via_assumes(i32 %a, i32 %b) {
+; CHECK-LABEL: @known_bits_recursion_via_assumes(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[B:%.*]], 3
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[A:%.*]], 7
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[AND]], 1
+; CHECK-NEXT:    tail call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp eq i32 [[A]], [[B]]
+; CHECK-NEXT:    tail call void @llvm.assume(i1 [[CMP2]])
+; CHECK-NEXT:    ret i32 [[AND1]]
+;
+entry:
+  %and1 = and i32 %b, 3
+  %and = and i32 %a, 7
+  %cmp = icmp eq i32 %and, 1
+  tail call void @llvm.assume(i1 %cmp)
+  %cmp2 = icmp eq i32 %a, %b
+  tail call void @llvm.assume(i1 %cmp2)
+  ret i32 %and1
+}
+
+define i32 @icmp1(i32 %a) #0 {
+; CHECK-LABEL: @icmp1(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[A:%.*]], 5
+; CHECK-NEXT:    tail call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    [[CONV:%.*]] = zext i1 [[CMP]] to i32
+; CHECK-NEXT:    ret i32 [[CONV]]
+;
+  %cmp = icmp sgt i32 %a, 5
+  tail call void @llvm.assume(i1 %cmp)
+  %conv = zext i1 %cmp to i32
+  ret i32 %conv
+}
+
+define i32 @icmp2(i32 %a) #0 {
+; CHECK-LABEL: @icmp2(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[A:%.*]], 5
+; CHECK-NEXT:    tail call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    ret i32 0
+;
+  %cmp = icmp sgt i32 %a, 5
+  tail call void @llvm.assume(i1 %cmp)
+  %t0 = zext i1 %cmp to i32
+  %lnot.ext = xor i32 %t0, 1
+  ret i32 %lnot.ext
+}
+
+; If the 'not' of a condition is known true, then the condition must be false.
+
+define i1 @assume_not(i1 %cond) {
+; CHECK-LABEL: @assume_not(
+; CHECK-NEXT:    [[NOTCOND:%.*]] = xor i1 [[COND:%.*]], true
+; CHECK-NEXT:    call void @llvm.assume(i1 [[NOTCOND]])
+; CHECK-NEXT:    ret i1 [[COND]]
+;
+  %notcond = xor i1 %cond, true
+  call void @llvm.assume(i1 %notcond)
+  ret i1 %cond
+}
+
+declare void @escape(ptr %a)
+
+; Canonicalize a nonnull assumption on a load into metadata form.
+
+define i32 @bundle1(ptr %P) {
+; CHECK-LABEL: @bundle1(
+; CHECK-NEXT:    tail call void @llvm.assume(i1 true) [ "nonnull"(ptr [[P:%.*]]) ]
+; CHECK-NEXT:    [[LOAD:%.*]] = load i32, ptr [[P]], align 4
+; CHECK-NEXT:    ret i32 [[LOAD]]
+;
+  tail call void @llvm.assume(i1 true) ["nonnull"(ptr %P)]
+  %load = load i32, ptr %P
+  ret i32 %load
+}
+
+define i32 @bundle2(ptr %P) {
+; CHECK-LABEL: @bundle2(
+; CHECK-NEXT:    [[LOAD:%.*]] = load i32, ptr [[P:%.*]], align 4
+; CHECK-NEXT:    ret i32 [[LOAD]]
+;
+  tail call void @llvm.assume(i1 true) ["ignore"(ptr undef)]
+  %load = load i32, ptr %P
+  ret i32 %load
+}
+
+define i1 @nonnull1(ptr %a) {
+; CHECK-LABEL: @nonnull1(
+; CHECK-NEXT:    [[LOAD:%.*]] = load ptr, ptr [[A:%.*]], align 8
+; CHECK-NEXT:    tail call void @escape(ptr nonnull [[LOAD]])
+; CHECK-NEXT:    ret i1 false
+;
+  %load = load ptr, ptr %a
+  %cmp = icmp ne ptr %load, null
+  tail call void @llvm.assume(i1 %cmp)
+  tail call void @escape(ptr %load)
+  %rval = icmp eq ptr %load, null
+  ret i1 %rval
+}
+
+; Make sure the above canonicalization applies only
+; to pointer types.  Doing otherwise would be illegal.
+
+define i1 @nonnull2(ptr %a) {
+; CHECK-LABEL: @nonnull2(
+; CHECK-NEXT:    [[LOAD:%.*]] = load i32, ptr [[A:%.*]], align 4
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[LOAD]], 0
+; CHECK-NEXT:    tail call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    ret i1 false
+;
+  %load = load i32, ptr %a
+  %cmp = icmp ne i32 %load, 0
+  tail call void @llvm.assume(i1 %cmp)
+  %rval = icmp eq i32 %load, 0
+  ret i1 %rval
+}
+
+; Make sure the above canonicalization does not trigger
+; if the assume is control dependent on something else
+
+define i1 @nonnull3(ptr %a, i1 %control) {
+; FIXME: in the BUNDLES version we could duplicate the load and keep the assume nonnull.
+; CHECK-LABEL: @nonnull3(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br i1 [[CONTROL:%.*]], label [[TAKEN:%.*]], label [[NOT_TAKEN:%.*]]
+; CHECK:       taken:
+; CHECK-NEXT:    ret i1 false
+; CHECK:       not_taken:
+; CHECK-NEXT:    [[LOAD:%.*]] = load ptr, ptr [[A:%.*]], align 8
+; CHECK-NEXT:    [[RVAL_2:%.*]] = icmp sgt ptr [[LOAD]], null
+; CHECK-NEXT:    ret i1 [[RVAL_2]]
+;
+entry:
+  %load = load ptr, ptr %a
+  %cmp = icmp ne ptr %load, null
+  br i1 %control, label %taken, label %not_taken
+taken:
+  tail call void @llvm.assume(i1 %cmp)
+  %rval = icmp eq ptr %load, null
+  ret i1 %rval
+not_taken:
+  %rval.2 = icmp sgt ptr %load, null
+  ret i1 %rval.2
+}
+
+; Make sure the above canonicalization does not trigger
+; if the path from the load to the assume is potentially
+; interrupted by an exception being thrown
+
+define i1 @nonnull4(ptr %a) {
+; CHECK-LABEL: @nonnull4(
+; CHECK-NEXT:    [[LOAD:%.*]] = load ptr, ptr [[A:%.*]], align 8
+; CHECK-NEXT:    tail call void @escape(ptr nonnull [[LOAD]])
+; CHECK-NEXT:    ret i1 false
+;
+  %load = load ptr, ptr %a
+  ;; This call may throw!
+  tail call void @escape(ptr %load)
+  %cmp = icmp ne ptr %load, null
+  tail call void @llvm.assume(i1 %cmp)
+  %rval = icmp eq ptr %load, null
+  ret i1 %rval
+}
+define i1 @nonnull5(ptr %a) {
+; CHECK-LABEL: @nonnull5(
+; CHECK-NEXT:    [[LOAD:%.*]] = load ptr, ptr [[A:%.*]], align 8
+; CHECK-NEXT:    tail call void @escape(ptr nonnull [[LOAD]])
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt ptr [[LOAD]], null
+; CHECK-NEXT:    tail call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    ret i1 false
+;
+  %load = load ptr, ptr %a
+  ;; This call may throw!
+  tail call void @escape(ptr %load)
+  %integral = ptrtoint ptr %load to i64
+  %cmp = icmp slt i64 %integral, 0
+  tail call void @llvm.assume(i1 %cmp) ; %load has at least highest bit set
+  %rval = icmp eq ptr %load, null
+  ret i1 %rval
+}
+
+; PR35846 - https://bugs.llvm.org/show_bug.cgi?id=35846
+
+define i32 @assumption_conflicts_with_known_bits(i32 %a, i32 %b) {
+; CHECK-LABEL: @assumption_conflicts_with_known_bits(
+; CHECK-NEXT:    store i1 true, ptr poison, align 1
+; CHECK-NEXT:    ret i32 poison
+;
+  %and1 = and i32 %b, 3
+  %B1 = lshr i32 %and1, %and1
+  %B3 = shl nuw nsw i32 %and1, %B1
+  %cmp = icmp eq i32 %B3, 1
+  tail call void @llvm.assume(i1 %cmp)
+  %cmp2 = icmp eq i32 %B1, %B3
+  tail call void @llvm.assume(i1 %cmp2)
+  ret i32 %and1
+}
+
+; PR37726 - https://bugs.llvm.org/show_bug.cgi?id=37726
+; There's a loophole in eliminating a redundant assumption when
+; we have conflicting assumptions. Verify that debuginfo doesn't
+; get in the way of the fold.
+
+define void @debug_interference(i8 %x) {
+; CHECK-LABEL: @debug_interference(
+; CHECK-NEXT:    tail call void @llvm.dbg.value(metadata i32 5, metadata [[META6:![0-9]+]], metadata !DIExpression()), !dbg [[DBG8:![0-9]+]]
+; CHECK-NEXT:    store i1 true, ptr poison, align 1
+; CHECK-NEXT:    ret void
+;
+  %cmp1 = icmp eq i8 %x, 0
+  %cmp2 = icmp ne i8 %x, 0
+  tail call void @llvm.assume(i1 %cmp1)
+  tail call void @llvm.dbg.value(metadata i32 5, metadata !1, metadata !DIExpression()), !dbg !9
+  tail call void @llvm.assume(i1 %cmp1)
+  tail call void @llvm.dbg.value(metadata i32 5, metadata !1, metadata !DIExpression()), !dbg !9
+  tail call void @llvm.assume(i1 %cmp2)
+  tail call void @llvm.dbg.value(metadata i32 5, metadata !1, metadata !DIExpression()), !dbg !9
+  tail call void @llvm.assume(i1 %cmp2)
+  ret void
+}
+
+; This would crash.
+; Does it ever make sense to peek through a bitcast of the icmp operand?
+
+define i32 @PR40940(<4 x i8> %x) {
+; CHECK-LABEL: @PR40940(
+; CHECK-NEXT:    [[SHUF:%.*]] = shufflevector <4 x i8> [[X:%.*]], <4 x i8> poison, <4 x i32> <i32 1, i32 1, i32 2, i32 3>
+; CHECK-NEXT:    [[T2:%.*]] = bitcast <4 x i8> [[SHUF]] to i32
+; CHECK-NEXT:    [[T3:%.*]] = icmp ult i32 [[T2]], 65536
+; CHECK-NEXT:    call void @llvm.assume(i1 [[T3]])
+; CHECK-NEXT:    ret i32 [[T2]]
+;
+  %shuf = shufflevector <4 x i8> %x, <4 x i8> undef, <4 x i32> <i32 1, i32 1, i32 2, i32 3>
+  %t2 = bitcast <4 x i8> %shuf to i32
+  %t3 = icmp ult i32 %t2, 65536
+  call void @llvm.assume(i1 %t3)
+  ret i32 %t2
+}
+
+define i1 @nonnull3A(ptr %a, i1 %control) {
+; CHECK-LABEL: @nonnull3A(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br i1 [[CONTROL:%.*]], label [[TAKEN:%.*]], label [[NOT_TAKEN:%.*]]
+; CHECK:       taken:
+; CHECK-NEXT:    ret i1 true
+; CHECK:       not_taken:
+; CHECK-NEXT:    [[LOAD:%.*]] = load ptr, ptr [[A:%.*]], align 8
+; CHECK-NEXT:    [[RVAL_2:%.*]] = icmp sgt ptr [[LOAD]], null
+; CHECK-NEXT:    ret i1 [[RVAL_2]]
+;
+entry:
+  %load = load ptr, ptr %a
+  %cmp = icmp ne ptr %load, null
+  br i1 %control, label %taken, label %not_taken
+taken:
+  call void @llvm.assume(i1 %cmp)
+  ret i1 %cmp
+not_taken:
+  call void @llvm.assume(i1 %cmp)
+  %rval.2 = icmp sgt ptr %load, null
+  ret i1 %rval.2
+}
+
+define i1 @nonnull3B(ptr %a, i1 %control) {
+; CHECK-LABEL: @nonnull3B(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[LOAD:%.*]] = load ptr, ptr [[A:%.*]], align 8
+; CHECK-NEXT:    br i1 [[CONTROL:%.*]], label [[TAKEN:%.*]], label [[NOT_TAKEN:%.*]]
+; CHECK:       taken:
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "nonnull"(ptr [[LOAD]]) ]
+; CHECK-NEXT:    ret i1 true
+; CHECK:       not_taken:
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "nonnull"(ptr [[LOAD]]) ]
+; CHECK-NEXT:    ret i1 [[CONTROL]]
+;
+entry:
+  %load = load ptr, ptr %a
+  %cmp = icmp ne ptr %load, null
+  br i1 %control, label %taken, label %not_taken
+taken:
+  call void @llvm.assume(i1 %cmp) ["nonnull"(ptr %load)]
+  ret i1 %cmp
+not_taken:
+  call void @llvm.assume(i1 %cmp) ["nonnull"(ptr %load)]
+  ret i1 %control
+}
+
+declare i1 @tmp1(i1)
+
+define i1 @nonnull3C(ptr %a, i1 %control) {
+; CHECK-LABEL: @nonnull3C(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[LOAD:%.*]] = load ptr, ptr [[A:%.*]], align 8
+; CHECK-NEXT:    br i1 [[CONTROL:%.*]], label [[TAKEN:%.*]], label [[NOT_TAKEN:%.*]]
+; CHECK:       taken:
+; CHECK-NEXT:    [[CMP2:%.*]] = call i1 @tmp1(i1 true)
+; CHECK-NEXT:    br label [[EXIT:%.*]]
+; CHECK:       exit:
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "nonnull"(ptr [[LOAD]]) ]
+; CHECK-NEXT:    ret i1 [[CMP2]]
+; CHECK:       not_taken:
+; CHECK-NEXT:    ret i1 [[CONTROL]]
+;
+entry:
+  %load = load ptr, ptr %a
+  %cmp = icmp ne ptr %load, null
+  br i1 %control, label %taken, label %not_taken
+taken:
+  %cmp2 = call i1 @tmp1(i1 %cmp)
+  br label %exit
+exit:
+  ; FIXME: this shouldn't be dropped because it is still dominated by the new position of %load
+  call void @llvm.assume(i1 %cmp) ["nonnull"(ptr %load)]
+  ret i1 %cmp2
+not_taken:
+  call void @llvm.assume(i1 %cmp)
+  ret i1 %control
+}
+
+define i1 @nonnull3D(ptr %a, i1 %control) {
+; CHECK-LABEL: @nonnull3D(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[LOAD:%.*]] = load ptr, ptr [[A:%.*]], align 8
+; CHECK-NEXT:    br i1 [[CONTROL:%.*]], label [[TAKEN:%.*]], label [[NOT_TAKEN:%.*]]
+; CHECK:       taken:
+; CHECK-NEXT:    [[CMP2:%.*]] = call i1 @tmp1(i1 true)
+; CHECK-NEXT:    br label [[EXIT:%.*]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret i1 [[CMP2]]
+; CHECK:       not_taken:
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "nonnull"(ptr [[LOAD]]) ]
+; CHECK-NEXT:    ret i1 [[CONTROL]]
+;
+entry:
+  %load = load ptr, ptr %a
+  %cmp = icmp ne ptr %load, null
+  br i1 %control, label %taken, label %not_taken
+taken:
+  %cmp2 = call i1 @tmp1(i1 %cmp)
+  br label %exit
+exit:
+  ret i1 %cmp2
+not_taken:
+  call void @llvm.assume(i1 %cmp) ["nonnull"(ptr %load)]
+  ret i1 %control
+}
+
+
+define void @always_true_assumption() {
+; CHECK-LABEL: @always_true_assumption(
+; CHECK-NEXT:    ret void
+;
+  call void @llvm.assume(i1 true)
+  ret void
+}
+
+; The alloca guarantees that the low bits of %a are zero because of alignment.
+; The assume says the opposite. Make sure we don't crash.
+
+define i64 @PR31809() {
+; CHECK-LABEL: @PR31809(
+; CHECK-NEXT:    store i1 true, ptr poison, align 1
+; CHECK-NEXT:    ret i64 poison
+;
+  %a = alloca i32
+  %t1 = ptrtoint ptr %a to i64
+  %cond = icmp eq i64 %t1, 3
+  call void @llvm.assume(i1 %cond)
+  ret i64 %t1
+}
+
+; Similar to above: there's no way to know which assumption is truthful,
+; so just don't crash.
+
+define i8 @conflicting_assumptions(i8 %x){
+; CHECK-LABEL: @conflicting_assumptions(
+; CHECK-NEXT:    store i1 true, ptr poison, align 1
+; CHECK-NEXT:    ret i8 poison
+;
+  %add = add i8 %x, 1
+  %cond1 = icmp eq i8 %x, 3
+  call void @llvm.assume(i1 %cond1)
+  %cond2 = icmp eq i8 %x, 4
+  call void @llvm.assume(i1 %cond2)
+  ret i8 %add
+}
+
+; Another case of conflicting assumptions. This would crash because we'd
+; try to set more known bits than existed in the known bits struct.
+
+define void @PR36270(i32 %b) {
+; CHECK-LABEL: @PR36270(
+; CHECK-NEXT:    unreachable
+;
+  %B7 = xor i32 -1, 2147483647
+  %and1 = and i32 %b, 3
+  %B12 = lshr i32 %B7, %and1
+  %C1 = icmp ult i32 %and1, %B12
+  tail call void @llvm.assume(i1 %C1)
+  %cmp2 = icmp eq i32 0, %B12
+  tail call void @llvm.assume(i1 %cmp2)
+  unreachable
+}
+
+; PR47416
+
+define i32 @unreachable_assume(i32 %x, i32 %y) {
+; CHECK-LABEL: @unreachable_assume(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP0:%.*]] = icmp sgt i32 [[X:%.*]], 1
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i32 [[Y:%.*]], 1
+; CHECK-NEXT:    [[OR:%.*]] = or i1 [[CMP0]], [[CMP1]]
+; CHECK-NEXT:    tail call void @llvm.assume(i1 [[OR]])
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp eq i32 [[X]], 1
+; CHECK-NEXT:    br i1 [[CMP2]], label [[IF:%.*]], label [[EXIT:%.*]]
+; CHECK:       if:
+; CHECK-NEXT:    [[A:%.*]] = and i32 [[Y]], -2
+; CHECK-NEXT:    [[CMP3:%.*]] = icmp ne i32 [[A]], 104
+; CHECK-NEXT:    tail call void @llvm.assume(i1 [[CMP3]])
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    unreachable
+;
+entry:
+  %cmp0 = icmp sgt i32 %x, 1
+  %cmp1 = icmp eq i32 %y, 1
+  %or = or i1 %cmp0, %cmp1
+  tail call void @llvm.assume(i1 %or)
+  %cmp2 = icmp eq i32 %x, 1
+  br i1 %cmp2, label %if, label %exit
+
+if:
+  %a = and i32 %y, -2
+  %cmp3 = icmp ne i32 %a, 104
+  tail call void @llvm.assume(i1 %cmp3)
+  br label %exit
+
+exit:
+  %cmp4 = icmp eq i32 %x, 2
+  tail call void @llvm.assume(i1 %cmp4)
+  unreachable
+}
+
+define i32 @unreachable_assume_logical(i32 %x, i32 %y) {
+; CHECK-LABEL: @unreachable_assume_logical(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP0:%.*]] = icmp sgt i32 [[X:%.*]], 1
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i32 [[Y:%.*]], 1
+; CHECK-NEXT:    [[OR:%.*]] = select i1 [[CMP0]], i1 true, i1 [[CMP1]]
+; CHECK-NEXT:    tail call void @llvm.assume(i1 [[OR]])
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp eq i32 [[X]], 1
+; CHECK-NEXT:    br i1 [[CMP2]], label [[IF:%.*]], label [[EXIT:%.*]]
+; CHECK:       if:
+; CHECK-NEXT:    [[A:%.*]] = and i32 [[Y]], -2
+; CHECK-NEXT:    [[CMP3:%.*]] = icmp ne i32 [[A]], 104
+; CHECK-NEXT:    tail call void @llvm.assume(i1 [[CMP3]])
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    unreachable
+;
+entry:
+  %cmp0 = icmp sgt i32 %x, 1
+  %cmp1 = icmp eq i32 %y, 1
+  %or = select i1 %cmp0, i1 true, i1 %cmp1
+  tail call void @llvm.assume(i1 %or)
+  %cmp2 = icmp eq i32 %x, 1
+  br i1 %cmp2, label %if, label %exit
+
+if:
+  %a = and i32 %y, -2
+  %cmp3 = icmp ne i32 %a, 104
+  tail call void @llvm.assume(i1 %cmp3)
+  br label %exit
+
+exit:
+  %cmp4 = icmp eq i32 %x, 2
+  tail call void @llvm.assume(i1 %cmp4)
+  unreachable
+}
+
+define i32 @unreachable_assumes_and_store(i32 %x, i32 %y, ptr %p) {
+; CHECK-LABEL: @unreachable_assumes_and_store(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP0:%.*]] = icmp sgt i32 [[X:%.*]], 1
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i32 [[Y:%.*]], 1
+; CHECK-NEXT:    [[OR:%.*]] = or i1 [[CMP0]], [[CMP1]]
+; CHECK-NEXT:    tail call void @llvm.assume(i1 [[OR]])
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp eq i32 [[X]], 1
+; CHECK-NEXT:    br i1 [[CMP2]], label [[IF:%.*]], label [[EXIT:%.*]]
+; CHECK:       if:
+; CHECK-NEXT:    [[A:%.*]] = and i32 [[Y]], -2
+; CHECK-NEXT:    [[CMP3:%.*]] = icmp ne i32 [[A]], 104
+; CHECK-NEXT:    tail call void @llvm.assume(i1 [[CMP3]])
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    unreachable
+;
+entry:
+  %cmp0 = icmp sgt i32 %x, 1
+  %cmp1 = icmp eq i32 %y, 1
+  %or = or i1 %cmp0, %cmp1
+  tail call void @llvm.assume(i1 %or)
+  %cmp2 = icmp eq i32 %x, 1
+  br i1 %cmp2, label %if, label %exit
+
+if:
+  %a = and i32 %y, -2
+  %cmp3 = icmp ne i32 %a, 104
+  tail call void @llvm.assume(i1 %cmp3)
+  br label %exit
+
+exit:
+  %cmp4 = icmp eq i32 %x, 2
+  tail call void @llvm.assume(i1 %cmp4)
+  %cmp5 = icmp ugt i32 %y, 42
+  tail call void @llvm.assume(i1 %cmp5)
+  store i32 %x, ptr %p
+  unreachable
+}
+
+define i32 @unreachable_assumes_and_store_logical(i32 %x, i32 %y, ptr %p) {
+; CHECK-LABEL: @unreachable_assumes_and_store_logical(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP0:%.*]] = icmp sgt i32 [[X:%.*]], 1
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i32 [[Y:%.*]], 1
+; CHECK-NEXT:    [[OR:%.*]] = select i1 [[CMP0]], i1 true, i1 [[CMP1]]
+; CHECK-NEXT:    tail call void @llvm.assume(i1 [[OR]])
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp eq i32 [[X]], 1
+; CHECK-NEXT:    br i1 [[CMP2]], label [[IF:%.*]], label [[EXIT:%.*]]
+; CHECK:       if:
+; CHECK-NEXT:    [[A:%.*]] = and i32 [[Y]], -2
+; CHECK-NEXT:    [[CMP3:%.*]] = icmp ne i32 [[A]], 104
+; CHECK-NEXT:    tail call void @llvm.assume(i1 [[CMP3]])
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    unreachable
+;
+entry:
+  %cmp0 = icmp sgt i32 %x, 1
+  %cmp1 = icmp eq i32 %y, 1
+  %or = select i1 %cmp0, i1 true, i1 %cmp1
+  tail call void @llvm.assume(i1 %or)
+  %cmp2 = icmp eq i32 %x, 1
+  br i1 %cmp2, label %if, label %exit
+
+if:
+  %a = and i32 %y, -2
+  %cmp3 = icmp ne i32 %a, 104
+  tail call void @llvm.assume(i1 %cmp3)
+  br label %exit
+
+exit:
+  %cmp4 = icmp eq i32 %x, 2
+  tail call void @llvm.assume(i1 %cmp4)
+  %cmp5 = icmp ugt i32 %y, 42
+  tail call void @llvm.assume(i1 %cmp5)
+  store i32 %x, ptr %p
+  unreachable
+}
+
+define void @canonicalize_assume(ptr %0) {
+; DEFAULT-LABEL: @canonicalize_assume(
+; DEFAULT-NEXT:    [[TMP2:%.*]] = getelementptr inbounds i8, ptr [[TMP0:%.*]], i64 8
+; DEFAULT-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[TMP2]], i64 16) ]
+; DEFAULT-NEXT:    ret void
+;
+; BUNDLES-LABEL: @canonicalize_assume(
+; BUNDLES-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[TMP0:%.*]], i64 8) ]
+; BUNDLES-NEXT:    ret void
+;
+  %2 = getelementptr inbounds i32, ptr %0, i64 2
+  call void @llvm.assume(i1 true) [ "align"(ptr %2, i64 16) ]
+  ret void
+}
+
+define void @assume_makes_and_known_assume_on_arg(ptr %p, i32 %x) {
+; CHECK-LABEL: @assume_makes_and_known_assume_on_arg(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], 1
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[AND]], 0
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    store i32 0, ptr [[P:%.*]], align 4
+; CHECK-NEXT:    ret void
+;
+  %and = and i32 %x, 1
+  %cmp = icmp eq i32 %and, 0
+  call void @llvm.assume(i1 %cmp)
+  %and2 = and i32 %x, 1
+  store i32 %and2, ptr %p
+  ret void
+}
+
+define void @assume_makes_and_known_assume_on_mul(ptr %p, i32 %a, i32 %b) {
+; CHECK-LABEL: @assume_makes_and_known_assume_on_mul(
+; CHECK-NEXT:    [[X:%.*]] = mul i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X]], 1
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[AND]], 0
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    store i32 0, ptr [[P:%.*]], align 4
+; CHECK-NEXT:    ret void
+;
+  %x = mul i32 %a, %b
+  %and = and i32 %x, 1
+  %cmp = icmp eq i32 %and, 0
+  call void @llvm.assume(i1 %cmp)
+  %and2 = and i32 %x, 1
+  store i32 %and2, ptr %p
+  ret void
+}
+
+define void @assume_makes_and_known_assume_on_bitwise(ptr %p, i32 %a, i32 %b) {
+; CHECK-LABEL: @assume_makes_and_known_assume_on_bitwise(
+; CHECK-NEXT:    [[X:%.*]] = or i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X]], 1
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[AND]], 0
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    store i32 0, ptr [[P:%.*]], align 4
+; CHECK-NEXT:    ret void
+;
+  %x = or i32 %a, %b
+  %and = and i32 %x, 1
+  %cmp = icmp eq i32 %and, 0
+  call void @llvm.assume(i1 %cmp)
+  %and2 = and i32 %x, 1
+  store i32 %and2, ptr %p
+  ret void
+}
+
+define i32 @range_16_31_top28(i32 %x) {
+; CHECK-LABEL: @range_16_31_top28(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[X:%.*]], -16
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[TMP1]], 16
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    ret i32 16
+;
+  %add = add i32 %x, -16
+  %cmp = icmp ult i32 %add, 16
+  call void @llvm.assume(i1 %cmp)
+  %res = and i32 %x, u0xfffffff0
+  ret i32 %res
+}
+
+define i32 @range_16_31_top29(i32 %x) {
+; CHECK-LABEL: @range_16_31_top29(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[X:%.*]], -16
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[TMP1]], 16
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    [[RES:%.*]] = and i32 [[X]], 24
+; CHECK-NEXT:    ret i32 [[RES]]
+;
+  %add = add i32 %x, -16
+  %cmp = icmp ult i32 %add, 16
+  call void @llvm.assume(i1 %cmp)
+  %res = and i32 %x, u0xfffffff8
+  ret i32 %res
+}
+
+define i32 @range_16_30_top28(i32 %x) {
+; CHECK-LABEL: @range_16_30_top28(
+; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[X:%.*]], -16
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[ADD]], 15
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    ret i32 16
+;
+  %add = add i32 %x, -16
+  %cmp = icmp ult i32 %add, 15
+  call void @llvm.assume(i1 %cmp)
+  %res = and i32 %x, u0xfffffff0
+  ret i32 %res
+}
+
+define i32 @range_16_32_top28(i32 %x) {
+; CHECK-LABEL: @range_16_32_top28(
+; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[X:%.*]], -16
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[ADD]], 17
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    [[RES:%.*]] = and i32 [[X]], 48
+; CHECK-NEXT:    ret i32 [[RES]]
+;
+  %add = add i32 %x, -16
+  %cmp = icmp ult i32 %add, 17
+  call void @llvm.assume(i1 %cmp)
+  %res = and i32 %x, u0xfffffff0
+  ret i32 %res
+}
+
+define i32 @range_16_32_top27(i32 %x) {
+; CHECK-LABEL: @range_16_32_top27(
+; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[X:%.*]], -16
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[ADD]], 17
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    [[RES:%.*]] = and i32 [[X]], 32
+; CHECK-NEXT:    ret i32 [[RES]]
+;
+  %add = add i32 %x, -16
+  %cmp = icmp ult i32 %add, 17
+  call void @llvm.assume(i1 %cmp)
+  %res = and i32 %x, u0xffffffe0
+  ret i32 %res
+}
+
+define i32 @range_16_32_top26(i32 %x) {
+; CHECK-LABEL: @range_16_32_top26(
+; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[X:%.*]], -16
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[ADD]], 17
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    ret i32 0
+;
+  %add = add i32 %x, -16
+  %cmp = icmp ult i32 %add, 17
+  call void @llvm.assume(i1 %cmp)
+  %res = and i32 %x, u0xffffffc0
+  ret i32 %res
+}
+
+define i32 @range_15_31_top28(i32 %x) {
+; CHECK-LABEL: @range_15_31_top28(
+; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[X:%.*]], -15
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[ADD]], 16
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    [[RES:%.*]] = and i32 [[X]], 16
+; CHECK-NEXT:    ret i32 [[RES]]
+;
+  %add = add i32 %x, -15
+  %cmp = icmp ult i32 %add, 16
+  call void @llvm.assume(i1 %cmp)
+  %res = and i32 %x, u0xfffffff0
+  ret i32 %res
+}
+
+define i32 @range_15_31_top27(i32 %x) {
+; CHECK-LABEL: @range_15_31_top27(
+; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[X:%.*]], -15
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[ADD]], 16
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    ret i32 0
+;
+  %add = add i32 %x, -15
+  %cmp = icmp ult i32 %add, 16
+  call void @llvm.assume(i1 %cmp)
+  %res = and i32 %x, u0xffffffe0
+  ret i32 %res
+}
+
+declare void @llvm.dbg.value(metadata, metadata, metadata)
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!5, !6, !7, !8}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C, file: !3, producer: "Me", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: null, retainedTypes: null, imports: null)
+!1 = !DILocalVariable(name: "", arg: 1, scope: !2, file: null, line: 1, type: null)
+!2 = distinct !DISubprogram(name: "debug", linkageName: "debug", scope: null, file: null, line: 0, type: null, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped, isOptimized: true, unit: !0)
+!3 = !DIFile(filename: "consecutive-fences.ll", directory: "")
+!5 = !{i32 2, !"Dwarf Version", i32 4}
+!6 = !{i32 2, !"Debug Info Version", i32 3}
+!7 = !{i32 1, !"wchar_size", i32 4}
+!8 = !{i32 7, !"PIC Level", i32 2}
+!9 = !DILocation(line: 0, column: 0, scope: !2)
+
+
+attributes #0 = { nounwind uwtable }
+attributes #1 = { nounwind }
+
diff --git a/llvm/test/Transforms/InstCombine/assume-icmp-null-select-dl-sentinel.ll b/llvm/test/Transforms/InstCombine/assume-icmp-null-select-dl-sentinel.ll
new file mode 100755
index 0000000000000..d49b6b30afcba
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/assume-icmp-null-select-dl-sentinel.ll
@@ -0,0 +1,37 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-z0:1-z2:neg1-z3:neg1-z5:neg1-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define ptr @example(ptr dereferenceable(24) %x) {
+; CHECK-LABEL: @example(
+; CHECK-NEXT:    ret ptr [[X:%.*]]
+;
+  %y = load ptr, ptr %x, align 8
+  %y_is_null = icmp eq ptr %y, null
+
+  %res = select i1 %y_is_null, ptr null, ptr %x
+
+  %nonnull = icmp ne ptr %res, null
+  call void @llvm.assume(i1 %nonnull)
+
+  ret ptr %res
+}
+
+; TODO: this should be folded to `ret ptr %x` as well.
+define ptr @example2(ptr %x) {
+; CHECK-LABEL: @example2(
+; CHECK-NEXT:    ret ptr [[X:%.*]]
+;
+  %y = load ptr, ptr %x, align 8
+  %y_is_null = icmp eq ptr %y, null
+
+  %res = select i1 %y_is_null, ptr null, ptr %x
+
+  %nonnull = icmp ne ptr %res, null
+  call void @llvm.assume(i1 %nonnull)
+
+  ret ptr %res
+}
+
+declare void @llvm.assume(i1)
diff --git a/llvm/test/Transforms/InstSimplify/compare-dl-sentinel.ll b/llvm/test/Transforms/InstSimplify/compare-dl-sentinel.ll
new file mode 100755
index 0000000000000..0fc0d22ed76c3
--- /dev/null
+++ b/llvm/test/Transforms/InstSimplify/compare-dl-sentinel.ll
@@ -0,0 +1,3270 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -passes=instsimplify -S | FileCheck %s
+target datalayout = "p:32:32-p1:64:64-z0:1-z2:neg1-z3:neg1-z5:neg1"
+
+declare void @llvm.assume(i1)
+
+define i1 @ptrtoint() {
+; CHECK-LABEL: @ptrtoint(
+; CHECK-NEXT:    ret i1 false
+;
+  %a = alloca i8
+  %tmp = ptrtoint ptr %a to i32
+  %r = icmp eq i32 %tmp, 0
+  ret i1 %r
+}
+
+define i1 @bitcast() {
+; CHECK-LABEL: @bitcast(
+; CHECK-NEXT:    ret i1 false
+;
+  %a = alloca i32
+  %b = alloca i64
+  %cmp = icmp eq ptr %a, %b
+  ret i1 %cmp
+}
+
+define i1 @gep() {
+; CHECK-LABEL: @gep(
+; CHECK-NEXT:    ret i1 false
+;
+  %a = alloca [3 x i8], align 8
+  %cmp = icmp eq ptr %a, null
+  ret i1 %cmp
+}
+
+define i1 @gep2() {
+; CHECK-LABEL: @gep2(
+; CHECK-NEXT:    ret i1 true
+;
+  %a = alloca [3 x i8], align 8
+  %cmp = icmp eq ptr %a, %a
+  ret i1 %cmp
+}
+
+; PR11238
+%gept = type { i32, i32 }
+ at gepy = global %gept zeroinitializer, align 8
+ at gepz = extern_weak global %gept
+
+define i1 @gep3() {
+; CHECK-LABEL: @gep3(
+; CHECK-NEXT:    ret i1 false
+;
+  %x = alloca %gept, align 8
+  %b = getelementptr %gept, ptr %x, i64 0, i32 1
+  %equal = icmp eq ptr %x, %b
+  ret i1 %equal
+}
+
+define i1 @gep4() {
+; CHECK-LABEL: @gep4(
+; CHECK-NEXT:    ret i1 false
+;
+  %x = alloca %gept, align 8
+  %b = getelementptr %gept, ptr @gepy, i64 0, i32 1
+  %equal = icmp eq ptr @gepy, %b
+  ret i1 %equal
+}
+
+ at a = common global [1 x i32] zeroinitializer, align 4
+
+define i1 @PR31262() {
+; CHECK-LABEL: @PR31262(
+; CHECK-NEXT:    ret i1 true
+;
+  %idx = getelementptr inbounds [1 x i32], ptr @a, i64 0, i64 undef
+  %cmp = icmp uge ptr %idx, @a
+  ret i1 %cmp
+}
+
+define i1 @gep5() {
+; CHECK-LABEL: @gep5(
+; CHECK-NEXT:    ret i1 false
+;
+  %x = alloca %gept, align 8
+  %a = getelementptr inbounds %gept, ptr %x, i64 0, i32 1
+  %equal = icmp eq ptr %a, @gepy
+  ret i1 %equal
+}
+
+define i1 @gep6(ptr %x) {
+; Same as @gep3 but potentially null.
+; CHECK-LABEL: @gep6(
+; CHECK-NEXT:    ret i1 false
+;
+  %b = getelementptr %gept, ptr %x, i64 0, i32 1
+  %equal = icmp eq ptr %x, %b
+  ret i1 %equal
+}
+
+define i1 @gep7(ptr %x) {
+; CHECK-LABEL: @gep7(
+; CHECK-NEXT:    [[EQUAL:%.*]] = icmp eq ptr [[X:%.*]], @gepz
+; CHECK-NEXT:    ret i1 [[EQUAL]]
+;
+  %equal = icmp eq ptr %x, @gepz
+  ret i1 %equal
+}
+
+define i1 @gep8(ptr %x) {
+; CHECK-LABEL: @gep8(
+; CHECK-NEXT:    [[A:%.*]] = getelementptr [[GEPT:%.*]], ptr [[X:%.*]], i32 1
+; CHECK-NEXT:    [[B:%.*]] = getelementptr [[GEPT]], ptr [[X]], i32 -1
+; CHECK-NEXT:    [[EQUAL:%.*]] = icmp ugt ptr [[A]], [[B]]
+; CHECK-NEXT:    ret i1 [[EQUAL]]
+;
+  %a = getelementptr %gept, ptr %x, i32 1
+  %b = getelementptr %gept, ptr %x, i32 -1
+  %equal = icmp ugt ptr %a, %b
+  ret i1 %equal
+}
+
+define i1 @gep9(ptr %ptr) {
+; CHECK-LABEL: @gep9(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    ret i1 true
+;
+entry:
+  %first2 = getelementptr inbounds i8, ptr %ptr, i32 1
+  %first3 = getelementptr inbounds i8, ptr %first2, i32 2
+  %first4 = getelementptr inbounds i8, ptr %first3, i32 4
+  %last1 = getelementptr inbounds i8, ptr %first2, i32 48
+  %last2 = getelementptr inbounds i8, ptr %last1, i32 8
+  %last3 = getelementptr inbounds i8, ptr %last2, i32 -4
+  %last4 = getelementptr inbounds i8, ptr %last3, i32 -4
+  %first.int = ptrtoint ptr %first4 to i32
+  %last.int = ptrtoint ptr %last4 to i32
+  %cmp = icmp ne i32 %last.int, %first.int
+  ret i1 %cmp
+}
+
+define i1 @gep10(ptr %ptr) {
+; CHECK-LABEL: @gep10(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    ret i1 true
+;
+entry:
+  %first1 = getelementptr inbounds i8, ptr %ptr, i32 -2
+  %first2 = getelementptr inbounds i8, ptr %first1, i32 44
+  %last1 = getelementptr inbounds i8, ptr %ptr, i32 48
+  %last2 = getelementptr inbounds i8, ptr %last1, i32 -6
+  %first.int = ptrtoint ptr %first2 to i32
+  %last.int = ptrtoint ptr %last2 to i32
+  %cmp = icmp eq i32 %last.int, %first.int
+  ret i1 %cmp
+}
+
+define i1 @gep11(ptr %ptr) {
+; CHECK-LABEL: @gep11(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    ret i1 true
+;
+entry:
+  %first1 = getelementptr inbounds i8, ptr %ptr, i32 -2
+  %last1 = getelementptr inbounds i8, ptr %ptr, i32 48
+  %last2 = getelementptr inbounds i8, ptr %last1, i32 -6
+  %cmp = icmp ult ptr %first1, %last2
+  ret i1 %cmp
+}
+
+define i1 @gep12(ptr %ptr) {
+; CHECK-LABEL: @gep12(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[FIRST1:%.*]] = getelementptr inbounds i8, ptr [[PTR:%.*]], i32 -2
+; CHECK-NEXT:    [[LAST1:%.*]] = getelementptr inbounds i8, ptr [[PTR]], i32 48
+; CHECK-NEXT:    [[LAST2:%.*]] = getelementptr inbounds i8, ptr [[LAST1]], i32 -6
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt ptr [[FIRST1]], [[LAST2]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+entry:
+  %first1 = getelementptr inbounds i8, ptr %ptr, i32 -2
+  %last1 = getelementptr inbounds i8, ptr %ptr, i32 48
+  %last2 = getelementptr inbounds i8, ptr %last1, i32 -6
+  %cmp = icmp slt ptr %first1, %last2
+  ret i1 %cmp
+}
+
+define i1 @gep13(ptr %ptr) {
+; CHECK-LABEL: @gep13(
+; CHECK-NEXT:    ret i1 false
+;
+; We can prove this GEP is non-null because it is inbounds.
+  %x = getelementptr inbounds i8, ptr %ptr, i32 1
+  %cmp = icmp eq ptr %x, null
+  ret i1 %cmp
+}
+
+define i1 @gep13_no_null_opt(ptr %ptr) #0 {
+; We can't prove this GEP is non-null.
+; CHECK-LABEL: @gep13_no_null_opt(
+; CHECK-NEXT:    ret i1 false
+;
+  %x = getelementptr inbounds i8, ptr %ptr, i32 1
+  %cmp = icmp eq ptr %x, null
+  ret i1 %cmp
+}
+
+define i1 @gep14(ptr %ptr) {
+; CHECK-LABEL: @gep14(
+; CHECK-NEXT:    ret i1 false
+;
+; We can't simplify this because the offset of one in the GEP actually doesn't
+; move the pointer.
+  %x = getelementptr inbounds { {}, i8 }, ptr %ptr, i32 0, i32 1
+  %cmp = icmp eq ptr %x, null
+  ret i1 %cmp
+}
+
+define i1 @gep15(ptr %ptr, i32 %y) {
+; CHECK-LABEL: @gep15(
+; CHECK-NEXT:    ret i1 false
+;
+; We can prove this GEP is non-null even though there is a user value, as we
+; would necessarily violate inbounds on one side or the other.
+  %x = getelementptr inbounds { {}, [4 x {i8, i8}]}, ptr %ptr, i32 0, i32 1, i32 %y, i32 1
+  %cmp = icmp eq ptr %x, null
+  ret i1 %cmp
+}
+
+define i1 @gep15_no_null_opt(ptr %ptr, i32 %y) #0 {
+; We can't prove this GEP is non-null.
+; CHECK-LABEL: @gep15_no_null_opt(
+; CHECK-NEXT:    ret i1 false
+;
+  %x = getelementptr inbounds { {}, [4 x {i8, i8}]}, ptr %ptr, i32 0, i32 1, i32 %y, i32 1
+  %cmp = icmp eq ptr %x, null
+  ret i1 %cmp
+}
+
+define i1 @gep16(ptr %ptr, i32 %a) {
+; CHECK-LABEL: @gep16(
+; CHECK-NEXT:    ret i1 false
+;
+; We can prove this GEP is non-null because it is inbounds and because we know
+; %b is non-zero even though we don't know its value.
+  %b = or i32 %a, 1
+  %x = getelementptr inbounds i8, ptr %ptr, i32 %b
+  %cmp = icmp eq ptr %x, null
+  ret i1 %cmp
+}
+
+define i1 @gep16_no_null_opt(ptr %ptr, i32 %a) #0 {
+; We can't prove this GEP is non-null.
+; CHECK-LABEL: @gep16_no_null_opt(
+; CHECK-NEXT:    ret i1 false
+;
+  %b = or i32 %a, 1
+  %x = getelementptr inbounds i8, ptr %ptr, i32 %b
+  %cmp = icmp eq ptr %x, null
+  ret i1 %cmp
+}
+
+define i1 @gep17() {
+; CHECK-LABEL: @gep17(
+; CHECK-NEXT:    ret i1 true
+;
+  %alloca = alloca i32, align 4
+  %gep1 = getelementptr inbounds i32, ptr %alloca, i32 1
+  %pti1 = ptrtoint ptr %gep1 to i32
+  %gep2 = getelementptr inbounds [4 x i8], ptr %alloca, i32 0, i32 1
+  %pti2 = ptrtoint ptr %gep2 to i32
+  %cmp = icmp ugt i32 %pti1, %pti2
+  ret i1 %cmp
+}
+
+; Negative test: GEP inbounds may cross sign boundary.
+define i1 @gep_same_base_constant_indices(ptr %a) {
+; CHECK-LABEL: @gep_same_base_constant_indices(
+; CHECK-NEXT:    [[ARRAYIDX1:%.*]] = getelementptr inbounds i8, ptr [[A:%.*]], i64 1
+; CHECK-NEXT:    [[ARRAYIDX2:%.*]] = getelementptr inbounds i8, ptr [[A]], i64 10
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt ptr [[ARRAYIDX1]], [[ARRAYIDX2]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %arrayidx1 = getelementptr inbounds i8, ptr %a, i64 1
+  %arrayidx2 = getelementptr inbounds i8, ptr %a, i64 10
+  %cmp = icmp slt ptr %arrayidx1, %arrayidx2
+  ret i1 %cmp
+}
+
+define i1 @zext(i32 %x) {
+; CHECK-LABEL: @zext(
+; CHECK-NEXT:    ret i1 true
+;
+  %e1 = zext i32 %x to i64
+  %e2 = zext i32 %x to i64
+  %r = icmp eq i64 %e1, %e2
+  ret i1 %r
+}
+
+define i1 @zext2(i1 %x) {
+; CHECK-LABEL: @zext2(
+; CHECK-NEXT:    ret i1 [[X:%.*]]
+;
+  %e = zext i1 %x to i32
+  %c = icmp ne i32 %e, 0
+  ret i1 %c
+}
+
+define i1 @zext3() {
+; CHECK-LABEL: @zext3(
+; CHECK-NEXT:    ret i1 true
+;
+  %e = zext i1 1 to i32
+  %c = icmp ne i32 %e, 0
+  ret i1 %c
+}
+
+define i1 @sext(i32 %x) {
+; CHECK-LABEL: @sext(
+; CHECK-NEXT:    ret i1 true
+;
+  %e1 = sext i32 %x to i64
+  %e2 = sext i32 %x to i64
+  %r = icmp eq i64 %e1, %e2
+  ret i1 %r
+}
+
+define i1 @sext2(i1 %x) {
+; CHECK-LABEL: @sext2(
+; CHECK-NEXT:    ret i1 [[X:%.*]]
+;
+  %e = sext i1 %x to i32
+  %c = icmp ne i32 %e, 0
+  ret i1 %c
+}
+
+define i1 @sext3() {
+; CHECK-LABEL: @sext3(
+; CHECK-NEXT:    ret i1 true
+;
+  %e = sext i1 1 to i32
+  %c = icmp ne i32 %e, 0
+  ret i1 %c
+}
+
+define i1 @add(i32 %x, i32 %y) {
+; CHECK-LABEL: @add(
+; CHECK-NEXT:    ret i1 false
+;
+  %l = lshr i32 %x, 1
+  %q = lshr i32 %y, 1
+  %r = or i32 %q, 1
+  %s = add i32 %l, %r
+  %c = icmp eq i32 %s, 0
+  ret i1 %c
+}
+
+define i1 @addv(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @addv(
+; CHECK-NEXT:    ret i1 false
+;
+  %l = lshr <2 x i32> %x, <i32 1, i32 0>
+  %q = lshr <2 x i32> %y, <i32 1, i32 0>
+  %r = or <2 x i32> %q, <i32 1, i32 0>
+  %s = add <2 x i32> %l, %r
+  %e = extractelement <2 x i32> %s, i32 0
+  %c = icmp eq i32 %e, 0
+  ret i1 %c
+}
+
+define i1 @add2(i8 %x, i8 %y) {
+; CHECK-LABEL: @add2(
+; CHECK-NEXT:    ret i1 false
+;
+  %l = or i8 %x, 128
+  %r = or i8 %y, 129
+  %s = add i8 %l, %r
+  %c = icmp eq i8 %s, 0
+  ret i1 %c
+}
+
+define i1 @add2v(<2 x i8> %x, <2 x i8> %y) {
+; CHECK-LABEL: @add2v(
+; CHECK-NEXT:    ret i1 false
+;
+  %l = or <2 x i8> %x, <i8 0, i8 128>
+  %r = or <2 x i8> %y, <i8 0, i8 129>
+  %s = add <2 x i8> %l, %r
+  %e = extractelement <2 x i8> %s, i32 1
+  %c = icmp eq i8 %e, 0
+  ret i1 %c
+}
+
+define i1 @add3(i8 %x, i8 %y) {
+; CHECK-LABEL: @add3(
+; CHECK-NEXT:    [[L:%.*]] = zext i8 [[X:%.*]] to i32
+; CHECK-NEXT:    [[R:%.*]] = zext i8 [[Y:%.*]] to i32
+; CHECK-NEXT:    [[S:%.*]] = add i32 [[L]], [[R]]
+; CHECK-NEXT:    [[C:%.*]] = icmp eq i32 [[S]], 0
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %l = zext i8 %x to i32
+  %r = zext i8 %y to i32
+  %s = add i32 %l, %r
+  %c = icmp eq i32 %s, 0
+  ret i1 %c
+}
+
+define i1 @add4(i32 %x, i32 %y) {
+; CHECK-LABEL: @add4(
+; CHECK-NEXT:    ret i1 true
+;
+  %z = add nsw i32 %y, 1
+  %s1 = add nsw i32 %x, %y
+  %s2 = add nsw i32 %x, %z
+  %c = icmp slt i32 %s1, %s2
+  ret i1 %c
+}
+
+define i1 @add5(i32 %x, i32 %y) {
+; CHECK-LABEL: @add5(
+; CHECK-NEXT:    ret i1 true
+;
+  %z = add nuw i32 %y, 1
+  %s1 = add nuw i32 %x, %z
+  %s2 = add nuw i32 %x, %y
+  %c = icmp ugt i32 %s1, %s2
+  ret i1 %c
+}
+
+define i1 @add6(i64 %A, i64 %B) {
+; CHECK-LABEL: @add6(
+; CHECK-NEXT:    ret i1 true
+;
+  %s1 = add i64 %A, %B
+  %s2 = add i64 %B, %A
+  %cmp = icmp eq i64 %s1, %s2
+  ret i1 %cmp
+}
+
+define i1 @addpowtwo(i32 %x, i32 %y) {
+; CHECK-LABEL: @addpowtwo(
+; CHECK-NEXT:    ret i1 false
+;
+  %l = lshr i32 %x, 1
+  %r = shl i32 1, %y
+  %s = add i32 %l, %r
+  %c = icmp eq i32 %s, 0
+  ret i1 %c
+}
+
+define i1 @addpowtwov(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @addpowtwov(
+; CHECK-NEXT:    [[L:%.*]] = lshr <2 x i32> [[X:%.*]], <i32 1, i32 0>
+; CHECK-NEXT:    [[R:%.*]] = shl <2 x i32> <i32 1, i32 0>, [[Y:%.*]]
+; CHECK-NEXT:    [[S:%.*]] = add <2 x i32> [[L]], [[R]]
+; CHECK-NEXT:    [[E:%.*]] = extractelement <2 x i32> [[S]], i32 0
+; CHECK-NEXT:    [[C:%.*]] = icmp eq i32 [[E]], 0
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %l = lshr <2 x i32> %x, <i32 1, i32 0>
+  %r = shl <2 x i32> <i32 1, i32 0>, %y
+  %s = add <2 x i32> %l, %r
+  %e = extractelement <2 x i32> %s, i32 0
+  %c = icmp eq i32 %e, 0
+  ret i1 %c
+}
+
+define i1 @or(i32 %x) {
+; CHECK-LABEL: @or(
+; CHECK-NEXT:    ret i1 false
+;
+  %o = or i32 %x, 1
+  %c = icmp eq i32 %o, 0
+  ret i1 %c
+}
+
+; Do not simplify if we cannot guarantee that the ConstantExpr is a non-zero
+; constant.
+ at GV = common global ptr null
+define i1 @or_constexp(i32 %x) {
+; CHECK-LABEL: @or_constexp(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = and i32 ptrtoint (ptr @GV to i32), 32
+; CHECK-NEXT:    [[O:%.*]] = or i32 [[X:%.*]], [[TMP0]]
+; CHECK-NEXT:    [[C:%.*]] = icmp eq i32 [[O]], 0
+; CHECK-NEXT:    ret i1 [[C]]
+;
+entry:
+  %0 = and i32 ptrtoint (ptr @GV to i32), 32
+  %o = or i32 %x, %0
+  %c = icmp eq i32 %o, 0
+  ret i1 %c
+}
+
+define i1 @shl1(i32 %x) {
+; CHECK-LABEL: @shl1(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = shl i32 1, %x
+  %c = icmp eq i32 %s, 0
+  ret i1 %c
+}
+
+define i1 @lshr1(i32 %x) {
+; CHECK-LABEL: @lshr1(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = lshr i32 -1, %x
+  %c = icmp eq i32 %s, 0
+  ret i1 %c
+}
+
+define i1 @lshr3(i32 %x) {
+; CHECK-LABEL: @lshr3(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = lshr i32 %x, %x
+  %c = icmp eq i32 %s, 0
+  ret i1 %c
+}
+
+define i1 @lshr4(i32 %X, i32 %Y) {
+; CHECK-LABEL: @lshr4(
+; CHECK-NEXT:    ret i1 true
+;
+  %A = lshr i32 %X, %Y
+  %C = icmp ule i32 %A, %X
+  ret i1 %C
+}
+
+define i1 @lshr5(i32 %X, i32 %Y) {
+; CHECK-LABEL: @lshr5(
+; CHECK-NEXT:    ret i1 false
+;
+  %A = lshr i32 %X, %Y
+  %C = icmp ugt i32 %A, %X
+  ret i1 %C
+}
+
+define i1 @lshr6(i32 %X, i32 %Y) {
+; CHECK-LABEL: @lshr6(
+; CHECK-NEXT:    ret i1 false
+;
+  %A = lshr i32 %X, %Y
+  %C = icmp ult i32 %X, %A
+  ret i1 %C
+}
+
+define i1 @lshr7(i32 %X, i32 %Y) {
+; CHECK-LABEL: @lshr7(
+; CHECK-NEXT:    ret i1 true
+;
+  %A = lshr i32 %X, %Y
+  %C = icmp uge i32 %X, %A
+  ret i1 %C
+}
+
+define i1 @lshr_nonzero_eq(i32 %x) {
+; CHECK-LABEL: @lshr_nonzero_eq(
+; CHECK-NEXT:    [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0
+; CHECK-NEXT:    call void @llvm.assume(i1 [[X_NE_0]])
+; CHECK-NEXT:    ret i1 false
+;
+  %x_ne_0 = icmp ne i32 %x, 0
+  call void @llvm.assume(i1 %x_ne_0)
+  %lhs = lshr i32 %x, 1
+  %cmp = icmp eq i32 %lhs, %x
+  ret i1 %cmp
+}
+
+define i1 @lshr_nonzero_uge(i32 %x) {
+; CHECK-LABEL: @lshr_nonzero_uge(
+; CHECK-NEXT:    [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0
+; CHECK-NEXT:    call void @llvm.assume(i1 [[X_NE_0]])
+; CHECK-NEXT:    ret i1 false
+;
+  %x_ne_0 = icmp ne i32 %x, 0
+  call void @llvm.assume(i1 %x_ne_0)
+  %lhs = lshr i32 %x, 1
+  %cmp = icmp uge i32 %lhs, %x
+  ret i1 %cmp
+}
+
+define i1 @lshr_nonzero_ne(i32 %x) {
+; CHECK-LABEL: @lshr_nonzero_ne(
+; CHECK-NEXT:    [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0
+; CHECK-NEXT:    call void @llvm.assume(i1 [[X_NE_0]])
+; CHECK-NEXT:    ret i1 true
+;
+  %x_ne_0 = icmp ne i32 %x, 0
+  call void @llvm.assume(i1 %x_ne_0)
+  %lhs = lshr i32 %x, 1
+  %cmp = icmp ne i32 %lhs, %x
+  ret i1 %cmp
+}
+
+define i1 @lshr_nonzero_ult(i32 %x) {
+; CHECK-LABEL: @lshr_nonzero_ult(
+; CHECK-NEXT:    [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0
+; CHECK-NEXT:    call void @llvm.assume(i1 [[X_NE_0]])
+; CHECK-NEXT:    ret i1 true
+;
+  %x_ne_0 = icmp ne i32 %x, 0
+  call void @llvm.assume(i1 %x_ne_0)
+  %lhs = lshr i32 %x, 1
+  %cmp = icmp ult i32 %lhs, %x
+  ret i1 %cmp
+}
+
+; Negative test - unknown shift amount
+define i1 @lshr_nonzero_neg_unknown(i32 %x, i32 %c) {
+; CHECK-LABEL: @lshr_nonzero_neg_unknown(
+; CHECK-NEXT:    [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0
+; CHECK-NEXT:    call void @llvm.assume(i1 [[X_NE_0]])
+; CHECK-NEXT:    [[LHS:%.*]] = lshr i32 [[X]], [[C:%.*]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[LHS]], [[X]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %x_ne_0 = icmp ne i32 %x, 0
+  call void @llvm.assume(i1 %x_ne_0)
+  %lhs = lshr i32 %x, %c
+  %cmp = icmp ult i32 %lhs, %x
+  ret i1 %cmp
+}
+
+; Negative test - x may be zero
+define i1 @lshr_nonzero_neg_maybe_zero(i32 %x) {
+; CHECK-LABEL: @lshr_nonzero_neg_maybe_zero(
+; CHECK-NEXT:    [[LHS:%.*]] = lshr i32 [[X:%.*]], 1
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[LHS]], [[X]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %lhs = lshr i32 %x, 1
+  %cmp = icmp ult i32 %lhs, %x
+  ret i1 %cmp
+}
+
+; Negative test - signed pred
+define i1 @lshr_nonzero_neg_signed(i32 %x, i32 %c) {
+; CHECK-LABEL: @lshr_nonzero_neg_signed(
+; CHECK-NEXT:    [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0
+; CHECK-NEXT:    call void @llvm.assume(i1 [[X_NE_0]])
+; CHECK-NEXT:    [[LHS:%.*]] = lshr i32 [[X]], 1
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[LHS]], [[X]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %x_ne_0 = icmp ne i32 %x, 0
+  call void @llvm.assume(i1 %x_ne_0)
+  %lhs = lshr i32 %x, 1
+  %cmp = icmp slt i32 %lhs, %x
+  ret i1 %cmp
+}
+
+define i1 @ashr1(i32 %x) {
+; CHECK-LABEL: @ashr1(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = ashr i32 -1, %x
+  %c = icmp eq i32 %s, 0
+  ret i1 %c
+}
+
+define i1 @ashr3(i32 %x) {
+; CHECK-LABEL: @ashr3(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = ashr i32 %x, %x
+  %c = icmp eq i32 %s, 0
+  ret i1 %c
+}
+
+define i1 @select1(i1 %cond) {
+; CHECK-LABEL: @select1(
+; CHECK-NEXT:    ret i1 [[COND:%.*]]
+;
+  %s = select i1 %cond, i32 1, i32 0
+  %c = icmp eq i32 %s, 1
+  ret i1 %c
+}
+
+define i1 @select2(i1 %cond) {
+; CHECK-LABEL: @select2(
+; CHECK-NEXT:    ret i1 [[COND:%.*]]
+;
+  %x = zext i1 %cond to i32
+  %s = select i1 %cond, i32 %x, i32 0
+  %c = icmp ne i32 %s, 0
+  ret i1 %c
+}
+
+define i1 @select3(i1 %cond) {
+; CHECK-LABEL: @select3(
+; CHECK-NEXT:    ret i1 [[COND:%.*]]
+;
+  %x = zext i1 %cond to i32
+  %s = select i1 %cond, i32 1, i32 %x
+  %c = icmp ne i32 %s, 0
+  ret i1 %c
+}
+
+define i1 @select4(i1 %cond) {
+; CHECK-LABEL: @select4(
+; CHECK-NEXT:    ret i1 [[COND:%.*]]
+;
+  %invert = xor i1 %cond, 1
+  %s = select i1 %invert, i32 0, i32 1
+  %c = icmp ne i32 %s, 0
+  ret i1 %c
+}
+
+define i1 @select5(i32 %x) {
+; CHECK-LABEL: @select5(
+; CHECK-NEXT:    ret i1 false
+;
+  %c = icmp eq i32 %x, 0
+  %s = select i1 %c, i32 1, i32 %x
+  %c2 = icmp eq i32 %s, 0
+  ret i1 %c2
+}
+
+define i1 @select6(i32 %x) {
+; CHECK-LABEL: @select6(
+; CHECK-NEXT:    ret i1 false
+;
+  %c = icmp sgt i32 %x, 0
+  %s = select i1 %c, i32 %x, i32 4
+  %c2 = icmp eq i32 %s, 0
+  ret i1 %c2
+}
+
+define i1 @urem1(i32 %X, i32 %Y) {
+; CHECK-LABEL: @urem1(
+; CHECK-NEXT:    ret i1 true
+;
+  %A = urem i32 %X, %Y
+  %B = icmp ult i32 %A, %Y
+  ret i1 %B
+}
+
+define i1 @urem2(i32 %X, i32 %Y) {
+; CHECK-LABEL: @urem2(
+; CHECK-NEXT:    ret i1 false
+;
+  %A = urem i32 %X, %Y
+  %B = icmp eq i32 %A, %Y
+  ret i1 %B
+}
+
+define i1 @urem4(i32 %X) {
+; CHECK-LABEL: @urem4(
+; CHECK-NEXT:    [[A:%.*]] = urem i32 [[X:%.*]], 15
+; CHECK-NEXT:    [[B:%.*]] = icmp ult i32 [[A]], 10
+; CHECK-NEXT:    ret i1 [[B]]
+;
+  %A = urem i32 %X, 15
+  %B = icmp ult i32 %A, 10
+  ret i1 %B
+}
+
+define i1 @urem5(i16 %X, i32 %Y) {
+; CHECK-LABEL: @urem5(
+; CHECK-NEXT:    [[A:%.*]] = zext i16 [[X:%.*]] to i32
+; CHECK-NEXT:    [[B:%.*]] = urem i32 [[A]], [[Y:%.*]]
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i32 [[B]], [[Y]]
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %A = zext i16 %X to i32
+  %B = urem i32 %A, %Y
+  %C = icmp slt i32 %B, %Y
+  ret i1 %C
+}
+
+define i1 @urem6(i32 %X, i32 %Y) {
+; CHECK-LABEL: @urem6(
+; CHECK-NEXT:    ret i1 true
+;
+  %A = urem i32 %X, %Y
+  %B = icmp ugt i32 %Y, %A
+  ret i1 %B
+}
+
+define i1 @urem7(i32 %X) {
+; CHECK-LABEL: @urem7(
+; CHECK-NEXT:    [[A:%.*]] = urem i32 1, [[X:%.*]]
+; CHECK-NEXT:    [[B:%.*]] = icmp sgt i32 [[A]], [[X]]
+; CHECK-NEXT:    ret i1 [[B]]
+;
+  %A = urem i32 1, %X
+  %B = icmp sgt i32 %A, %X
+  ret i1 %B
+}
+
+define i1 @urem8(i8 %X, i8 %Y) {
+; CHECK-LABEL: @urem8(
+; CHECK-NEXT:    ret i1 true
+;
+  %A = urem i8 %X, %Y
+  %B = icmp ule i8 %A, %X
+  ret i1 %B
+}
+
+define i1 @urem9(i8 %X, i8 %Y) {
+; CHECK-LABEL: @urem9(
+; CHECK-NEXT:    ret i1 false
+;
+  %A = urem i8 %X, %Y
+  %B = icmp ugt i8 %A, %X
+  ret i1 %B
+}
+
+define i1 @urem10(i8 %X, i8 %Y) {
+; CHECK-LABEL: @urem10(
+; CHECK-NEXT:    ret i1 true
+;
+  %A = urem i8 %X, %Y
+  %B = icmp uge i8 %X, %A
+  ret i1 %B
+}
+
+define i1 @urem11(i8 %X, i8 %Y) {
+; CHECK-LABEL: @urem11(
+; CHECK-NEXT:    ret i1 false
+;
+  %A = urem i8 %X, %Y
+  %B = icmp ult i8 %X, %A
+  ret i1 %B
+}
+
+; PR9343 #15
+define i1 @srem2(i16 %X, i32 %Y) {
+; CHECK-LABEL: @srem2(
+; CHECK-NEXT:    ret i1 false
+;
+  %A = zext i16 %X to i32
+  %B = add nsw i32 %A, 1
+  %C = srem i32 %B, %Y
+  %D = icmp slt i32 %C, 0
+  ret i1 %D
+}
+
+define i1 @srem2v(<2 x i16> %X, <2 x i32> %Y) {
+; CHECK-LABEL: @srem2v(
+; CHECK-NEXT:    ret i1 false
+;
+  %A = zext <2 x i16> %X to <2 x i32>
+  %B = add nsw <2 x i32> %A, <i32 1, i32 0>
+  %C = srem <2 x i32> %B, %Y
+  %D = extractelement <2 x i32> %C, i32 0
+  %E = icmp slt i32 %D, 0
+  ret i1 %E
+}
+
+define i1 @srem3(i16 %X, i32 %Y) {
+; CHECK-LABEL: @srem3(
+; CHECK-NEXT:    ret i1 false
+;
+  %A = zext i16 %X to i32
+  %B = or i32 2147483648, %A
+  %C = sub nsw i32 1, %B
+  %D = srem i32 %C, %Y
+  %E = icmp slt i32 %D, 0
+  ret i1 %E
+}
+
+define i1 @srem3v(<2 x i16> %X, <2 x i32> %Y) {
+; CHECK-LABEL: @srem3v(
+; CHECK-NEXT:    ret i1 false
+;
+  %A = zext <2 x i16> %X to <2 x i32>
+  %B = or <2 x i32> <i32 1, i32 2147483648>, %A
+  %C = sub nsw <2 x i32> <i32 0, i32 1>, %B
+  %D = srem <2 x i32> %C, %Y
+  %E = extractelement <2 x i32> %C, i32 1
+  %F = icmp slt i32 %E, 0
+  ret i1 %F
+}
+
+define i1 @udiv2(i32 %Z) {
+; CHECK-LABEL: @udiv2(
+; CHECK-NEXT:    ret i1 true
+;
+  %A = udiv exact i32 10, %Z
+  %B = udiv exact i32 20, %Z
+  %C = icmp ult i32 %A, %B
+  ret i1 %C
+}
+
+; Exact sdiv and equality preds can simplify.
+
+define i1 @sdiv_exact_equality(i32 %Z) {
+; CHECK-LABEL: @sdiv_exact_equality(
+; CHECK-NEXT:    ret i1 false
+;
+  %A = sdiv exact i32 10, %Z
+  %B = sdiv exact i32 20, %Z
+  %C = icmp eq i32 %A, %B
+  ret i1 %C
+}
+
+; But not other preds: PR32949 - https://bugs.llvm.org/show_bug.cgi?id=32949
+
+define i1 @sdiv_exact_not_equality(i32 %Z) {
+; CHECK-LABEL: @sdiv_exact_not_equality(
+; CHECK-NEXT:    [[A:%.*]] = sdiv exact i32 10, [[Z:%.*]]
+; CHECK-NEXT:    [[B:%.*]] = sdiv exact i32 20, [[Z]]
+; CHECK-NEXT:    [[C:%.*]] = icmp ult i32 [[A]], [[B]]
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %A = sdiv exact i32 10, %Z
+  %B = sdiv exact i32 20, %Z
+  %C = icmp ult i32 %A, %B
+  ret i1 %C
+}
+
+define i1 @udiv3(i32 %X, i32 %Y) {
+; CHECK-LABEL: @udiv3(
+; CHECK-NEXT:    ret i1 false
+;
+  %A = udiv i32 %X, %Y
+  %C = icmp ugt i32 %A, %X
+  ret i1 %C
+}
+
+define i1 @udiv4(i32 %X, i32 %Y) {
+; CHECK-LABEL: @udiv4(
+; CHECK-NEXT:    ret i1 true
+;
+  %A = udiv i32 %X, %Y
+  %C = icmp ule i32 %A, %X
+  ret i1 %C
+}
+
+; PR11340
+define i1 @udiv6(i32 %X) nounwind {
+; CHECK-LABEL: @udiv6(
+; CHECK-NEXT:    [[A:%.*]] = udiv i32 1, [[X:%.*]]
+; CHECK-NEXT:    [[C:%.*]] = icmp eq i32 [[A]], 0
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %A = udiv i32 1, %X
+  %C = icmp eq i32 %A, 0
+  ret i1 %C
+}
+
+define i1 @udiv7(i32 %X, i32 %Y) {
+; CHECK-LABEL: @udiv7(
+; CHECK-NEXT:    ret i1 false
+;
+  %A = udiv i32 %X, %Y
+  %C = icmp ult i32 %X, %A
+  ret i1 %C
+}
+
+define i1 @udiv8(i32 %X, i32 %Y) {
+; CHECK-LABEL: @udiv8(
+; CHECK-NEXT:    ret i1 true
+;
+  %A = udiv i32 %X, %Y
+  %C = icmp uge i32 %X, %A
+  ret i1 %C
+}
+
+define i1 @udiv_nonzero_eq(i32 %x) {
+; CHECK-LABEL: @udiv_nonzero_eq(
+; CHECK-NEXT:    [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0
+; CHECK-NEXT:    call void @llvm.assume(i1 [[X_NE_0]])
+; CHECK-NEXT:    ret i1 false
+;
+  %x_ne_0 = icmp ne i32 %x, 0
+  call void @llvm.assume(i1 %x_ne_0)
+  %lhs = udiv i32 %x, 3
+  %cmp = icmp eq i32 %lhs, %x
+  ret i1 %cmp
+}
+
+define i1 @udiv_nonzero_uge(i32 %x) {
+; CHECK-LABEL: @udiv_nonzero_uge(
+; CHECK-NEXT:    [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0
+; CHECK-NEXT:    call void @llvm.assume(i1 [[X_NE_0]])
+; CHECK-NEXT:    ret i1 false
+;
+  %x_ne_0 = icmp ne i32 %x, 0
+  call void @llvm.assume(i1 %x_ne_0)
+  %lhs = udiv i32 %x, 3
+  %cmp = icmp uge i32 %lhs, %x
+  ret i1 %cmp
+}
+
+define i1 @udiv_nonzero_ne(i32 %x) {
+; CHECK-LABEL: @udiv_nonzero_ne(
+; CHECK-NEXT:    [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0
+; CHECK-NEXT:    call void @llvm.assume(i1 [[X_NE_0]])
+; CHECK-NEXT:    ret i1 true
+;
+  %x_ne_0 = icmp ne i32 %x, 0
+  call void @llvm.assume(i1 %x_ne_0)
+  %lhs = udiv i32 %x, 3
+  %cmp = icmp ne i32 %lhs, %x
+  ret i1 %cmp
+}
+
+define i1 @udiv_nonzero_ult(i32 %x) {
+; CHECK-LABEL: @udiv_nonzero_ult(
+; CHECK-NEXT:    [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0
+; CHECK-NEXT:    call void @llvm.assume(i1 [[X_NE_0]])
+; CHECK-NEXT:    ret i1 true
+;
+  %x_ne_0 = icmp ne i32 %x, 0
+  call void @llvm.assume(i1 %x_ne_0)
+  %lhs = udiv i32 %x, 3
+  %cmp = icmp ult i32 %lhs, %x
+  ret i1 %cmp
+}
+
+; Negative test - unknown divisor
+define i1 @udiv_nonzero_neg_unknown(i32 %x, i32 %c) {
+; CHECK-LABEL: @udiv_nonzero_neg_unknown(
+; CHECK-NEXT:    [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0
+; CHECK-NEXT:    call void @llvm.assume(i1 [[X_NE_0]])
+; CHECK-NEXT:    [[LHS:%.*]] = udiv i32 [[X]], [[C:%.*]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[LHS]], [[X]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %x_ne_0 = icmp ne i32 %x, 0
+  call void @llvm.assume(i1 %x_ne_0)
+  %lhs = udiv i32 %x, %c
+  %cmp = icmp ult i32 %lhs, %x
+  ret i1 %cmp
+}
+
+; Negative test - x may be zero
+define i1 @udiv_nonzero_neg_maybe_zero(i32 %x) {
+; CHECK-LABEL: @udiv_nonzero_neg_maybe_zero(
+; CHECK-NEXT:    [[LHS:%.*]] = udiv i32 [[X:%.*]], 3
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[LHS]], [[X]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %lhs = udiv i32 %x, 3
+  %cmp = icmp ult i32 %lhs, %x
+  ret i1 %cmp
+}
+
+; Negative test - signed pred
+define i1 @udiv_nonzero_neg_signed(i32 %x) {
+; CHECK-LABEL: @udiv_nonzero_neg_signed(
+; CHECK-NEXT:    [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0
+; CHECK-NEXT:    call void @llvm.assume(i1 [[X_NE_0]])
+; CHECK-NEXT:    [[LHS:%.*]] = udiv i32 [[X]], 3
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[LHS]], [[X]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %x_ne_0 = icmp ne i32 %x, 0
+  call void @llvm.assume(i1 %x_ne_0)
+  %lhs = udiv i32 %x, 3
+  %cmp = icmp slt i32 %lhs, %x
+  ret i1 %cmp
+}
+
+; Square of a non-zero number is non-zero if there is no overflow.
+define i1 @mul1(i32 %X) {
+; CHECK-LABEL: @mul1(
+; CHECK-NEXT:    ret i1 false
+;
+  %Y = or i32 %X, 1
+  %M = mul nuw i32 %Y, %Y
+  %C = icmp eq i32 %M, 0
+  ret i1 %C
+}
+
+define i1 @mul1v(<2 x i32> %X) {
+; CHECK-LABEL: @mul1v(
+; CHECK-NEXT:    ret i1 false
+;
+  %Y = or <2 x i32> %X, <i32 1, i32 0>
+  %M = mul nuw <2 x i32> %Y, %Y
+  %E = extractelement <2 x i32> %M, i32 0
+  %C = icmp eq i32 %E, 0
+  ret i1 %C
+}
+
+; Square of a non-zero number is positive if there is no signed overflow.
+define i1 @mul2(i32 %X) {
+; CHECK-LABEL: @mul2(
+; CHECK-NEXT:    ret i1 true
+;
+  %Y = or i32 %X, 1
+  %M = mul nsw i32 %Y, %Y
+  %C = icmp sgt i32 %M, 0
+  ret i1 %C
+}
+
+define i1 @mul2v(<2 x i32> %X) {
+; CHECK-LABEL: @mul2v(
+; CHECK-NEXT:    ret i1 true
+;
+  %Y = or <2 x i32> %X, <i32 0, i32 1>
+  %M = mul nsw <2 x i32> %Y, %Y
+  %E = extractelement <2 x i32> %M, i32 1
+  %C = icmp sgt i32 %E, 0
+  ret i1 %C
+}
+
+; Product of non-negative numbers is non-negative if there is no signed overflow.
+define i1 @mul3(i32 %X, i32 %Y) {
+; CHECK-LABEL: @mul3(
+; CHECK-NEXT:    ret i1 true
+;
+  %XX = mul nsw i32 %X, %X
+  %YY = mul nsw i32 %Y, %Y
+  %M = mul nsw i32 %XX, %YY
+  %C = icmp sge i32 %M, 0
+  ret i1 %C
+}
+
+define <2 x i1> @mul3v(<2 x i32> %X, <2 x i32> %Y) {
+; CHECK-LABEL: @mul3v(
+; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
+;
+  %XX = mul nsw <2 x i32> %X, %X
+  %YY = mul nsw <2 x i32> %Y, %Y
+  %M = mul nsw <2 x i32> %XX, %YY
+  %C = icmp sge <2 x i32> %M, zeroinitializer
+  ret <2 x i1> %C
+}
+
+define <2 x i1> @vectorselect1(<2 x i1> %cond) {
+; CHECK-LABEL: @vectorselect1(
+; CHECK-NEXT:    ret <2 x i1> [[COND:%.*]]
+;
+  %invert = xor <2 x i1> %cond, <i1 1, i1 1>
+  %s = select <2 x i1> %invert, <2 x i32> <i32 0, i32 0>, <2 x i32> <i32 1, i32 1>
+  %c = icmp ne <2 x i32> %s, <i32 0, i32 0>
+  ret <2 x i1> %c
+}
+
+; PR11948
+define <2 x i1> @vectorselectcrash(i32 %arg1) {
+; CHECK-LABEL: @vectorselectcrash(
+; CHECK-NEXT:    [[TOBOOL40:%.*]] = icmp ne i32 [[ARG1:%.*]], 0
+; CHECK-NEXT:    [[COND43:%.*]] = select i1 [[TOBOOL40]], <2 x i16> <i16 -5, i16 66>, <2 x i16> <i16 46, i16 1>
+; CHECK-NEXT:    [[CMP45:%.*]] = icmp ugt <2 x i16> [[COND43]], <i16 73, i16 21>
+; CHECK-NEXT:    ret <2 x i1> [[CMP45]]
+;
+  %tobool40 = icmp ne i32 %arg1, 0
+  %cond43 = select i1 %tobool40, <2 x i16> <i16 -5, i16 66>, <2 x i16> <i16 46, i16 1>
+  %cmp45 = icmp ugt <2 x i16> %cond43, <i16 73, i16 21>
+  ret <2 x i1> %cmp45
+}
+
+; PR12013
+define i1 @alloca_compare(i64 %idx) {
+; CHECK-LABEL: @alloca_compare(
+; CHECK-NEXT:    ret i1 false
+;
+  %sv = alloca { i32, i32, [124 x i32] }
+  %1 = getelementptr inbounds { i32, i32, [124 x i32] }, ptr %sv, i32 0, i32 2, i64 %idx
+  %2 = icmp eq ptr %1, null
+  ret i1 %2
+}
+
+define i1 @alloca_compare_no_null_opt(i64 %idx) #0 {
+; CHECK-LABEL: @alloca_compare_no_null_opt(
+; CHECK-NEXT:    ret i1 false
+;
+  %sv = alloca { i32, i32, [124 x i32] }
+  %cmp = getelementptr inbounds { i32, i32, [124 x i32] }, ptr %sv, i32 0, i32 2, i64 %idx
+  %X = icmp eq ptr %cmp, null
+  ret i1 %X
+}
+; PR12075
+define i1 @infinite_gep() {
+; CHECK-LABEL: @infinite_gep(
+; CHECK-NEXT:    ret i1 true
+; CHECK:       unreachableblock:
+; CHECK-NEXT:    [[X:%.*]] = getelementptr i32, ptr [[X]], i32 1
+; CHECK-NEXT:    [[Y:%.*]] = icmp eq ptr [[X]], null
+; CHECK-NEXT:    ret i1 [[Y]]
+;
+  ret i1 1
+
+unreachableblock:
+  %X = getelementptr i32, ptr%X, i32 1
+  %Y = icmp eq ptr %X, null
+  ret i1 %Y
+}
+
+; It's not valid to fold a comparison of an argument with an alloca, even though
+; that's tempting. An argument can't *alias* an alloca, however the aliasing rule
+; relies on restrictions against guessing an object's address and dereferencing.
+; There are no restrictions against guessing an object's address and comparing.
+
+define i1 @alloca_argument_compare(ptr %arg) {
+; CHECK-LABEL: @alloca_argument_compare(
+; CHECK-NEXT:    [[ALLOC:%.*]] = alloca i64, align 8
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[ARG:%.*]], [[ALLOC]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %alloc = alloca i64
+  %cmp = icmp eq ptr %arg, %alloc
+  ret i1 %cmp
+}
+
+; As above, but with the operands reversed.
+
+define i1 @alloca_argument_compare_swapped(ptr %arg) {
+; CHECK-LABEL: @alloca_argument_compare_swapped(
+; CHECK-NEXT:    [[ALLOC:%.*]] = alloca i64, align 8
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[ALLOC]], [[ARG:%.*]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %alloc = alloca i64
+  %cmp = icmp eq ptr %alloc, %arg
+  ret i1 %cmp
+}
+
+; Don't assume that a noalias argument isn't equal to a global variable's
+; address. This is an example where AliasAnalysis' NoAlias concept is
+; different from actual pointer inequality.
+
+ at y = external global i32
+define zeroext i1 @external_compare(ptr noalias %x) {
+; CHECK-LABEL: @external_compare(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[X:%.*]], @y
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %cmp = icmp eq ptr %x, @y
+  ret i1 %cmp
+}
+
+define i1 @alloca_gep(i64 %a, i64 %b) {
+; CHECK-LABEL: @alloca_gep(
+; CHECK-NEXT:    ret i1 false
+;
+; We can prove this GEP is non-null because it is inbounds and the pointer
+; is non-null.
+  %strs = alloca [1000 x [1001 x i8]], align 16
+  %x = getelementptr inbounds [1000 x [1001 x i8]], ptr %strs, i64 0, i64 %a, i64 %b
+  %cmp = icmp eq ptr %x, null
+  ret i1 %cmp
+}
+
+define i1 @alloca_gep_no_null_opt(i64 %a, i64 %b) #0 {
+; CHECK-LABEL: @alloca_gep_no_null_opt(
+; CHECK-NEXT:    ret i1 false
+;
+; We can't prove this GEP is non-null.
+  %strs = alloca [1000 x [1001 x i8]], align 16
+  %x = getelementptr inbounds [1000 x [1001 x i8]], ptr %strs, i64 0, i64 %a, i64 %b
+  %cmp = icmp eq ptr %x, null
+  ret i1 %cmp
+}
+
+define i1 @non_inbounds_gep_compare(ptr %a) {
+; CHECK-LABEL: @non_inbounds_gep_compare(
+; CHECK-NEXT:    ret i1 true
+;
+; Equality compares with non-inbounds GEPs can be folded.
+  %x = getelementptr i64, ptr %a, i64 42
+  %y = getelementptr inbounds i64, ptr %x, i64 -42
+  %z = getelementptr i64, ptr %a, i64 -42
+  %w = getelementptr inbounds i64, ptr %z, i64 42
+  %cmp = icmp eq ptr %y, %w
+  ret i1 %cmp
+}
+
+define i1 @non_inbounds_gep_compare2(ptr %a) {
+; CHECK-LABEL: @non_inbounds_gep_compare2(
+; CHECK-NEXT:    ret i1 true
+;
+; Equality compares with non-inbounds GEPs can be folded.
+  %x = getelementptr i64, ptr %a, i64 4294967297
+  %y = getelementptr i64, ptr %a, i64 1
+  %cmp = icmp eq ptr %y, %y
+  ret i1 %cmp
+}
+
+define i1 @compare_always_true_slt(i16 %a) {
+; CHECK-LABEL: @compare_always_true_slt(
+; CHECK-NEXT:    ret i1 true
+;
+  %t1 = zext i16 %a to i32
+  %t2 = sub i32 0, %t1
+  %t3 = icmp slt i32 %t2, 1
+  ret i1 %t3
+}
+
+define <2 x i1> @compare_always_true_slt_splat(<2 x i16> %a) {
+; CHECK-LABEL: @compare_always_true_slt_splat(
+; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
+;
+  %t1 = zext <2 x i16> %a to <2 x i32>
+  %t2 = sub <2 x i32> zeroinitializer, %t1
+  %t3 = icmp slt <2 x i32> %t2, <i32 1, i32 1>
+  ret <2 x i1> %t3
+}
+
+define i1 @compare_always_true_sle(i16 %a) {
+; CHECK-LABEL: @compare_always_true_sle(
+; CHECK-NEXT:    ret i1 true
+;
+  %t1 = zext i16 %a to i32
+  %t2 = sub i32 0, %t1
+  %t3 = icmp sle i32 %t2, 0
+  ret i1 %t3
+}
+
+define <2 x i1> @compare_always_true_sle_splat(<2 x i16> %a) {
+; CHECK-LABEL: @compare_always_true_sle_splat(
+; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
+;
+  %t1 = zext <2 x i16> %a to <2 x i32>
+  %t2 = sub <2 x i32> zeroinitializer, %t1
+  %t3 = icmp sle <2 x i32> %t2, zeroinitializer
+  ret <2 x i1> %t3
+}
+
+define i1 @compare_always_false_sgt(i16 %a) {
+; CHECK-LABEL: @compare_always_false_sgt(
+; CHECK-NEXT:    ret i1 false
+;
+  %t1 = zext i16 %a to i32
+  %t2 = sub i32 0, %t1
+  %t3 = icmp sgt i32 %t2, 0
+  ret i1 %t3
+}
+
+define <2 x i1> @compare_always_false_sgt_splat(<2 x i16> %a) {
+; CHECK-LABEL: @compare_always_false_sgt_splat(
+; CHECK-NEXT:    ret <2 x i1> zeroinitializer
+;
+  %t1 = zext <2 x i16> %a to <2 x i32>
+  %t2 = sub <2 x i32> zeroinitializer, %t1
+  %t3 = icmp sgt <2 x i32> %t2, zeroinitializer
+  ret <2 x i1> %t3
+}
+
+define i1 @compare_always_false_sge(i16 %a) {
+; CHECK-LABEL: @compare_always_false_sge(
+; CHECK-NEXT:    ret i1 false
+;
+  %t1 = zext i16 %a to i32
+  %t2 = sub i32 0, %t1
+  %t3 = icmp sge i32 %t2, 1
+  ret i1 %t3
+}
+
+define <2 x i1> @compare_always_false_sge_splat(<2 x i16> %a) {
+; CHECK-LABEL: @compare_always_false_sge_splat(
+; CHECK-NEXT:    ret <2 x i1> zeroinitializer
+;
+  %t1 = zext <2 x i16> %a to <2 x i32>
+  %t2 = sub <2 x i32> zeroinitializer, %t1
+  %t3 = icmp sge <2 x i32> %t2, <i32 1, i32 1>
+  ret <2 x i1> %t3
+}
+
+define i1 @compare_always_false_eq(i16 %a) {
+; CHECK-LABEL: @compare_always_false_eq(
+; CHECK-NEXT:    ret i1 false
+;
+  %t1 = zext i16 %a to i32
+  %t2 = sub i32 0, %t1
+  %t3 = icmp eq i32 %t2, 1
+  ret i1 %t3
+}
+
+define <2 x i1> @compare_always_false_eq_splat(<2 x i16> %a) {
+; CHECK-LABEL: @compare_always_false_eq_splat(
+; CHECK-NEXT:    ret <2 x i1> zeroinitializer
+;
+  %t1 = zext <2 x i16> %a to <2 x i32>
+  %t2 = sub <2 x i32> zeroinitializer, %t1
+  %t3 = icmp eq <2 x i32> %t2, <i32 1, i32 1>
+  ret <2 x i1> %t3
+}
+
+define i1 @compare_always_true_ne(i16 %a) {
+; CHECK-LABEL: @compare_always_true_ne(
+; CHECK-NEXT:    ret i1 true
+;
+  %t1 = zext i16 %a to i32
+  %t2 = sub i32 0, %t1
+  %t3 = icmp ne i32 %t2, 1
+  ret i1 %t3
+}
+
+define <2 x i1> @compare_always_true_ne_splat(<2 x i16> %a) {
+; CHECK-LABEL: @compare_always_true_ne_splat(
+; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
+;
+  %t1 = zext <2 x i16> %a to <2 x i32>
+  %t2 = sub <2 x i32> zeroinitializer, %t1
+  %t3 = icmp ne <2 x i32> %t2, <i32 1, i32 1>
+  ret <2 x i1> %t3
+}
+
+define i1 @lshr_ugt_false(i32 %a) {
+; CHECK-LABEL: @lshr_ugt_false(
+; CHECK-NEXT:    ret i1 false
+;
+  %shr = lshr i32 1, %a
+  %cmp = icmp ugt i32 %shr, 1
+  ret i1 %cmp
+}
+
+define i1 @nonnull_arg(ptr nonnull %i) {
+; CHECK-LABEL: @nonnull_arg(
+; CHECK-NEXT:    ret i1 false
+;
+  %cmp = icmp eq ptr %i, null
+  ret i1 %cmp
+}
+
+define i1 @nonnull_arg_no_null_opt(ptr nonnull %i) #0 {
+; CHECK-LABEL: @nonnull_arg_no_null_opt(
+; CHECK-NEXT:    ret i1 false
+;
+  %cmp = icmp eq ptr %i, null
+  ret i1 %cmp
+}
+
+define i1 @nonnull_deref_arg(ptr dereferenceable(4) %i) {
+; CHECK-LABEL: @nonnull_deref_arg(
+; CHECK-NEXT:    ret i1 false
+;
+  %cmp = icmp eq ptr %i, null
+  ret i1 %cmp
+}
+
+define i1 @nonnull_deref_arg_no_null_opt(ptr dereferenceable(4) %i) #0 {
+; CHECK-LABEL: @nonnull_deref_arg_no_null_opt(
+; CHECK-NEXT:    ret i1 false
+;
+  %cmp = icmp eq ptr %i, null
+  ret i1 %cmp
+}
+define i1 @nonnull_deref_as_arg(ptr addrspace(1) dereferenceable(4) %i) {
+; CHECK-LABEL: @nonnull_deref_as_arg(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr addrspace(1) [[I:%.*]], null
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %cmp = icmp eq ptr addrspace(1) %i, null
+  ret i1 %cmp
+}
+
+declare nonnull ptr @returns_nonnull_helper()
+define i1 @returns_nonnull() {
+; CHECK-LABEL: @returns_nonnull(
+; CHECK-NEXT:    [[CALL:%.*]] = call nonnull ptr @returns_nonnull_helper()
+; CHECK-NEXT:    ret i1 false
+;
+  %call = call nonnull ptr @returns_nonnull_helper()
+  %cmp = icmp eq ptr %call, null
+  ret i1 %cmp
+}
+
+declare dereferenceable(4) ptr @returns_nonnull_deref_helper()
+define i1 @returns_nonnull_deref() {
+; CHECK-LABEL: @returns_nonnull_deref(
+; CHECK-NEXT:    [[CALL:%.*]] = call dereferenceable(4) ptr @returns_nonnull_deref_helper()
+; CHECK-NEXT:    ret i1 false
+;
+  %call = call dereferenceable(4) ptr @returns_nonnull_deref_helper()
+  %cmp = icmp eq ptr %call, null
+  ret i1 %cmp
+}
+
+define i1 @returns_nonnull_deref_no_null_opt () #0 {
+; CHECK-LABEL: @returns_nonnull_deref_no_null_opt(
+; CHECK-NEXT:    [[CALL:%.*]] = call dereferenceable(4) ptr @returns_nonnull_deref_helper()
+; CHECK-NEXT:    ret i1 false
+;
+  %call = call dereferenceable(4) ptr @returns_nonnull_deref_helper()
+  %cmp = icmp eq ptr %call, null
+  ret i1 %cmp
+}
+
+declare dereferenceable(4) ptr addrspace(1) @returns_nonnull_deref_as_helper()
+define i1 @returns_nonnull_as_deref() {
+; CHECK-LABEL: @returns_nonnull_as_deref(
+; CHECK-NEXT:    [[CALL:%.*]] = call dereferenceable(4) ptr addrspace(1) @returns_nonnull_deref_as_helper()
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr addrspace(1) [[CALL]], null
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %call = call dereferenceable(4) ptr addrspace(1) @returns_nonnull_deref_as_helper()
+  %cmp = icmp eq ptr addrspace(1) %call, null
+  ret i1 %cmp
+}
+
+define i1 @nonnull_load(ptr %addr) {
+; CHECK-LABEL: @nonnull_load(
+; CHECK-NEXT:    ret i1 false
+;
+  %ptr = load ptr, ptr %addr, !nonnull !{}
+  %cmp = icmp eq ptr %ptr, null
+  ret i1 %cmp
+}
+
+define i1 @nonnull_load_as_outer(ptr addrspace(1) %addr) {
+; CHECK-LABEL: @nonnull_load_as_outer(
+; CHECK-NEXT:    ret i1 false
+;
+  %ptr = load ptr, ptr addrspace(1) %addr, !nonnull !{}
+  %cmp = icmp eq ptr %ptr, null
+  ret i1 %cmp
+}
+define i1 @nonnull_load_as_inner(ptr %addr) {
+; CHECK-LABEL: @nonnull_load_as_inner(
+; CHECK-NEXT:    [[PTR:%.*]] = load ptr addrspace(1), ptr [[ADDR:%.*]], align 8, !nonnull [[META0:![0-9]+]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr addrspace(1) [[PTR]], null
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %ptr = load ptr addrspace(1), ptr %addr, !nonnull !{}
+  %cmp = icmp eq ptr addrspace(1) %ptr, null
+  ret i1 %cmp
+}
+
+; If a bit is known to be zero for A and known to be one for B,
+; then A and B cannot be equal.
+define i1 @icmp_eq_const(i32 %a) {
+; CHECK-LABEL: @icmp_eq_const(
+; CHECK-NEXT:    ret i1 false
+;
+  %b = mul nsw i32 %a, -2
+  %c = icmp eq i32 %b, 1
+  ret i1 %c
+}
+
+define <2 x i1> @icmp_eq_const_vec(<2 x i32> %a) {
+; CHECK-LABEL: @icmp_eq_const_vec(
+; CHECK-NEXT:    ret <2 x i1> zeroinitializer
+;
+  %b = mul nsw <2 x i32> %a, <i32 -2, i32 -2>
+  %c = icmp eq <2 x i32> %b, <i32 1, i32 1>
+  ret <2 x i1> %c
+}
+
+define i1 @icmp_ne_const(i32 %a) {
+; CHECK-LABEL: @icmp_ne_const(
+; CHECK-NEXT:    ret i1 true
+;
+  %b = mul nsw i32 %a, -2
+  %c = icmp ne i32 %b, 1
+  ret i1 %c
+}
+
+define <2 x i1> @icmp_ne_const_vec(<2 x i32> %a) {
+; CHECK-LABEL: @icmp_ne_const_vec(
+; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
+;
+  %b = mul nsw <2 x i32> %a, <i32 -2, i32 -2>
+  %c = icmp ne <2 x i32> %b, <i32 1, i32 1>
+  ret <2 x i1> %c
+}
+
+define i1 @icmp_sdiv_int_min(i32 %a) {
+; CHECK-LABEL: @icmp_sdiv_int_min(
+; CHECK-NEXT:    [[DIV:%.*]] = sdiv i32 -2147483648, [[A:%.*]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[DIV]], -1073741824
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %div = sdiv i32 -2147483648, %a
+  %cmp = icmp ne i32 %div, -1073741824
+  ret i1 %cmp
+
+}
+
+define i1 @icmp_sdiv_pr20288(i64 %a) {
+; CHECK-LABEL: @icmp_sdiv_pr20288(
+; CHECK-NEXT:    [[DIV:%.*]] = sdiv i64 [[A:%.*]], -8589934592
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i64 [[DIV]], 1073741824
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %div = sdiv i64 %a, -8589934592
+  %cmp = icmp ne i64 %div, 1073741824
+  ret i1 %cmp
+
+}
+
+define i1 @icmp_sdiv_neg1(i64 %a) {
+; CHECK-LABEL: @icmp_sdiv_neg1(
+; CHECK-NEXT:    [[DIV:%.*]] = sdiv i64 [[A:%.*]], -1
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i64 [[DIV]], 1073741824
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %div = sdiv i64 %a, -1
+  %cmp = icmp ne i64 %div, 1073741824
+  ret i1 %cmp
+
+}
+
+define i1 @icmp_known_bits(i4 %x, i4 %y) {
+; CHECK-LABEL: @icmp_known_bits(
+; CHECK-NEXT:    ret i1 false
+;
+  %and1 = and i4 %y, -7
+  %and2 = and i4 %x, -7
+  %or1 = or i4 %and1, 2
+  %or2 = or i4 %and2, 2
+  %add = add i4 %or1, %or2
+  %cmp = icmp eq i4 %add, 0
+  ret i1 %cmp
+}
+
+define i1 @icmp_known_bits_vec(<2 x i4> %x, <2 x i4> %y) {
+; CHECK-LABEL: @icmp_known_bits_vec(
+; CHECK-NEXT:    ret i1 false
+;
+  %and1 = and <2 x i4> %y, <i4 -7, i4 -1>
+  %and2 = and <2 x i4> %x, <i4 -7, i4 -1>
+  %or1 = or <2 x i4> %and1, <i4 2, i4 2>
+  %or2 = or <2 x i4> %and2, <i4 2, i4 2>
+  %add = add <2 x i4> %or1, %or2
+  %ext = extractelement <2 x i4> %add,i32 0
+  %cmp = icmp eq i4 %ext, 0
+  ret i1 %cmp
+}
+
+define i1 @icmp_shl_nuw_1(i64 %a) {
+; CHECK-LABEL: @icmp_shl_nuw_1(
+; CHECK-NEXT:    ret i1 true
+;
+  %shl = shl nuw i64 1, %a
+  %cmp = icmp ne i64 %shl, 0
+  ret i1 %cmp
+}
+
+define i1 @icmp_shl_1_V_ugt_2147483648(i32 %V) {
+; CHECK-LABEL: @icmp_shl_1_V_ugt_2147483648(
+; CHECK-NEXT:    ret i1 false
+;
+  %shl = shl i32 1, %V
+  %cmp = icmp ugt i32 %shl, 2147483648
+  ret i1 %cmp
+}
+
+define <2 x i1> @icmp_shl_1_ugt_signmask(<2 x i8> %V) {
+; CHECK-LABEL: @icmp_shl_1_ugt_signmask(
+; CHECK-NEXT:    ret <2 x i1> zeroinitializer
+;
+  %shl = shl <2 x i8> <i8 1, i8 1>, %V
+  %cmp = icmp ugt <2 x i8> %shl, <i8 128, i8 128>
+  ret <2 x i1> %cmp
+}
+
+define <2 x i1> @icmp_shl_1_ugt_signmask_undef(<2 x i8> %V) {
+; CHECK-LABEL: @icmp_shl_1_ugt_signmask_undef(
+; CHECK-NEXT:    [[SHL:%.*]] = shl <2 x i8> <i8 1, i8 1>, [[V:%.*]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt <2 x i8> [[SHL]], <i8 -128, i8 undef>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %shl = shl <2 x i8> <i8 1, i8 1>, %V
+  %cmp = icmp ugt <2 x i8> %shl, <i8 128, i8 undef>
+  ret <2 x i1> %cmp
+}
+
+define <2 x i1> @icmp_shl_1_ugt_signmask_undef2(<2 x i8> %V) {
+; CHECK-LABEL: @icmp_shl_1_ugt_signmask_undef2(
+; CHECK-NEXT:    [[SHL:%.*]] = shl <2 x i8> <i8 1, i8 undef>, [[V:%.*]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt <2 x i8> [[SHL]], <i8 undef, i8 -128>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %shl = shl <2 x i8> <i8 1, i8 undef>, %V
+  %cmp = icmp ugt <2 x i8> %shl, <i8 undef, i8 128>
+  ret <2 x i1> %cmp
+}
+
+define i1 @icmp_shl_1_V_ule_2147483648(i32 %V) {
+; CHECK-LABEL: @icmp_shl_1_V_ule_2147483648(
+; CHECK-NEXT:    ret i1 true
+;
+  %shl = shl i32 1, %V
+  %cmp = icmp ule i32 %shl, 2147483648
+  ret i1 %cmp
+}
+
+define <2 x i1> @icmp_shl_1_ule_signmask(<2 x i8> %V) {
+; CHECK-LABEL: @icmp_shl_1_ule_signmask(
+; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
+;
+  %shl = shl <2 x i8> <i8 1, i8 1>, %V
+  %cmp = icmp ule <2 x i8> %shl, <i8 128, i8 128>
+  ret <2 x i1> %cmp
+}
+
+define <2 x i1> @icmp_shl_1_ule_signmask_undef(<2 x i8> %V) {
+; CHECK-LABEL: @icmp_shl_1_ule_signmask_undef(
+; CHECK-NEXT:    [[SHL:%.*]] = shl <2 x i8> <i8 1, i8 1>, [[V:%.*]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ule <2 x i8> [[SHL]], <i8 -128, i8 undef>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %shl = shl <2 x i8> <i8 1, i8 1>, %V
+  %cmp = icmp ule <2 x i8> %shl, <i8 128, i8 undef>
+  ret <2 x i1> %cmp
+}
+
+define <2 x i1> @icmp_shl_1_ule_signmask_undef2(<2 x i8> %V) {
+; CHECK-LABEL: @icmp_shl_1_ule_signmask_undef2(
+; CHECK-NEXT:    [[SHL:%.*]] = shl <2 x i8> <i8 1, i8 undef>, [[V:%.*]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ule <2 x i8> [[SHL]], <i8 undef, i8 -128>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %shl = shl <2 x i8> <i8 1, i8 undef>, %V
+  %cmp = icmp ule <2 x i8> %shl, <i8 undef, i8 128>
+  ret <2 x i1> %cmp
+}
+
+define i1 @shl_1_cmp_eq_nonpow2(i32 %x) {
+; CHECK-LABEL: @shl_1_cmp_eq_nonpow2(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = shl i32 1, %x
+  %c = icmp eq i32 %s, 31
+  ret i1 %c
+}
+
+define <2 x i1> @shl_1_cmp_eq_nonpow2_splat(<2 x i32> %x) {
+; CHECK-LABEL: @shl_1_cmp_eq_nonpow2_splat(
+; CHECK-NEXT:    ret <2 x i1> zeroinitializer
+;
+  %s = shl <2 x i32> <i32 1, i32 1>, %x
+  %c = icmp eq <2 x i32> %s, <i32 31, i32 31>
+  ret <2 x i1> %c
+}
+
+define <2 x i1> @shl_1_cmp_eq_nonpow2_splat_undef(<2 x i32> %x) {
+; CHECK-LABEL: @shl_1_cmp_eq_nonpow2_splat_undef(
+; CHECK-NEXT:    [[S:%.*]] = shl <2 x i32> <i32 1, i32 1>, [[X:%.*]]
+; CHECK-NEXT:    [[C:%.*]] = icmp eq <2 x i32> [[S]], <i32 31, i32 undef>
+; CHECK-NEXT:    ret <2 x i1> [[C]]
+;
+  %s = shl <2 x i32> <i32 1, i32 1>, %x
+  %c = icmp eq <2 x i32> %s, <i32 31, i32 undef>
+  ret <2 x i1> %c
+}
+
+define i1 @shl_1_cmp_ne_nonpow2(i32 %x) {
+; CHECK-LABEL: @shl_1_cmp_ne_nonpow2(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = shl i32 1, %x
+  %c = icmp ne i32 %s, 42
+  ret i1 %c
+}
+
+define <2 x i1> @shl_1_cmp_ne_nonpow2_splat(<2 x i32> %x) {
+; CHECK-LABEL: @shl_1_cmp_ne_nonpow2_splat(
+; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
+;
+  %s = shl <2 x i32> <i32 1, i32 1>, %x
+  %c = icmp ne <2 x i32> %s, <i32 42, i32 42>
+  ret <2 x i1> %c
+}
+
+define <2 x i1> @shl_1_cmp_ne_nonpow2_splat_undef(<2 x i32> %x) {
+; CHECK-LABEL: @shl_1_cmp_ne_nonpow2_splat_undef(
+; CHECK-NEXT:    [[S:%.*]] = shl <2 x i32> <i32 undef, i32 1>, [[X:%.*]]
+; CHECK-NEXT:    [[C:%.*]] = icmp ne <2 x i32> [[S]], <i32 42, i32 undef>
+; CHECK-NEXT:    ret <2 x i1> [[C]]
+;
+  %s = shl <2 x i32> <i32 undef, i32 1>, %x
+  %c = icmp ne <2 x i32> %s, <i32 42, i32 undef>
+  ret <2 x i1> %c
+}
+
+define i1 @shl_pow2_cmp_eq_nonpow2(i32 %x) {
+; CHECK-LABEL: @shl_pow2_cmp_eq_nonpow2(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = shl i32 4, %x
+  %c = icmp eq i32 %s, 31
+  ret i1 %c
+}
+
+define <2 x i1> @shl_pow21_cmp_ne_nonpow2_splat_undef(<2 x i32> %x) {
+; CHECK-LABEL: @shl_pow21_cmp_ne_nonpow2_splat_undef(
+; CHECK-NEXT:    [[S:%.*]] = shl <2 x i32> <i32 undef, i32 4>, [[X:%.*]]
+; CHECK-NEXT:    [[C:%.*]] = icmp ne <2 x i32> [[S]], <i32 31, i32 undef>
+; CHECK-NEXT:    ret <2 x i1> [[C]]
+;
+  %s = shl <2 x i32> <i32 undef, i32 4>, %x
+  %c = icmp ne <2 x i32> %s, <i32 31, i32 undef>
+  ret <2 x i1> %c
+}
+
+; Negative test - overflowing shift could be zero.
+
+define i1 @shl_pow2_cmp_ne_zero(i32 %x) {
+; CHECK-LABEL: @shl_pow2_cmp_ne_zero(
+; CHECK-NEXT:    [[S:%.*]] = shl i32 16, [[X:%.*]]
+; CHECK-NEXT:    [[C:%.*]] = icmp ne i32 [[S]], 0
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %s = shl i32 16, %x
+  %c = icmp ne i32 %s, 0
+  ret i1 %c
+}
+
+; Negative test - overflowing shift could be zero.
+
+define <2 x i1> @shl_pow2_cmp_ne_zero_splat(<2 x i32> %x) {
+; CHECK-LABEL: @shl_pow2_cmp_ne_zero_splat(
+; CHECK-NEXT:    [[S:%.*]] = shl <2 x i32> <i32 16, i32 16>, [[X:%.*]]
+; CHECK-NEXT:    [[C:%.*]] = icmp ne <2 x i32> [[S]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[C]]
+;
+  %s = shl <2 x i32> <i32 16, i32 16>, %x
+  %c = icmp ne <2 x i32> %s, zeroinitializer
+  ret <2 x i1> %c
+}
+
+define i1 @shl_pow2_cmp_eq_zero_nuw(i32 %x) {
+; CHECK-LABEL: @shl_pow2_cmp_eq_zero_nuw(
+; CHECK-NEXT:    ret i1 false
+;
+  %s = shl nuw i32 16, %x
+  %c = icmp eq i32 %s, 0
+  ret i1 %c
+}
+
+define <2 x i1> @shl_pow2_cmp_ne_zero_nuw_splat_undef(<2 x i32> %x) {
+; CHECK-LABEL: @shl_pow2_cmp_ne_zero_nuw_splat_undef(
+; CHECK-NEXT:    [[S:%.*]] = shl nuw <2 x i32> <i32 16, i32 undef>, [[X:%.*]]
+; CHECK-NEXT:    [[C:%.*]] = icmp ne <2 x i32> [[S]], <i32 undef, i32 0>
+; CHECK-NEXT:    ret <2 x i1> [[C]]
+;
+  %s = shl nuw <2 x i32> <i32 16, i32 undef>, %x
+  %c = icmp ne <2 x i32> %s, <i32 undef, i32 0>
+  ret <2 x i1> %c
+}
+
+define i1 @shl_pow2_cmp_ne_zero_nsw(i32 %x) {
+; CHECK-LABEL: @shl_pow2_cmp_ne_zero_nsw(
+; CHECK-NEXT:    ret i1 true
+;
+  %s = shl nsw i32 16, %x
+  %c = icmp ne i32 %s, 0
+  ret i1 %c
+}
+
+define <2 x i1> @shl_pow2_cmp_eq_zero_nsw_splat_undef(<2 x i32> %x) {
+; CHECK-LABEL: @shl_pow2_cmp_eq_zero_nsw_splat_undef(
+; CHECK-NEXT:    [[S:%.*]] = shl nsw <2 x i32> <i32 undef, i32 16>, [[X:%.*]]
+; CHECK-NEXT:    [[C:%.*]] = icmp eq <2 x i32> [[S]], <i32 0, i32 undef>
+; CHECK-NEXT:    ret <2 x i1> [[C]]
+;
+  %s = shl nsw <2 x i32> <i32 undef, i32 16>, %x
+  %c = icmp eq <2 x i32> %s, <i32 0, i32 undef>
+  ret <2 x i1> %c
+}
+
+define i1 @tautological1(i32 %A, i32 %B) {
+; CHECK-LABEL: @tautological1(
+; CHECK-NEXT:    ret i1 false
+;
+  %C = and i32 %A, %B
+  %D = icmp ugt i32 %C, %A
+  ret i1 %D
+}
+
+define i1 @tautological2(i32 %A, i32 %B) {
+; CHECK-LABEL: @tautological2(
+; CHECK-NEXT:    ret i1 true
+;
+  %C = and i32 %A, %B
+  %D = icmp ule i32 %C, %A
+  ret i1 %D
+}
+
+define i1 @tautological3(i32 %A, i32 %B) {
+; CHECK-LABEL: @tautological3(
+; CHECK-NEXT:    ret i1 true
+;
+  %C = or i32 %A, %B
+  %D = icmp ule i32 %A, %C
+  ret i1 %D
+}
+
+define i1 @tautological4(i32 %A, i32 %B) {
+; CHECK-LABEL: @tautological4(
+; CHECK-NEXT:    ret i1 false
+;
+  %C = or i32 %A, %B
+  %D = icmp ugt i32 %A, %C
+  ret i1 %D
+}
+
+define i1 @tautological5(i32 %A, i32 %B) {
+; CHECK-LABEL: @tautological5(
+; CHECK-NEXT:    ret i1 false
+;
+  %C = or i32 %A, %B
+  %D = icmp ult i32 %C, %A
+  ret i1 %D
+}
+
+define i1 @tautological6(i32 %A, i32 %B) {
+; CHECK-LABEL: @tautological6(
+; CHECK-NEXT:    ret i1 true
+;
+  %C = or i32 %A, %B
+  %D = icmp uge i32 %C, %A
+  ret i1 %D
+}
+
+define i1 @tautological7(i32 %A, i32 %B) {
+; CHECK-LABEL: @tautological7(
+; CHECK-NEXT:    ret i1 true
+;
+  %C = and i32 %A, %B
+  %D = icmp uge i32 %A, %C
+  ret i1 %D
+}
+
+define i1 @tautological8(i32 %A, i32 %B) {
+; CHECK-LABEL: @tautological8(
+; CHECK-NEXT:    ret i1 false
+;
+  %C = and i32 %A, %B
+  %D = icmp ult i32 %A, %C
+  ret i1 %D
+}
+
+define i1 @tautological9(i32 %A) {
+; CHECK-LABEL: @tautological9(
+; CHECK-NEXT:    ret i1 false
+;
+  %C1 = and i32 %A, 1
+  %C2 = and i32 %A, 3
+  %D = icmp ugt i32 %C1, %C2
+  ret i1 %D
+}
+
+define <2 x i1> @tautological9_vec(<2 x i32> %A) {
+; CHECK-LABEL: @tautological9_vec(
+; CHECK-NEXT:    ret <2 x i1> zeroinitializer
+;
+  %C1 = and <2 x i32> %A, <i32 1, i32 1>
+  %C2 = and <2 x i32> %A, <i32 3, i32 3>
+  %D = icmp ugt <2 x i32> %C1, %C2
+  ret <2 x i1> %D
+}
+
+define i1 @tautological10(i32 %A) {
+; CHECK-LABEL: @tautological10(
+; CHECK-NEXT:    ret i1 true
+;
+  %C1 = and i32 %A, 1
+  %C2 = and i32 %A, 3
+  %D = icmp ule i32 %C1, %C2
+  ret i1 %D
+}
+
+define i1 @tautological11(i32 %A) {
+; CHECK-LABEL: @tautological11(
+; CHECK-NEXT:    ret i1 true
+;
+  %C1 = or i32 %A, 1
+  %C2 = or i32 %A, 3
+  %D = icmp ule i32 %C1, %C2
+  ret i1 %D
+}
+
+define i1 @tautological12(i32 %A) {
+; CHECK-LABEL: @tautological12(
+; CHECK-NEXT:    ret i1 false
+;
+  %C1 = or i32 %A, 1
+  %C2 = or i32 %A, 3
+  %D = icmp ugt i32 %C1, %C2
+  ret i1 %D
+}
+
+define i1 @tautological13(i32 %A) {
+; CHECK-LABEL: @tautological13(
+; CHECK-NEXT:    ret i1 false
+;
+  %C1 = or i32 %A, 1
+  %C2 = or i32 %A, 3
+  %D = icmp ult i32 %C2, %C1
+  ret i1 %D
+}
+
+define i1 @tautological14(i32 %A) {
+; CHECK-LABEL: @tautological14(
+; CHECK-NEXT:    ret i1 true
+;
+  %C1 = or i32 %A, 1
+  %C2 = or i32 %A, 3
+  %D = icmp uge i32 %C2, %C1
+  ret i1 %D
+}
+
+define i1 @tautological15(i32 %A) {
+; CHECK-LABEL: @tautological15(
+; CHECK-NEXT:    ret i1 true
+;
+  %C1 = and i32 %A, 1
+  %C2 = and i32 %A, 3
+  %D = icmp uge i32 %C2, %C1
+  ret i1 %D
+}
+
+define i1 @tautological16(i32 %A) {
+; CHECK-LABEL: @tautological16(
+; CHECK-NEXT:    ret i1 false
+;
+  %C1 = and i32 %A, 1
+  %C2 = and i32 %A, 3
+  %D = icmp ult i32 %C2, %C1
+  ret i1 %D
+}
+
+define i1 @tautological9_negative(i32 %A) {
+; CHECK-LABEL: @tautological9_negative(
+; CHECK-NEXT:    [[C1:%.*]] = and i32 [[A:%.*]], 1
+; CHECK-NEXT:    [[C2:%.*]] = and i32 [[A]], 2
+; CHECK-NEXT:    [[D:%.*]] = icmp ugt i32 [[C1]], [[C2]]
+; CHECK-NEXT:    ret i1 [[D]]
+;
+  %C1 = and i32 %A, 1
+  %C2 = and i32 %A, 2
+  %D = icmp ugt i32 %C1, %C2
+  ret i1 %D
+}
+
+define i1 @tautological10_negative(i32 %A) {
+; CHECK-LABEL: @tautological10_negative(
+; CHECK-NEXT:    [[C1:%.*]] = and i32 [[A:%.*]], 1
+; CHECK-NEXT:    [[C2:%.*]] = and i32 [[A]], 2
+; CHECK-NEXT:    [[D:%.*]] = icmp ule i32 [[C1]], [[C2]]
+; CHECK-NEXT:    ret i1 [[D]]
+;
+  %C1 = and i32 %A, 1
+  %C2 = and i32 %A, 2
+  %D = icmp ule i32 %C1, %C2
+  ret i1 %D
+}
+
+define i1 @tautological11_negative(i32 %A) {
+; CHECK-LABEL: @tautological11_negative(
+; CHECK-NEXT:    [[C1:%.*]] = or i32 [[A:%.*]], 1
+; CHECK-NEXT:    [[C2:%.*]] = or i32 [[A]], 2
+; CHECK-NEXT:    [[D:%.*]] = icmp ule i32 [[C1]], [[C2]]
+; CHECK-NEXT:    ret i1 [[D]]
+;
+  %C1 = or i32 %A, 1
+  %C2 = or i32 %A, 2
+  %D = icmp ule i32 %C1, %C2
+  ret i1 %D
+}
+
+define i1 @tautological12_negative(i32 %A) {
+; CHECK-LABEL: @tautological12_negative(
+; CHECK-NEXT:    [[C1:%.*]] = or i32 [[A:%.*]], 1
+; CHECK-NEXT:    [[C2:%.*]] = or i32 [[A]], 2
+; CHECK-NEXT:    [[D:%.*]] = icmp ugt i32 [[C1]], [[C2]]
+; CHECK-NEXT:    ret i1 [[D]]
+;
+  %C1 = or i32 %A, 1
+  %C2 = or i32 %A, 2
+  %D = icmp ugt i32 %C1, %C2
+  ret i1 %D
+}
+
+define i1 @tautological13_negative(i32 %A) {
+; CHECK-LABEL: @tautological13_negative(
+; CHECK-NEXT:    [[C1:%.*]] = or i32 [[A:%.*]], 1
+; CHECK-NEXT:    [[C2:%.*]] = or i32 [[A]], 2
+; CHECK-NEXT:    [[D:%.*]] = icmp ult i32 [[C2]], [[C1]]
+; CHECK-NEXT:    ret i1 [[D]]
+;
+  %C1 = or i32 %A, 1
+  %C2 = or i32 %A, 2
+  %D = icmp ult i32 %C2, %C1
+  ret i1 %D
+}
+
+define i1 @tautological14_negative(i32 %A) {
+; CHECK-LABEL: @tautological14_negative(
+; CHECK-NEXT:    [[C1:%.*]] = or i32 [[A:%.*]], 1
+; CHECK-NEXT:    [[C2:%.*]] = or i32 [[A]], 2
+; CHECK-NEXT:    [[D:%.*]] = icmp uge i32 [[C2]], [[C1]]
+; CHECK-NEXT:    ret i1 [[D]]
+;
+  %C1 = or i32 %A, 1
+  %C2 = or i32 %A, 2
+  %D = icmp uge i32 %C2, %C1
+  ret i1 %D
+}
+
+define i1 @tautological15_negative(i32 %A) {
+; CHECK-LABEL: @tautological15_negative(
+; CHECK-NEXT:    [[C1:%.*]] = and i32 [[A:%.*]], 1
+; CHECK-NEXT:    [[C2:%.*]] = and i32 [[A]], 2
+; CHECK-NEXT:    [[D:%.*]] = icmp uge i32 [[C2]], [[C1]]
+; CHECK-NEXT:    ret i1 [[D]]
+;
+  %C1 = and i32 %A, 1
+  %C2 = and i32 %A, 2
+  %D = icmp uge i32 %C2, %C1
+  ret i1 %D
+}
+
+define i1 @tautological16_negative(i32 %A) {
+; CHECK-LABEL: @tautological16_negative(
+; CHECK-NEXT:    [[C1:%.*]] = and i32 [[A:%.*]], 1
+; CHECK-NEXT:    [[C2:%.*]] = and i32 [[A]], 2
+; CHECK-NEXT:    [[D:%.*]] = icmp ult i32 [[C2]], [[C1]]
+; CHECK-NEXT:    ret i1 [[D]]
+;
+  %C1 = and i32 %A, 1
+  %C2 = and i32 %A, 2
+  %D = icmp ult i32 %C2, %C1
+  ret i1 %D
+}
+
+define i1 @tautological17_subset1(i32 %A) {
+; CHECK-LABEL: @tautological17_subset1(
+; CHECK-NEXT:    ret i1 false
+;
+  %C1 = and i32 %A, 1
+  %C2 = and i32 %A, 3
+  %D = icmp sgt i32 %C1, %C2
+  ret i1 %D
+}
+
+define i1 @tautological17_subset2(i32 %A) {
+; CHECK-LABEL: @tautological17_subset2(
+; CHECK-NEXT:    ret i1 false
+;
+  %C1 = and i32 %A, -4
+  %C2 = and i32 %A, -3
+  %D = icmp sgt i32 %C1, %C2
+  ret i1 %D
+}
+
+define i1 @tautological17_negative(i32 %A) {
+; CHECK-LABEL: @tautological17_negative(
+; CHECK-NEXT:    [[C1:%.*]] = and i32 [[A:%.*]], 1
+; CHECK-NEXT:    [[C2:%.*]] = and i32 [[A]], -3
+; CHECK-NEXT:    [[D:%.*]] = icmp sgt i32 [[C1]], [[C2]]
+; CHECK-NEXT:    ret i1 [[D]]
+;
+  %C1 = and i32 %A, 1
+  %C2 = and i32 %A, -3
+  %D = icmp sgt i32 %C1, %C2
+  ret i1 %D
+}
+
+define i1 @tautological18_subset1(i32 %A) {
+; CHECK-LABEL: @tautological18_subset1(
+; CHECK-NEXT:    ret i1 true
+;
+  %C1 = and i32 %A, 1
+  %C2 = and i32 %A, 3
+  %D = icmp sle i32 %C1, %C2
+  ret i1 %D
+}
+
+define i1 @tautological18_subset2(i32 %A) {
+; CHECK-LABEL: @tautological18_subset2(
+; CHECK-NEXT:    ret i1 true
+;
+  %C1 = and i32 %A, -4
+  %C2 = and i32 %A, -3
+  %D = icmp sle i32 %C1, %C2
+  ret i1 %D
+}
+
+define i1 @tautological18_negative(i32 %A) {
+; CHECK-LABEL: @tautological18_negative(
+; CHECK-NEXT:    [[C1:%.*]] = and i32 [[A:%.*]], 1
+; CHECK-NEXT:    [[C2:%.*]] = and i32 [[A]], -3
+; CHECK-NEXT:    [[D:%.*]] = icmp sle i32 [[C1]], [[C2]]
+; CHECK-NEXT:    ret i1 [[D]]
+;
+  %C1 = and i32 %A, 1
+  %C2 = and i32 %A, -3
+  %D = icmp sle i32 %C1, %C2
+  ret i1 %D
+}
+
+define i1 @tautological19_subset1(i32 %A) {
+; CHECK-LABEL: @tautological19_subset1(
+; CHECK-NEXT:    ret i1 false
+;
+  %C1 = or i32 %A, 1
+  %C2 = or i32 %A, 3
+  %D = icmp sgt i32 %C1, %C2
+  ret i1 %D
+}
+
+define i1 @tautological19_subset2(i32 %A) {
+; CHECK-LABEL: @tautological19_subset2(
+; CHECK-NEXT:    ret i1 false
+;
+  %C1 = and i32 %A, -4
+  %C2 = and i32 %A, -3
+  %D = icmp sgt i32 %C1, %C2
+  ret i1 %D
+}
+
+define i1 @tautological19_negative(i32 %A) {
+; CHECK-LABEL: @tautological19_negative(
+; CHECK-NEXT:    [[C1:%.*]] = and i32 [[A:%.*]], 1
+; CHECK-NEXT:    [[C2:%.*]] = and i32 [[A]], -3
+; CHECK-NEXT:    [[D:%.*]] = icmp sgt i32 [[C1]], [[C2]]
+; CHECK-NEXT:    ret i1 [[D]]
+;
+  %C1 = and i32 %A, 1
+  %C2 = and i32 %A, -3
+  %D = icmp sgt i32 %C1, %C2
+  ret i1 %D
+}
+
+define i1 @tautological20_subset1(i32 %A) {
+; CHECK-LABEL: @tautological20_subset1(
+; CHECK-NEXT:    ret i1 true
+;
+  %C1 = and i32 %A, 1
+  %C2 = and i32 %A, 3
+  %D = icmp sle i32 %C1, %C2
+  ret i1 %D
+}
+
+define i1 @tautological20_subset2(i32 %A) {
+; CHECK-LABEL: @tautological20_subset2(
+; CHECK-NEXT:    ret i1 true
+;
+  %C1 = and i32 %A, -4
+  %C2 = and i32 %A, -3
+  %D = icmp sle i32 %C1, %C2
+  ret i1 %D
+}
+
+define i1 @tautological20_negative(i32 %A) {
+; CHECK-LABEL: @tautological20_negative(
+; CHECK-NEXT:    [[C1:%.*]] = and i32 [[A:%.*]], 1
+; CHECK-NEXT:    [[C2:%.*]] = and i32 [[A]], -3
+; CHECK-NEXT:    [[D:%.*]] = icmp sle i32 [[C1]], [[C2]]
+; CHECK-NEXT:    ret i1 [[D]]
+;
+  %C1 = and i32 %A, 1
+  %C2 = and i32 %A, -3
+  %D = icmp sle i32 %C1, %C2
+  ret i1 %D
+}
+
+declare void @helper_i1(i1)
+; Series of tests for icmp s[lt|ge] (or A, B), A and icmp s[gt|le] A, (or A, B)
+define void @icmp_slt_sge_or(i32 %Ax, i32 %Bx) {
+; 'p' for positive, 'n' for negative, 'x' for potentially either.
+; %D is 'icmp slt (or A, B), A'
+; %E is 'icmp sge (or A, B), A' making it the not of %D
+; %F is 'icmp sgt A, (or A, B)' making it the same as %D
+; %G is 'icmp sle A, (or A, B)' making it the not of %D
+; CHECK-LABEL: @icmp_slt_sge_or(
+; CHECK-NEXT:    [[APOS:%.*]] = and i32 [[AX:%.*]], 2147483647
+; CHECK-NEXT:    [[BNEG:%.*]] = or i32 [[BX:%.*]], -2147483648
+; CHECK-NEXT:    [[CPX:%.*]] = or i32 [[APOS]], [[BX]]
+; CHECK-NEXT:    [[DPX:%.*]] = icmp slt i32 [[CPX]], [[APOS]]
+; CHECK-NEXT:    [[EPX:%.*]] = icmp sge i32 [[CPX]], [[APOS]]
+; CHECK-NEXT:    [[FPX:%.*]] = icmp sgt i32 [[APOS]], [[CPX]]
+; CHECK-NEXT:    [[GPX:%.*]] = icmp sle i32 [[APOS]], [[CPX]]
+; CHECK-NEXT:    [[CXX:%.*]] = or i32 [[AX]], [[BX]]
+; CHECK-NEXT:    [[DXX:%.*]] = icmp slt i32 [[CXX]], [[AX]]
+; CHECK-NEXT:    [[EXX:%.*]] = icmp sge i32 [[CXX]], [[AX]]
+; CHECK-NEXT:    [[FXX:%.*]] = icmp sgt i32 [[AX]], [[CXX]]
+; CHECK-NEXT:    [[GXX:%.*]] = icmp sle i32 [[AX]], [[CXX]]
+; CHECK-NEXT:    [[CXN:%.*]] = or i32 [[AX]], [[BNEG]]
+; CHECK-NEXT:    [[DXN:%.*]] = icmp slt i32 [[CXN]], [[AX]]
+; CHECK-NEXT:    [[EXN:%.*]] = icmp sge i32 [[CXN]], [[AX]]
+; CHECK-NEXT:    [[FXN:%.*]] = icmp sgt i32 [[AX]], [[CXN]]
+; CHECK-NEXT:    [[GXN:%.*]] = icmp sle i32 [[AX]], [[CXN]]
+; CHECK-NEXT:    call void @helper_i1(i1 false)
+; CHECK-NEXT:    call void @helper_i1(i1 true)
+; CHECK-NEXT:    call void @helper_i1(i1 false)
+; CHECK-NEXT:    call void @helper_i1(i1 true)
+; CHECK-NEXT:    call void @helper_i1(i1 [[DPX]])
+; CHECK-NEXT:    call void @helper_i1(i1 [[EPX]])
+; CHECK-NEXT:    call void @helper_i1(i1 [[FPX]])
+; CHECK-NEXT:    call void @helper_i1(i1 [[GPX]])
+; CHECK-NEXT:    call void @helper_i1(i1 true)
+; CHECK-NEXT:    call void @helper_i1(i1 false)
+; CHECK-NEXT:    call void @helper_i1(i1 true)
+; CHECK-NEXT:    call void @helper_i1(i1 false)
+; CHECK-NEXT:    call void @helper_i1(i1 false)
+; CHECK-NEXT:    call void @helper_i1(i1 true)
+; CHECK-NEXT:    call void @helper_i1(i1 false)
+; CHECK-NEXT:    call void @helper_i1(i1 true)
+; CHECK-NEXT:    call void @helper_i1(i1 [[DXX]])
+; CHECK-NEXT:    call void @helper_i1(i1 [[EXX]])
+; CHECK-NEXT:    call void @helper_i1(i1 [[FXX]])
+; CHECK-NEXT:    call void @helper_i1(i1 [[GXX]])
+; CHECK-NEXT:    call void @helper_i1(i1 [[DXN]])
+; CHECK-NEXT:    call void @helper_i1(i1 [[EXN]])
+; CHECK-NEXT:    call void @helper_i1(i1 [[FXN]])
+; CHECK-NEXT:    call void @helper_i1(i1 [[GXN]])
+; CHECK-NEXT:    call void @helper_i1(i1 false)
+; CHECK-NEXT:    call void @helper_i1(i1 true)
+; CHECK-NEXT:    call void @helper_i1(i1 false)
+; CHECK-NEXT:    call void @helper_i1(i1 true)
+; CHECK-NEXT:    call void @helper_i1(i1 false)
+; CHECK-NEXT:    call void @helper_i1(i1 true)
+; CHECK-NEXT:    call void @helper_i1(i1 false)
+; CHECK-NEXT:    call void @helper_i1(i1 true)
+; CHECK-NEXT:    call void @helper_i1(i1 false)
+; CHECK-NEXT:    call void @helper_i1(i1 true)
+; CHECK-NEXT:    call void @helper_i1(i1 false)
+; CHECK-NEXT:    call void @helper_i1(i1 true)
+; CHECK-NEXT:    ret void
+;
+  %Aneg = or i32 %Ax, 2147483648
+  %Apos = and i32 %Ax, 2147483647
+  %Bneg = or i32 %Bx, 2147483648
+  %Bpos = and i32 %Bx, 2147483647
+
+  %Cpp = or i32 %Apos, %Bpos
+  %Dpp = icmp slt i32 %Cpp, %Apos
+  %Epp = icmp sge i32 %Cpp, %Apos
+  %Fpp = icmp sgt i32 %Apos, %Cpp
+  %Gpp = icmp sle i32 %Apos, %Cpp
+  %Cpx = or i32 %Apos, %Bx
+  %Dpx = icmp slt i32 %Cpx, %Apos
+  %Epx = icmp sge i32 %Cpx, %Apos
+  %Fpx = icmp sgt i32 %Apos, %Cpx
+  %Gpx = icmp sle i32 %Apos, %Cpx
+  %Cpn = or i32 %Apos, %Bneg
+  %Dpn = icmp slt i32 %Cpn, %Apos
+  %Epn = icmp sge i32 %Cpn, %Apos
+  %Fpn = icmp sgt i32 %Apos, %Cpn
+  %Gpn = icmp sle i32 %Apos, %Cpn
+
+  %Cxp = or i32 %Ax, %Bpos
+  %Dxp = icmp slt i32 %Cxp, %Ax
+  %Exp = icmp sge i32 %Cxp, %Ax
+  %Fxp = icmp sgt i32 %Ax, %Cxp
+  %Gxp = icmp sle i32 %Ax, %Cxp
+  %Cxx = or i32 %Ax, %Bx
+  %Dxx = icmp slt i32 %Cxx, %Ax
+  %Exx = icmp sge i32 %Cxx, %Ax
+  %Fxx = icmp sgt i32 %Ax, %Cxx
+  %Gxx = icmp sle i32 %Ax, %Cxx
+  %Cxn = or i32 %Ax, %Bneg
+  %Dxn = icmp slt i32 %Cxn, %Ax
+  %Exn = icmp sge i32 %Cxn, %Ax
+  %Fxn = icmp sgt i32 %Ax, %Cxn
+  %Gxn = icmp sle i32 %Ax, %Cxn
+
+  %Cnp = or i32 %Aneg, %Bpos
+  %Dnp = icmp slt i32 %Cnp, %Aneg
+  %Enp = icmp sge i32 %Cnp, %Aneg
+  %Fnp = icmp sgt i32 %Aneg, %Cnp
+  %Gnp = icmp sle i32 %Aneg, %Cnp
+  %Cnx = or i32 %Aneg, %Bx
+  %Dnx = icmp slt i32 %Cnx, %Aneg
+  %Enx = icmp sge i32 %Cnx, %Aneg
+  %Fnx = icmp sgt i32 %Aneg, %Cnx
+  %Gnx = icmp sle i32 %Aneg, %Cnx
+  %Cnn = or i32 %Aneg, %Bneg
+  %Dnn = icmp slt i32 %Cnn, %Aneg
+  %Enn = icmp sge i32 %Cnn, %Aneg
+  %Fnn = icmp sgt i32 %Aneg, %Cnn
+  %Gnn = icmp sle i32 %Aneg, %Cnn
+
+  call void @helper_i1(i1 %Dpp)
+  call void @helper_i1(i1 %Epp)
+  call void @helper_i1(i1 %Fpp)
+  call void @helper_i1(i1 %Gpp)
+  call void @helper_i1(i1 %Dpx)
+  call void @helper_i1(i1 %Epx)
+  call void @helper_i1(i1 %Fpx)
+  call void @helper_i1(i1 %Gpx)
+  call void @helper_i1(i1 %Dpn)
+  call void @helper_i1(i1 %Epn)
+  call void @helper_i1(i1 %Fpn)
+  call void @helper_i1(i1 %Gpn)
+  call void @helper_i1(i1 %Dxp)
+  call void @helper_i1(i1 %Exp)
+  call void @helper_i1(i1 %Fxp)
+  call void @helper_i1(i1 %Gxp)
+  call void @helper_i1(i1 %Dxx)
+  call void @helper_i1(i1 %Exx)
+  call void @helper_i1(i1 %Fxx)
+  call void @helper_i1(i1 %Gxx)
+  call void @helper_i1(i1 %Dxn)
+  call void @helper_i1(i1 %Exn)
+  call void @helper_i1(i1 %Fxn)
+  call void @helper_i1(i1 %Gxn)
+  call void @helper_i1(i1 %Dnp)
+  call void @helper_i1(i1 %Enp)
+  call void @helper_i1(i1 %Fnp)
+  call void @helper_i1(i1 %Gnp)
+  call void @helper_i1(i1 %Dnx)
+  call void @helper_i1(i1 %Enx)
+  call void @helper_i1(i1 %Fnx)
+  call void @helper_i1(i1 %Gnx)
+  call void @helper_i1(i1 %Dnn)
+  call void @helper_i1(i1 %Enn)
+  call void @helper_i1(i1 %Fnn)
+  call void @helper_i1(i1 %Gnn)
+  ret void
+}
+
+define i1 @constant_fold_inttoptr_null() {
+; CHECK-LABEL: @constant_fold_inttoptr_null(
+; CHECK-NEXT:    ret i1 false
+;
+  %x = icmp eq ptr inttoptr (i64 32 to ptr), null
+  ret i1 %x
+}
+
+define i1 @constant_fold_null_inttoptr() {
+; CHECK-LABEL: @constant_fold_null_inttoptr(
+; CHECK-NEXT:    ret i1 false
+;
+  %x = icmp eq ptr null, inttoptr (i64 32 to ptr)
+  ret i1 %x
+}
+
+define i1 @cmp_through_addrspacecast(ptr addrspace(1) %p1) {
+; CHECK-LABEL: @cmp_through_addrspacecast(
+; CHECK-NEXT:    ret i1 true
+;
+  %p0 = addrspacecast ptr addrspace(1) %p1 to ptr
+  %p0.1 = getelementptr inbounds i32, ptr %p0, i64 1
+  %cmp = icmp ne ptr %p0, %p0.1
+  ret i1 %cmp
+}
+
+; Test simplifications for: icmp (X+Y), (X+Z) -> icmp Y,Z
+; Test the overflow check when the RHS has NSW set and constant Z is greater
+; than Y, then we know X+Y also can't overflow.
+
+define i1 @icmp_nsw_1(i32 %V) {
+; CHECK-LABEL: @icmp_nsw_1(
+; CHECK-NEXT:    ret i1 true
+;
+  %add5 = add i32 %V, 5
+  %add6 = add nsw i32 %V, 6
+  %s1 = sext i32 %add5 to i64
+  %s2 = sext i32 %add6 to i64
+  %cmp = icmp slt i64 %s1, %s2
+  ret i1 %cmp
+}
+
+define i1 @icmp_nsw_2(i32 %V) {
+; CHECK-LABEL: @icmp_nsw_2(
+; CHECK-NEXT:    ret i1 true
+;
+  %add5 = add i32 %V, 5
+  %add6 = add nsw i32 %V, 6
+  %cmp = icmp slt i32 %add5, %add6
+  ret i1 %cmp
+}
+
+define i1 @icmp_nsw_22(i32 %V) {
+; CHECK-LABEL: @icmp_nsw_22(
+; CHECK-NEXT:    ret i1 true
+;
+  %add5 = add nsw i32 %V, 5
+  %add6 = add nsw i32 %V, 6
+  %cmp = icmp slt i32 %add5, %add6
+  ret i1 %cmp
+}
+
+define i1 @icmp_nsw_23(i32 %V) {
+; CHECK-LABEL: @icmp_nsw_23(
+; CHECK-NEXT:    [[ADD5:%.*]] = add nsw i32 [[V:%.*]], 5
+; CHECK-NEXT:    [[ADD6:%.*]] = add i32 [[V]], 6
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[ADD5]], [[ADD6]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %add5 = add nsw i32 %V, 5
+  %add6 = add i32 %V, 6
+  %cmp = icmp slt i32 %add5, %add6
+  ret i1 %cmp
+}
+
+define i1 @icmp_nsw_false(i32 %V) {
+; CHECK-LABEL: @icmp_nsw_false(
+; CHECK-NEXT:    ret i1 false
+;
+  %add5 = add nsw i32 %V, 6
+  %add6 = add i32 %V, 5
+  %cmp = icmp slt i32 %add5, %add6
+  ret i1 %cmp
+}
+
+define i1 @icmp_nsw_false_2(i32 %V) {
+; CHECK-LABEL: @icmp_nsw_false_2(
+; CHECK-NEXT:    ret i1 false
+;
+  %add5 = add nsw i32 %V, 6
+  %add6 = add nsw i32 %V, 5
+  %cmp = icmp slt i32 %add5, %add6
+  ret i1 %cmp
+}
+
+define i1 @icmp_nsw_false_3(i32 %V) {
+; CHECK-LABEL: @icmp_nsw_false_3(
+; CHECK-NEXT:    [[ADD5:%.*]] = add nsw i32 [[V:%.*]], 5
+; CHECK-NEXT:    [[ADD6:%.*]] = add i32 [[V]], 5
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[ADD5]], [[ADD6]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %add5 = add nsw i32 %V, 5
+  %add6 = add i32 %V, 5
+  %cmp = icmp slt i32 %add5, %add6
+  ret i1 %cmp
+}
+
+define i1 @icmp_nsw_false_4(i32 %V) {
+; CHECK-LABEL: @icmp_nsw_false_4(
+; CHECK-NEXT:    [[ADD5:%.*]] = add i32 [[V:%.*]], 6
+; CHECK-NEXT:    [[ADD6:%.*]] = add nsw i32 [[V]], 5
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[ADD5]], [[ADD6]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %add5 = add i32 %V, 6
+  %add6 = add nsw i32 %V, 5
+  %cmp = icmp slt i32 %add5, %add6
+  ret i1 %cmp
+}
+
+define i1 @icmp_nsw_false_5(i8 %V) {
+; CHECK-LABEL: @icmp_nsw_false_5(
+; CHECK-NEXT:    [[ADD:%.*]] = add i8 [[V:%.*]], 121
+; CHECK-NEXT:    [[ADDNSW:%.*]] = add nsw i8 [[V]], -104
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[ADD]], [[ADDNSW]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %add = add i8 %V, 121
+  %addnsw = add nsw i8 %V, -104
+  %cmp = icmp slt i8 %add, %addnsw
+  ret i1 %cmp
+}
+
+define i1 @icmp_nsw_i8(i8 %V) {
+; CHECK-LABEL: @icmp_nsw_i8(
+; CHECK-NEXT:    ret i1 true
+;
+  %add5 = add i8 %V, 5
+  %add6 = add nsw i8 %V, 6
+  %cmp = icmp slt i8 %add5, %add6
+  ret i1 %cmp
+}
+
+define i1 @icmp_nsw_i16(i16 %V) {
+; CHECK-LABEL: @icmp_nsw_i16(
+; CHECK-NEXT:    ret i1 true
+;
+  %add5 = add i16 %V, 0
+  %add6 = add nsw i16 %V, 1
+  %cmp = icmp slt i16 %add5, %add6
+  ret i1 %cmp
+}
+
+define i1 @icmp_nsw_i64(i64 %V) {
+; CHECK-LABEL: @icmp_nsw_i64(
+; CHECK-NEXT:    ret i1 true
+;
+  %add5 = add i64 %V, 5
+  %add6 = add nsw i64 %V, 6
+  %cmp = icmp slt i64 %add5, %add6
+  ret i1 %cmp
+}
+
+define <4 x i1> @icmp_nsw_vec(<4 x i32> %V) {
+; CHECK-LABEL: @icmp_nsw_vec(
+; CHECK-NEXT:    ret <4 x i1> <i1 true, i1 true, i1 true, i1 true>
+;
+  %add5 = add <4 x i32> %V, <i32 5, i32 5, i32 5, i32 5>
+  %add6 = add nsw <4 x i32> %V, <i32 6, i32 6, i32 6, i32 6>
+  %cmp = icmp slt <4 x i32> %add5, %add6
+  ret <4 x i1> %cmp
+}
+
+define i1 @icmp_nsw_3(i32 %V) {
+; CHECK-LABEL: @icmp_nsw_3(
+; CHECK-NEXT:    [[ADD5:%.*]] = add i32 [[V:%.*]], 5
+; CHECK-NEXT:    [[ADD5_2:%.*]] = add nsw i32 [[V]], 5
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[ADD5]], [[ADD5_2]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %add5 = add i32 %V, 5
+  %add5_2 = add nsw i32 %V, 5
+  %cmp = icmp slt i32 %add5, %add5_2
+  ret i1 %cmp
+}
+
+define i1 @icmp_nsw_4(i32 %V) {
+; CHECK-LABEL: @icmp_nsw_4(
+; CHECK-NEXT:    [[ADD5:%.*]] = add i32 [[V:%.*]], 5
+; CHECK-NEXT:    [[ADD4:%.*]] = add nsw i32 [[V]], 4
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[ADD5]], [[ADD4]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %add5 = add i32 %V, 5
+  %add4 = add nsw i32 %V, 4
+  %cmp = icmp slt i32 %add5, %add4
+  ret i1 %cmp
+}
+
+define i1 @icmp_nsw_5(i32 %V) {
+; CHECK-LABEL: @icmp_nsw_5(
+; CHECK-NEXT:    [[ADD5:%.*]] = add nsw i32 [[V:%.*]], 5
+; CHECK-NEXT:    [[ADD6:%.*]] = add i32 [[V]], 6
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[ADD5]], [[ADD6]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %add5 = add nsw i32 %V, 5
+  %add6 = add i32 %V, 6
+  %cmp = icmp slt i32 %add5, %add6
+  ret i1 %cmp
+}
+
+define i1 @icmp_nsw_7(i32 %V, i32 %arg) {
+; CHECK-LABEL: @icmp_nsw_7(
+; CHECK-NEXT:    [[ADD5:%.*]] = add i32 [[V:%.*]], 5
+; CHECK-NEXT:    [[ADDARG:%.*]] = add nsw i32 [[V]], [[ARG:%.*]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[ADD5]], [[ADDARG]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %add5 = add i32 %V, 5
+  %addarg = add nsw i32 %V, %arg
+  %cmp = icmp slt i32 %add5, %addarg
+  ret i1 %cmp
+}
+
+define i1 @icmp_nsw_8(i32 %V, i32 %arg) {
+; CHECK-LABEL: @icmp_nsw_8(
+; CHECK-NEXT:    [[ADDARG:%.*]] = add i32 [[V:%.*]], [[ARG:%.*]]
+; CHECK-NEXT:    [[ADD6:%.*]] = add nsw i32 [[V]], 5
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[ADDARG]], [[ADD6]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %addarg = add i32 %V, %arg
+  %add6 = add nsw i32 %V, 5
+  %cmp = icmp slt i32 %addarg, %add6
+  ret i1 %cmp
+}
+
+define i1 @icmp_nsw_9(i32 %V1, i32 %V2) {
+; CHECK-LABEL: @icmp_nsw_9(
+; CHECK-NEXT:    [[ADD_V1:%.*]] = add i32 [[V1:%.*]], 5
+; CHECK-NEXT:    [[ADD_V2:%.*]] = add nsw i32 [[V2:%.*]], 6
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[ADD_V1]], [[ADD_V2]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %add_V1 = add i32 %V1, 5
+  %add_V2 = add nsw i32 %V2, 6
+  %cmp = icmp slt i32 %add_V1, %add_V2
+  ret i1 %cmp
+}
+
+define i1 @icmp_nsw_10(i32 %V) {
+; CHECK-LABEL: @icmp_nsw_10(
+; CHECK-NEXT:    [[ADD5:%.*]] = add i32 [[V:%.*]], 5
+; CHECK-NEXT:    [[ADD6:%.*]] = add nsw i32 [[V]], 6
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[ADD6]], [[ADD5]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %add5 = add i32 %V, 5
+  %add6 = add nsw i32 %V, 6
+  %cmp = icmp sgt i32 %add6, %add5
+  ret i1 %cmp
+}
+
+define i1 @icmp_nsw_11(i32 %V) {
+; CHECK-LABEL: @icmp_nsw_11(
+; CHECK-NEXT:    [[ADD5:%.*]] = add i32 [[V:%.*]], -125
+; CHECK-NEXT:    [[ADD6:%.*]] = add nsw i32 [[V]], -99
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[ADD5]], [[ADD6]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %add5 = add i32 %V, -125
+  %add6 = add nsw i32 %V, -99
+  %cmp = icmp slt i32 %add5, %add6
+  ret i1 %cmp
+}
+
+define i1 @icmp_nsw_nonpos(i32 %V) {
+; CHECK-LABEL: @icmp_nsw_nonpos(
+; CHECK-NEXT:    ret i1 false
+;
+  %add5 = add i32 %V, 0
+  %add6 = add nsw i32 %V, -1
+  %cmp = icmp slt i32 %add5, %add6
+  ret i1 %cmp
+}
+
+define i1 @icmp_nsw_nonpos2(i32 %V) {
+; CHECK-LABEL: @icmp_nsw_nonpos2(
+; CHECK-NEXT:    [[ADD5:%.*]] = add i32 [[V:%.*]], 1
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[ADD5]], [[V]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %add5 = add i32 %V, 1
+  %add6 = add nsw i32 %V, 0
+  %cmp = icmp slt i32 %add5, %add6
+  ret i1 %cmp
+}
+
+declare i11 @llvm.ctpop.i11(i11)
+declare i73 @llvm.ctpop.i73(i73)
+declare <2 x i13> @llvm.ctpop.v2i13(<2 x i13>)
+
+define i1 @ctpop_sgt_bitwidth(i11 %x) {
+; CHECK-LABEL: @ctpop_sgt_bitwidth(
+; CHECK-NEXT:    ret i1 false
+;
+  %pop = call i11 @llvm.ctpop.i11(i11 %x)
+  %cmp = icmp sgt i11 %pop, 11
+  ret i1 %cmp
+}
+
+define i1 @ctpop_sle_minus1(i11 %x) {
+; CHECK-LABEL: @ctpop_sle_minus1(
+; CHECK-NEXT:    ret i1 false
+;
+  %pop = call i11 @llvm.ctpop.i11(i11 %x)
+  %cmp = icmp sle i11 %pop, -1
+  ret i1 %cmp
+}
+
+define i1 @ctpop_ugt_bitwidth(i73 %x) {
+; CHECK-LABEL: @ctpop_ugt_bitwidth(
+; CHECK-NEXT:    ret i1 false
+;
+  %pop = call i73 @llvm.ctpop.i73(i73 %x)
+  %cmp = icmp ugt i73 %pop, 73
+  ret i1 %cmp
+}
+
+; Negative test - does not simplify, but instcombine could reduce this.
+
+define i1 @ctpop_ugt_bitwidth_minus1(i73 %x) {
+; CHECK-LABEL: @ctpop_ugt_bitwidth_minus1(
+; CHECK-NEXT:    [[POP:%.*]] = call i73 @llvm.ctpop.i73(i73 [[X:%.*]])
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i73 [[POP]], 72
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %pop = call i73 @llvm.ctpop.i73(i73 %x)
+  %cmp = icmp ugt i73 %pop, 72
+  ret i1 %cmp
+}
+
+define <2 x i1> @ctpop_sgt_bitwidth_splat(<2 x i13> %x) {
+; CHECK-LABEL: @ctpop_sgt_bitwidth_splat(
+; CHECK-NEXT:    ret <2 x i1> zeroinitializer
+;
+  %pop = call <2 x i13> @llvm.ctpop.v2i13(<2 x i13> %x)
+  %cmp = icmp sgt <2 x i13> %pop, <i13 13, i13 13>
+  ret <2 x i1> %cmp
+}
+
+define i1 @ctpop_ult_plus1_bitwidth(i11 %x) {
+; CHECK-LABEL: @ctpop_ult_plus1_bitwidth(
+; CHECK-NEXT:    ret i1 true
+;
+  %pop = call i11 @llvm.ctpop.i11(i11 %x)
+  %cmp = icmp ult i11 %pop, 12
+  ret i1 %cmp
+}
+
+define i1 @ctpop_ne_big_bitwidth(i73 %x) {
+; CHECK-LABEL: @ctpop_ne_big_bitwidth(
+; CHECK-NEXT:    ret i1 true
+;
+  %pop = call i73 @llvm.ctpop.i73(i73 %x)
+  %cmp = icmp ne i73 %pop, 75
+  ret i1 %cmp
+}
+
+define <2 x i1> @ctpop_slt_bitwidth_plus1_splat(<2 x i13> %x) {
+; CHECK-LABEL: @ctpop_slt_bitwidth_plus1_splat(
+; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
+;
+  %pop = call <2 x i13> @llvm.ctpop.v2i13(<2 x i13> %x)
+  %cmp = icmp slt <2 x i13> %pop, <i13 14, i13 14>
+  ret <2 x i1> %cmp
+}
+
+; Negative test - does not simplify, but instcombine could reduce this.
+
+define <2 x i1> @ctpop_slt_bitwidth_splat(<2 x i13> %x) {
+; CHECK-LABEL: @ctpop_slt_bitwidth_splat(
+; CHECK-NEXT:    [[POP:%.*]] = call <2 x i13> @llvm.ctpop.v2i13(<2 x i13> [[X:%.*]])
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt <2 x i13> [[POP]], <i13 13, i13 13>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %pop = call <2 x i13> @llvm.ctpop.v2i13(<2 x i13> %x)
+  %cmp = icmp slt <2 x i13> %pop, <i13 13, i13 13>
+  ret <2 x i1> %cmp
+}
+
+declare i11 @llvm.ctlz.i11(i11)
+declare i73 @llvm.ctlz.i73(i73)
+declare <2 x i13> @llvm.ctlz.v2i13(<2 x i13>)
+
+define i1 @ctlz_sgt_bitwidth(i11 %x) {
+; CHECK-LABEL: @ctlz_sgt_bitwidth(
+; CHECK-NEXT:    ret i1 false
+;
+  %pop = call i11 @llvm.ctlz.i11(i11 %x)
+  %cmp = icmp sgt i11 %pop, 11
+  ret i1 %cmp
+}
+
+define i1 @ctlz_sle_minus1(i11 %x) {
+; CHECK-LABEL: @ctlz_sle_minus1(
+; CHECK-NEXT:    ret i1 false
+;
+  %pop = call i11 @llvm.ctlz.i11(i11 %x)
+  %cmp = icmp sle i11 %pop, -1
+  ret i1 %cmp
+}
+
+define i1 @ctlz_ugt_bitwidth(i73 %x) {
+; CHECK-LABEL: @ctlz_ugt_bitwidth(
+; CHECK-NEXT:    ret i1 false
+;
+  %pop = call i73 @llvm.ctlz.i73(i73 %x)
+  %cmp = icmp ugt i73 %pop, 73
+  ret i1 %cmp
+}
+
+; Negative test - does not simplify, but instcombine could reduce this.
+
+define i1 @ctlz_ugt_bitwidth_minus1(i73 %x) {
+; CHECK-LABEL: @ctlz_ugt_bitwidth_minus1(
+; CHECK-NEXT:    [[POP:%.*]] = call i73 @llvm.ctlz.i73(i73 [[X:%.*]], i1 false)
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i73 [[POP]], 72
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %pop = call i73 @llvm.ctlz.i73(i73 %x)
+  %cmp = icmp ugt i73 %pop, 72
+  ret i1 %cmp
+}
+
+define <2 x i1> @ctlz_sgt_bitwidth_splat(<2 x i13> %x) {
+; CHECK-LABEL: @ctlz_sgt_bitwidth_splat(
+; CHECK-NEXT:    ret <2 x i1> zeroinitializer
+;
+  %pop = call <2 x i13> @llvm.ctlz.v2i13(<2 x i13> %x)
+  %cmp = icmp sgt <2 x i13> %pop, <i13 13, i13 13>
+  ret <2 x i1> %cmp
+}
+
+define i1 @ctlz_ult_plus1_bitwidth(i11 %x) {
+; CHECK-LABEL: @ctlz_ult_plus1_bitwidth(
+; CHECK-NEXT:    ret i1 true
+;
+  %pop = call i11 @llvm.ctlz.i11(i11 %x)
+  %cmp = icmp ult i11 %pop, 12
+  ret i1 %cmp
+}
+
+define i1 @ctlz_ne_big_bitwidth(i73 %x) {
+; CHECK-LABEL: @ctlz_ne_big_bitwidth(
+; CHECK-NEXT:    ret i1 true
+;
+  %pop = call i73 @llvm.ctlz.i73(i73 %x)
+  %cmp = icmp ne i73 %pop, 75
+  ret i1 %cmp
+}
+
+define <2 x i1> @ctlz_slt_bitwidth_plus1_splat(<2 x i13> %x) {
+; CHECK-LABEL: @ctlz_slt_bitwidth_plus1_splat(
+; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
+;
+  %pop = call <2 x i13> @llvm.ctlz.v2i13(<2 x i13> %x)
+  %cmp = icmp slt <2 x i13> %pop, <i13 14, i13 14>
+  ret <2 x i1> %cmp
+}
+
+; Negative test - does not simplify, but instcombine could reduce this.
+
+define <2 x i1> @ctlz_slt_bitwidth_splat(<2 x i13> %x) {
+; CHECK-LABEL: @ctlz_slt_bitwidth_splat(
+; CHECK-NEXT:    [[POP:%.*]] = call <2 x i13> @llvm.ctlz.v2i13(<2 x i13> [[X:%.*]], i1 false)
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt <2 x i13> [[POP]], <i13 13, i13 13>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %pop = call <2 x i13> @llvm.ctlz.v2i13(<2 x i13> %x)
+  %cmp = icmp slt <2 x i13> %pop, <i13 13, i13 13>
+  ret <2 x i1> %cmp
+}
+
+declare i11 @llvm.cttz.i11(i11)
+declare i73 @llvm.cttz.i73(i73)
+declare <2 x i13> @llvm.cttz.v2i13(<2 x i13>)
+
+define i1 @cttz_sgt_bitwidth(i11 %x) {
+; CHECK-LABEL: @cttz_sgt_bitwidth(
+; CHECK-NEXT:    ret i1 false
+;
+  %pop = call i11 @llvm.cttz.i11(i11 %x)
+  %cmp = icmp sgt i11 %pop, 11
+  ret i1 %cmp
+}
+
+define i1 @cttz_sle_minus1(i11 %x) {
+; CHECK-LABEL: @cttz_sle_minus1(
+; CHECK-NEXT:    ret i1 false
+;
+  %pop = call i11 @llvm.cttz.i11(i11 %x)
+  %cmp = icmp sle i11 %pop, -1
+  ret i1 %cmp
+}
+
+define i1 @cttz_ugt_bitwidth(i73 %x) {
+; CHECK-LABEL: @cttz_ugt_bitwidth(
+; CHECK-NEXT:    ret i1 false
+;
+  %pop = call i73 @llvm.cttz.i73(i73 %x)
+  %cmp = icmp ugt i73 %pop, 73
+  ret i1 %cmp
+}
+
+; Negative test - does not simplify, but instcombine could reduce this.
+
+define i1 @cttz_ugt_bitwidth_minus1(i73 %x) {
+; CHECK-LABEL: @cttz_ugt_bitwidth_minus1(
+; CHECK-NEXT:    [[POP:%.*]] = call i73 @llvm.cttz.i73(i73 [[X:%.*]], i1 false)
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i73 [[POP]], 72
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %pop = call i73 @llvm.cttz.i73(i73 %x)
+  %cmp = icmp ugt i73 %pop, 72
+  ret i1 %cmp
+}
+
+define <2 x i1> @cttz_sgt_bitwidth_splat(<2 x i13> %x) {
+; CHECK-LABEL: @cttz_sgt_bitwidth_splat(
+; CHECK-NEXT:    ret <2 x i1> zeroinitializer
+;
+  %pop = call <2 x i13> @llvm.cttz.v2i13(<2 x i13> %x)
+  %cmp = icmp sgt <2 x i13> %pop, <i13 13, i13 13>
+  ret <2 x i1> %cmp
+}
+
+define i1 @cttz_ult_plus1_bitwidth(i11 %x) {
+; CHECK-LABEL: @cttz_ult_plus1_bitwidth(
+; CHECK-NEXT:    ret i1 true
+;
+  %pop = call i11 @llvm.cttz.i11(i11 %x)
+  %cmp = icmp ult i11 %pop, 12
+  ret i1 %cmp
+}
+
+define i1 @cttz_ne_big_bitwidth(i73 %x) {
+; CHECK-LABEL: @cttz_ne_big_bitwidth(
+; CHECK-NEXT:    ret i1 true
+;
+  %pop = call i73 @llvm.cttz.i73(i73 %x)
+  %cmp = icmp ne i73 %pop, 75
+  ret i1 %cmp
+}
+
+define <2 x i1> @cttz_slt_bitwidth_plus1_splat(<2 x i13> %x) {
+; CHECK-LABEL: @cttz_slt_bitwidth_plus1_splat(
+; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
+;
+  %pop = call <2 x i13> @llvm.cttz.v2i13(<2 x i13> %x)
+  %cmp = icmp slt <2 x i13> %pop, <i13 14, i13 14>
+  ret <2 x i1> %cmp
+}
+
+; Negative test - does not simplify, but instcombine could reduce this.
+
+define <2 x i1> @cttz_slt_bitwidth_splat(<2 x i13> %x) {
+; CHECK-LABEL: @cttz_slt_bitwidth_splat(
+; CHECK-NEXT:    [[POP:%.*]] = call <2 x i13> @llvm.cttz.v2i13(<2 x i13> [[X:%.*]], i1 false)
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt <2 x i13> [[POP]], <i13 13, i13 13>
+; CHECK-NEXT:    ret <2 x i1> [[CMP]]
+;
+  %pop = call <2 x i13> @llvm.cttz.v2i13(<2 x i13> %x)
+  %cmp = icmp slt <2 x i13> %pop, <i13 13, i13 13>
+  ret <2 x i1> %cmp
+}
+
+; A zero sized alloca *can* be equal to another alloca
+define i1 @zero_sized_alloca1() {
+; CHECK-LABEL: @zero_sized_alloca1(
+; CHECK-NEXT:    [[A:%.*]] = alloca i32, i32 0, align 4
+; CHECK-NEXT:    [[B:%.*]] = alloca i32, i32 0, align 4
+; CHECK-NEXT:    [[RES:%.*]] = icmp ne ptr [[A]], [[B]]
+; CHECK-NEXT:    ret i1 [[RES]]
+;
+  %a = alloca i32, i32 0
+  %b = alloca i32, i32 0
+  %res = icmp ne ptr %a, %b
+  ret i1 %res
+}
+
+define i1 @zero_sized_alloca2() {
+; CHECK-LABEL: @zero_sized_alloca2(
+; CHECK-NEXT:    [[A:%.*]] = alloca i32, i32 0, align 4
+; CHECK-NEXT:    [[B:%.*]] = alloca i32, align 4
+; CHECK-NEXT:    [[RES:%.*]] = icmp ne ptr [[A]], [[B]]
+; CHECK-NEXT:    ret i1 [[RES]]
+;
+  %a = alloca i32, i32 0
+  %b = alloca i32
+  %res = icmp ne ptr %a, %b
+  ret i1 %res
+}
+
+define i1 @scalar_vectors_are_non_empty() {
+; CHECK-LABEL: @scalar_vectors_are_non_empty(
+; CHECK-NEXT:    ret i1 true
+;
+  %a = alloca <vscale x 2 x i32>
+  %b = alloca <vscale x 2 x i32>
+  %res = icmp ne ptr %a, %b
+  ret i1 %res
+}
+
+; Never equal
+define i1 @byval_args_inequal(ptr byval(i32) %a, ptr byval(i32) %b) {
+; CHECK-LABEL: @byval_args_inequal(
+; CHECK-NEXT:    ret i1 true
+;
+  %res = icmp ne ptr %a, %b
+  ret i1 %res
+}
+
+; Arguments can be adjacent on the stack
+define i1 @neg_args_adjacent(ptr byval(i32) %a, ptr byval(i32) %b) {
+; CHECK-LABEL: @neg_args_adjacent(
+; CHECK-NEXT:    [[A_OFF:%.*]] = getelementptr i32, ptr [[A:%.*]], i32 1
+; CHECK-NEXT:    [[RES:%.*]] = icmp ne ptr [[A_OFF]], [[B:%.*]]
+; CHECK-NEXT:    ret i1 [[RES]]
+;
+  %a.off = getelementptr i32, ptr %a, i32 1
+  %res = icmp ne ptr %a.off, %b
+  ret i1 %res
+}
+
+; Never equal
+define i1 @test_byval_alloca_inequal(ptr byval(i32) %a) {
+; CHECK-LABEL: @test_byval_alloca_inequal(
+; CHECK-NEXT:    ret i1 true
+;
+  %b = alloca i32
+  %res = icmp ne ptr %a, %b
+  ret i1 %res
+}
+
+; Byval argument can be immediately before alloca, and crossing
+; over is allowed.
+define i1 @neg_byval_alloca_adjacent(ptr byval(i32) %a) {
+; CHECK-LABEL: @neg_byval_alloca_adjacent(
+; CHECK-NEXT:    [[B:%.*]] = alloca i32, align 4
+; CHECK-NEXT:    [[A_OFF:%.*]] = getelementptr i32, ptr [[A:%.*]], i32 1
+; CHECK-NEXT:    [[RES:%.*]] = icmp ne ptr [[A_OFF]], [[B]]
+; CHECK-NEXT:    ret i1 [[RES]]
+;
+  %b = alloca i32
+  %a.off = getelementptr i32, ptr %a, i32 1
+  %res = icmp ne ptr %a.off, %b
+  ret i1 %res
+}
+
+ at A = global i32 0
+ at B = global i32 0
+ at A.alias = alias i32, ptr @A
+
+define i1 @globals_inequal() {
+; CHECK-LABEL: @globals_inequal(
+; CHECK-NEXT:    ret i1 true
+;
+  %res = icmp ne ptr @A, @B
+  ret i1 %res
+}
+
+; TODO: Never equal
+define i1 @globals_offset_inequal() {
+; CHECK-LABEL: @globals_offset_inequal(
+; CHECK-NEXT:    ret i1 icmp ne (ptr getelementptr (i8, ptr @A, i32 1), ptr getelementptr (i8, ptr @B, i32 1))
+;
+  %a.off = getelementptr i8, ptr @A, i32 1
+  %b.off = getelementptr i8, ptr @B, i32 1
+  %res = icmp ne ptr %a.off, %b.off
+  ret i1 %res
+}
+
+
+; Never equal
+define i1 @test_byval_global_inequal(ptr byval(i32) %a) {
+; CHECK-LABEL: @test_byval_global_inequal(
+; CHECK-NEXT:    ret i1 true
+;
+  %b = alloca i32
+  %res = icmp ne ptr %a, @B
+  ret i1 %res
+}
+
+
+define i1 @neg_global_alias() {
+; CHECK-LABEL: @neg_global_alias(
+; CHECK-NEXT:    ret i1 icmp ne (ptr @A, ptr @A.alias)
+;
+  %res = icmp ne ptr @A, @A.alias
+  ret i1 %res
+}
+
+
+define i1 @icmp_lshr_known_non_zero_ult_true(i8 %x) {
+; CHECK-LABEL: @icmp_lshr_known_non_zero_ult_true(
+; CHECK-NEXT:    ret i1 true
+;
+  %or = or i8 %x, 1
+  %x1 = shl nuw i8 %or, 1
+  %x2 = shl nuw i8 %or, 2
+  %cmp = icmp ult i8 %x1, %x2
+  ret i1 %cmp
+}
+
+define i1 @icmp_lshr_known_non_zero_ult_false(i8 %x) {
+; CHECK-LABEL: @icmp_lshr_known_non_zero_ult_false(
+; CHECK-NEXT:    ret i1 false
+;
+  %or = or i8 %x, 1
+  %x1 = shl nuw i8 %or, 1
+  %x2 = shl nuw i8 %or, 2
+  %cmp = icmp ugt i8 %x1, %x2
+  ret i1 %cmp
+}
+
+define i1 @icmp_lshr_known_non_zero_slt_true(i8 %x) {
+; CHECK-LABEL: @icmp_lshr_known_non_zero_slt_true(
+; CHECK-NEXT:    ret i1 true
+;
+  %or = or i8 %x, 1
+  %x1 = shl nuw nsw i8 %or, 1
+  %x2 = shl nuw nsw i8 %or, 2
+  %cmp = icmp slt i8 %x1, %x2
+  ret i1 %cmp
+}
+
+define i1 @icmp_lshr_known_non_zero_slt_false(i8 %x) {
+; CHECK-LABEL: @icmp_lshr_known_non_zero_slt_false(
+; CHECK-NEXT:    ret i1 false
+;
+  %or = or i8 %x, 1
+  %x1 = shl nuw nsw i8 %or, 2
+  %x2 = shl nuw nsw i8 %or, 1
+  %cmp = icmp slt i8 %x1, %x2
+  ret i1 %cmp
+}
+
+define i1 @neg_icmp_lshr_known_non_zero_slt_no_nsw(i8 %x) {
+; CHECK-LABEL: @neg_icmp_lshr_known_non_zero_slt_no_nsw(
+; CHECK-NEXT:    [[OR:%.*]] = or i8 [[X:%.*]], 1
+; CHECK-NEXT:    [[X1:%.*]] = shl nuw i8 [[OR]], 1
+; CHECK-NEXT:    [[X2:%.*]] = shl nuw i8 [[OR]], 2
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[X1]], [[X2]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %or = or i8 %x, 1
+  %x1 = shl nuw i8 %or, 1
+  %x2 = shl nuw i8 %or, 2
+  %cmp = icmp slt i8 %x1, %x2
+  ret i1 %cmp
+}
+
+define i1 @neg_icmp_lshr_known_non_zero_ult_no_nuw(i8 %x) {
+; CHECK-LABEL: @neg_icmp_lshr_known_non_zero_ult_no_nuw(
+; CHECK-NEXT:    [[OR:%.*]] = or i8 [[X:%.*]], 1
+; CHECK-NEXT:    [[X1:%.*]] = shl i8 [[OR]], 1
+; CHECK-NEXT:    [[X2:%.*]] = shl i8 [[OR]], 2
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i8 [[X1]], [[X2]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %or = or i8 %x, 1
+  %x1 = shl i8 %or, 1
+  %x2 = shl i8 %or, 2
+  %cmp = icmp ult i8 %x1, %x2
+  ret i1 %cmp
+}
+
+define i1 @neg_icmp_lshr_known_non_zero_slt_no_nuw(i8 %x) {
+; CHECK-LABEL: @neg_icmp_lshr_known_non_zero_slt_no_nuw(
+; CHECK-NEXT:    [[OR:%.*]] = or i8 [[X:%.*]], 1
+; CHECK-NEXT:    [[X1:%.*]] = shl nsw i8 [[OR]], 1
+; CHECK-NEXT:    [[X2:%.*]] = shl nsw i8 [[OR]], 2
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[X1]], [[X2]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %or = or i8 %x, 1
+  %x1 = shl nsw i8 %or, 1
+  %x2 = shl nsw i8 %or, 2
+  %cmp = icmp slt i8 %x1, %x2
+  ret i1 %cmp
+}
+
+define i1 @neg_icmp_lshr_unknown_value(i8 %x) {
+; CHECK-LABEL: @neg_icmp_lshr_unknown_value(
+; CHECK-NEXT:    [[X1:%.*]] = shl nuw i8 [[X:%.*]], 2
+; CHECK-NEXT:    [[X2:%.*]] = shl nuw i8 [[X]], 1
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i8 [[X1]], [[X2]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %x1 = shl nuw i8 %x, 2
+  %x2 = shl nuw i8 %x, 1
+  %cmp = icmp ugt i8 %x1, %x2
+  ret i1 %cmp
+}
+
+define i1 @neg_icmp_lshr_unknown_shift(i8 %x, i8 %C1) {
+; CHECK-LABEL: @neg_icmp_lshr_unknown_shift(
+; CHECK-NEXT:    [[OR:%.*]] = or i8 [[X:%.*]], 1
+; CHECK-NEXT:    [[X1:%.*]] = shl nuw i8 [[OR]], 2
+; CHECK-NEXT:    [[X2:%.*]] = shl nuw i8 [[OR]], [[C1:%.*]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i8 [[X1]], [[X2]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %or = or i8 %x, 1
+  %x1 = shl nuw i8 %or, 2
+  %x2 = shl nuw i8 %or, %C1
+  %cmp = icmp ugt i8 %x1, %x2
+  ret i1 %cmp
+}
+
+define i1 @neg_icmp_lshr_different_shift_values(i8 %x, i8 %y) {
+; CHECK-LABEL: @neg_icmp_lshr_different_shift_values(
+; CHECK-NEXT:    [[X1:%.*]] = shl nuw nsw i8 [[X:%.*]], 1
+; CHECK-NEXT:    [[X2:%.*]] = shl nuw nsw i8 [[Y:%.*]], 2
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i8 [[X1]], [[X2]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %x1 = shl nuw nsw i8 %x, 1
+  %x2 = shl nuw nsw i8 %y, 2
+  %cmp = icmp ult i8 %x1, %x2
+  ret i1 %cmp
+}
+
+define i1 @icmp_ult_vscale_true(i8 %x, i8 %y) {
+; CHECK-LABEL: @icmp_ult_vscale_true(
+; CHECK-NEXT:    ret i1 true
+;
+  %vscale = call i64 @llvm.vscale.i64()
+  %x1 = shl nuw nsw i64 %vscale, 1
+  %x2 = shl nuw nsw i64 %vscale, 2
+  %cmp = icmp ult i64 %x1, %x2
+  ret i1 %cmp
+}
+
+define i1 @icmp_ult_vscale_false(i8 %x, i8 %y) {
+; CHECK-LABEL: @icmp_ult_vscale_false(
+; CHECK-NEXT:    ret i1 false
+;
+  %vscale = call i64 @llvm.vscale.i64()
+  %x1 = shl nuw nsw i64 %vscale, 1
+  %x2 = shl nuw nsw i64 %vscale, 2
+  %cmp = icmp ugt i64 %x1, %x2
+  ret i1 %cmp
+}
+
+declare i64 @llvm.vscale.i64()
+
+; TODO: Add coverage for global aliases, link once, etc..
+
+
+attributes #0 = { null_pointer_is_valid }
diff --git a/llvm/test/Transforms/InstSimplify/icmp-dl-sentinel.ll b/llvm/test/Transforms/InstSimplify/icmp-dl-sentinel.ll
new file mode 100755
index 0000000000000..a9d1fd546869f
--- /dev/null
+++ b/llvm/test/Transforms/InstSimplify/icmp-dl-sentinel.ll
@@ -0,0 +1,414 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -passes=instsimplify -S | FileCheck %s
+
+target datalayout = "e-p:64:64:64-p1:16:16:16-p2:32:32:32-p3:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-z0:1-z2:neg1-z3:neg1-z5:neg1"
+
+declare void @usei8ptr(ptr %ptr)
+
+; Ensure that we do not crash when looking at such a weird bitcast.
+define i1 @bitcast_from_single_element_pointer_vector_to_pointer(<1 x ptr> %ptr1vec, ptr %ptr2) {
+; CHECK-LABEL: @bitcast_from_single_element_pointer_vector_to_pointer(
+; CHECK-NEXT:    [[PTR1:%.*]] = bitcast <1 x ptr> [[PTR1VEC:%.*]] to ptr
+; CHECK-NEXT:    call void @usei8ptr(ptr [[PTR1]])
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[PTR1]], [[PTR2:%.*]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %ptr1 = bitcast <1 x ptr> %ptr1vec to ptr
+  call void @usei8ptr(ptr %ptr1)
+  %cmp = icmp eq ptr %ptr1, %ptr2
+  ret i1 %cmp
+}
+
+define i1 @poison(i32 %x) {
+; CHECK-LABEL: @poison(
+; CHECK-NEXT:    ret i1 poison
+;
+  %v = icmp eq i32 %x, poison
+  ret i1 %v
+}
+
+define i1 @poison2(i32 %x) {
+; CHECK-LABEL: @poison2(
+; CHECK-NEXT:    ret i1 poison
+;
+  %v = icmp slt i32 %x, poison
+  ret i1 %v
+}
+
+define i1 @mul_div_cmp_smaller(i8 %x) {
+; CHECK-LABEL: @mul_div_cmp_smaller(
+; CHECK-NEXT:    ret i1 true
+;
+  %mul = mul i8 %x, 3
+  %div = udiv i8 %mul, 4
+  %cmp = icmp ule i8 %div, %x
+  ret i1 %cmp
+}
+
+define i1 @mul_div_cmp_equal(i8 %x) {
+; CHECK-LABEL: @mul_div_cmp_equal(
+; CHECK-NEXT:    ret i1 true
+;
+  %mul = mul i8 %x, 3
+  %div = udiv i8 %mul, 3
+  %cmp = icmp ule i8 %div, %x
+  ret i1 %cmp
+}
+
+; Negative test: 3>2
+define i1 @mul_div_cmp_greater(i8 %x) {
+; CHECK-LABEL: @mul_div_cmp_greater(
+; CHECK-NEXT:    [[MUL:%.*]] = mul i8 [[X:%.*]], 3
+; CHECK-NEXT:    [[DIV:%.*]] = udiv i8 [[MUL]], 2
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ule i8 [[DIV]], [[X]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %mul = mul i8 %x, 3
+  %div = udiv i8 %mul, 2
+  %cmp = icmp ule i8 %div, %x
+  ret i1 %cmp
+}
+define i1 @mul_div_cmp_ugt(i8 %x) {
+; CHECK-LABEL: @mul_div_cmp_ugt(
+; CHECK-NEXT:    ret i1 false
+;
+  %mul = mul i8 %x, 3
+  %div = udiv i8 %mul, 4
+  %cmp = icmp ugt i8 %div, %x
+  ret i1 %cmp
+}
+
+; Negative test: Wrong predicate
+define i1 @mul_div_cmp_uge(i8 %x) {
+; CHECK-LABEL: @mul_div_cmp_uge(
+; CHECK-NEXT:    [[MUL:%.*]] = mul i8 [[X:%.*]], 3
+; CHECK-NEXT:    [[DIV:%.*]] = udiv i8 [[MUL]], 4
+; CHECK-NEXT:    [[CMP:%.*]] = icmp uge i8 [[DIV]], [[X]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %mul = mul i8 %x, 3
+  %div = udiv i8 %mul, 4
+  %cmp = icmp uge i8 %div, %x
+  ret i1 %cmp
+}
+
+; Negative test: Wrong predicate
+define i1 @mul_div_cmp_ult(i8 %x) {
+; CHECK-LABEL: @mul_div_cmp_ult(
+; CHECK-NEXT:    [[MUL:%.*]] = mul i8 [[X:%.*]], 3
+; CHECK-NEXT:    [[DIV:%.*]] = udiv i8 [[MUL]], 4
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i8 [[DIV]], [[X]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %mul = mul i8 %x, 3
+  %div = udiv i8 %mul, 4
+  %cmp = icmp ult i8 %div, %x
+  ret i1 %cmp
+}
+
+; Negative test: Wrong icmp operand
+define i1 @mul_div_cmp_wrong_operand(i8 %x, i8 %y) {
+; CHECK-LABEL: @mul_div_cmp_wrong_operand(
+; CHECK-NEXT:    [[MUL:%.*]] = mul i8 [[X:%.*]], 3
+; CHECK-NEXT:    [[DIV:%.*]] = udiv i8 [[MUL]], 4
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ule i8 [[DIV]], [[Y:%.*]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %mul = mul i8 %x, 3
+  %div = udiv i8 %mul, 4
+  %cmp = icmp ule i8 %div, %y
+  ret i1 %cmp
+}
+
+define i1 @mul_lshr_cmp_smaller(i8 %x) {
+; CHECK-LABEL: @mul_lshr_cmp_smaller(
+; CHECK-NEXT:    ret i1 true
+;
+  %mul = mul i8 %x, 3
+  %div = lshr i8 %mul, 2
+  %cmp = icmp ule i8 %div, %x
+  ret i1 %cmp
+}
+
+define i1 @mul_lshr_cmp_equal(i8 %x) {
+; CHECK-LABEL: @mul_lshr_cmp_equal(
+; CHECK-NEXT:    ret i1 true
+;
+  %mul = mul i8 %x, 4
+  %div = lshr i8 %mul, 2
+  %cmp = icmp ule i8 %div, %x
+  ret i1 %cmp
+}
+
+define i1 @mul_lshr_cmp_greater(i8 %x) {
+; CHECK-LABEL: @mul_lshr_cmp_greater(
+; CHECK-NEXT:    [[MUL:%.*]] = mul i8 [[X:%.*]], 5
+; CHECK-NEXT:    [[DIV:%.*]] = lshr i8 [[MUL]], 2
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ule i8 [[DIV]], [[X]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %mul = mul i8 %x, 5
+  %div = lshr i8 %mul, 2
+  %cmp = icmp ule i8 %div, %x
+  ret i1 %cmp
+}
+
+define i1 @shl_div_cmp_smaller(i8 %x) {
+; CHECK-LABEL: @shl_div_cmp_smaller(
+; CHECK-NEXT:    ret i1 true
+;
+  %mul = shl i8 %x, 2
+  %div = udiv i8 %mul, 5
+  %cmp = icmp ule i8 %div, %x
+  ret i1 %cmp
+}
+
+define i1 @shl_div_cmp_equal(i8 %x) {
+; CHECK-LABEL: @shl_div_cmp_equal(
+; CHECK-NEXT:    ret i1 true
+;
+  %mul = shl i8 %x, 2
+  %div = udiv i8 %mul, 4
+  %cmp = icmp ule i8 %div, %x
+  ret i1 %cmp
+}
+
+define i1 @shl_div_cmp_greater(i8 %x) {
+; CHECK-LABEL: @shl_div_cmp_greater(
+; CHECK-NEXT:    [[MUL:%.*]] = shl i8 [[X:%.*]], 2
+; CHECK-NEXT:    [[DIV:%.*]] = udiv i8 [[MUL]], 3
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ule i8 [[DIV]], [[X]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %mul = shl i8 %x, 2
+  %div = udiv i8 %mul, 3
+  %cmp = icmp ule i8 %div, %x
+  ret i1 %cmp
+}
+
+; Don't crash matching recurrences/invertible ops.
+
+define void @PR50191(i32 %x) {
+; CHECK-LABEL: @PR50191(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[LOOP:%.*]]
+; CHECK:       loop:
+; CHECK-NEXT:    [[P1:%.*]] = phi i32 [ [[X:%.*]], [[ENTRY:%.*]] ], [ [[SUB1:%.*]], [[LOOP]] ]
+; CHECK-NEXT:    [[P2:%.*]] = phi i32 [ [[X]], [[ENTRY]] ], [ [[SUB2:%.*]], [[LOOP]] ]
+; CHECK-NEXT:    [[SUB1]] = sub i32 [[P1]], [[P2]]
+; CHECK-NEXT:    [[SUB2]] = sub i32 42, [[P2]]
+; CHECK-NEXT:    br label [[LOOP]]
+;
+entry:
+  br label %loop
+
+loop:
+  %p1 = phi i32 [ %x, %entry ], [ %sub1, %loop ]
+  %p2 = phi i32 [ %x, %entry ], [ %sub2, %loop ]
+  %cmp = icmp eq i32 %p1, %p2
+  %user = zext i1 %cmp to i32
+  %sub1 = sub i32 %p1, %p2
+  %sub2 = sub i32 42, %p2
+  br label %loop
+}
+
+define i1 @sub_false(i32 %x) {
+; CHECK-LABEL: @sub_false(
+; CHECK-NEXT:    ret i1 false
+;
+  %sub = sub i32 1, %x
+  %cmp = icmp eq i32 %sub, %x
+  ret i1 %cmp
+}
+
+define i1 @sub_swap(i8 %x) {
+; CHECK-LABEL: @sub_swap(
+; CHECK-NEXT:    ret i1 true
+;
+  %sub = sub i8 3, %x
+  %cmp = icmp ne i8 %x, %sub
+  ret i1 %cmp
+}
+
+define <2 x i1> @sub_odd(<2 x i8> %x) {
+; CHECK-LABEL: @sub_odd(
+; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
+;
+  %sub = sub <2 x i8> <i8 3, i8 3>, %x
+  %cmp = icmp ne <2 x i8> %sub, %x
+  ret <2 x i1> %cmp
+}
+
+define <2 x i1> @sub_odd_poison(<2 x i8> %x) {
+; CHECK-LABEL: @sub_odd_poison(
+; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
+;
+  %sub = sub <2 x i8> <i8 poison, i8 1>, %x
+  %cmp = icmp ne <2 x i8> %sub, %x
+  ret <2 x i1> %cmp
+}
+
+define i1 @sub_even(i8 %x) {
+; CHECK-LABEL: @sub_even(
+; CHECK-NEXT:    [[SUB:%.*]] = sub i8 2, [[X:%.*]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i8 [[SUB]], [[X]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %sub = sub i8 2, %x
+  %cmp = icmp ne i8 %sub, %x
+  ret i1 %cmp
+}
+
+define i1 @load_ptr(ptr %p) {
+; CHECK-LABEL: @load_ptr(
+; CHECK-NEXT:    ret i1 true
+;
+  %load_p = load ptr, ptr %p, !dereferenceable !{i64 8}
+  %r = icmp ne ptr %load_p, null
+  ret i1 %r
+}
+
+define i1 @load_ptr_null_valid(ptr %p) null_pointer_is_valid {
+; CHECK-LABEL: @load_ptr_null_valid(
+; CHECK-NEXT:    ret i1 true
+;
+  %load_p = load ptr, ptr %p, !dereferenceable !{i64 8}
+  %r = icmp ne ptr %load_p, null
+  ret i1 %r
+}
+
+define i1 @non_eq_disjoint_or_common_op(i8 %x, i8 %y, i8 %ww, i8 %a) {
+; CHECK-LABEL: @non_eq_disjoint_or_common_op(
+; CHECK-NEXT:    ret i1 false
+;
+  %w = add nuw i8 %ww, 1
+  %z = add i8 %y, %w
+
+  %xy = or disjoint i8 %x, %y
+  %xz = or disjoint i8 %x, %z
+
+  %axy = add i8 %a, %xy
+  %axz = add i8 %a, %xz
+  %r = icmp eq i8 %axy, %axz
+  ret i1 %r
+}
+
+define i1 @non_eq_disjoint_or_common_op_fail(i8 %x, i8 %y, i8 %ww, i8 %a) {
+; CHECK-LABEL: @non_eq_disjoint_or_common_op_fail(
+; CHECK-NEXT:    [[W:%.*]] = add nuw i8 [[WW:%.*]], 1
+; CHECK-NEXT:    [[Z:%.*]] = add i8 [[Y:%.*]], [[W]]
+; CHECK-NEXT:    [[XY:%.*]] = or i8 [[X:%.*]], [[Y]]
+; CHECK-NEXT:    [[XZ:%.*]] = or disjoint i8 [[X]], [[Z]]
+; CHECK-NEXT:    [[AXY:%.*]] = add i8 [[A:%.*]], [[XY]]
+; CHECK-NEXT:    [[AXZ:%.*]] = add i8 [[A]], [[XZ]]
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[AXY]], [[AXZ]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %w = add nuw i8 %ww, 1
+  %z = add i8 %y, %w
+
+  %xy = or i8 %x, %y
+  %xz = or disjoint i8 %x, %z
+
+  %axy = add i8 %a, %xy
+  %axz = add i8 %a, %xz
+  %r = icmp eq i8 %axy, %axz
+  ret i1 %r
+}
+
+define i1 @non_eq_xor_common_op(i8 %x, i8 %y, i8 %ww, i8 %a) {
+; CHECK-LABEL: @non_eq_xor_common_op(
+; CHECK-NEXT:    ret i1 false
+;
+  %w = add nuw i8 %ww, 1
+  %z = add i8 %y, %w
+
+  %xy = xor i8 %y, %x
+  %xz = xor i8 %x, %z
+
+  %axy = add i8 %a, %xy
+  %axz = add i8 %a, %xz
+  %r = icmp eq i8 %axy, %axz
+  ret i1 %r
+}
+
+define i1 @non_eq_xor_common_op_fail(i8 %x, i8 %y, i8 %ww, i8 %a) {
+; CHECK-LABEL: @non_eq_xor_common_op_fail(
+; CHECK-NEXT:    [[W:%.*]] = add nsw i8 [[WW:%.*]], 1
+; CHECK-NEXT:    [[Z:%.*]] = add i8 [[Y:%.*]], [[W]]
+; CHECK-NEXT:    [[XY:%.*]] = xor i8 [[Y]], [[X:%.*]]
+; CHECK-NEXT:    [[XZ:%.*]] = xor i8 [[X]], [[Z]]
+; CHECK-NEXT:    [[AXY:%.*]] = add i8 [[A:%.*]], [[XY]]
+; CHECK-NEXT:    [[AXZ:%.*]] = add i8 [[A]], [[XZ]]
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[AXY]], [[AXZ]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %w = add nsw i8 %ww, 1
+  %z = add i8 %y, %w
+
+  %xy = xor i8 %y, %x
+  %xz = xor i8 %x, %z
+
+  %axy = add i8 %a, %xy
+  %axz = add i8 %a, %xz
+  %r = icmp eq i8 %axy, %axz
+  ret i1 %r
+}
+
+define i1 @non_eq_disjoint_or(i8 %x, i8 %yy, i8 %w) {
+; CHECK-LABEL: @non_eq_disjoint_or(
+; CHECK-NEXT:    ret i1 false
+;
+  %y = add nuw i8 %yy, 1
+  %lhs = add i8 %x, %w
+  %val = or disjoint i8 %y, %w
+  %rhs = add i8 %x, %val
+  %r = icmp eq i8 %lhs, %rhs
+  ret i1 %r
+}
+
+define i1 @non_eq_or_fail(i8 %x, i8 %yy, i8 %w) {
+; CHECK-LABEL: @non_eq_or_fail(
+; CHECK-NEXT:    [[Y:%.*]] = add nuw i8 [[YY:%.*]], 1
+; CHECK-NEXT:    [[LHS:%.*]] = add i8 [[X:%.*]], [[W:%.*]]
+; CHECK-NEXT:    [[VAL:%.*]] = or i8 [[Y]], [[W]]
+; CHECK-NEXT:    [[RHS:%.*]] = add i8 [[X]], [[VAL]]
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[LHS]], [[RHS]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %y = add nuw i8 %yy, 1
+  %lhs = add i8 %x, %w
+  %val = or i8 %y, %w
+  %rhs = add i8 %x, %val
+  %r = icmp eq i8 %lhs, %rhs
+  ret i1 %r
+}
+
+define i1 @non_eq_xor(i8 %x, i8 %yy, i8 %w) {
+; CHECK-LABEL: @non_eq_xor(
+; CHECK-NEXT:    ret i1 false
+;
+  %y = add nuw i8 %yy, 1
+  %lhs = add i8 %x, %w
+  %val = xor i8 %y, %w
+  %rhs = add i8 %x, %val
+  %r = icmp eq i8 %lhs, %rhs
+  ret i1 %r
+}
+
+define i1 @non_eq_xor_fail(i8 %x, i8 %yy, i8 %w) {
+; CHECK-LABEL: @non_eq_xor_fail(
+; CHECK-NEXT:    [[Y:%.*]] = add nsw i8 [[YY:%.*]], 1
+; CHECK-NEXT:    [[LHS:%.*]] = add i8 [[X:%.*]], [[W:%.*]]
+; CHECK-NEXT:    [[VAL:%.*]] = xor i8 [[Y]], [[W]]
+; CHECK-NEXT:    [[RHS:%.*]] = add i8 [[X]], [[VAL]]
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[LHS]], [[RHS]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %y = add nsw i8 %yy, 1
+  %lhs = add i8 %x, %w
+  %val = xor i8 %y, %w
+  %rhs = add i8 %x, %val
+  %r = icmp eq i8 %lhs, %rhs
+  ret i1 %r
+}
diff --git a/llvm/test/Transforms/InstSimplify/null-ptr-is-valid-dl-sentinel.ll b/llvm/test/Transforms/InstSimplify/null-ptr-is-valid-dl-sentinel.ll
new file mode 100755
index 0000000000000..e66ea08eaca36
--- /dev/null
+++ b/llvm/test/Transforms/InstSimplify/null-ptr-is-valid-dl-sentinel.ll
@@ -0,0 +1,23 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -passes=instsimplify < %s | FileCheck %s
+
+target datalayout = "A5-z0:1-z2:neg1-z3:neg1-z5:neg1"
+
+; A 0 valued byval pointer may be valid
+define i1 @byval_may_be_zero(ptr addrspace(5) byval(i32) %ptr) {
+; CHECK-LABEL: @byval_may_be_zero(
+; CHECK-NEXT:    ret i1 false
+;
+  %cmp = icmp eq ptr addrspace(5) %ptr, null
+  ret i1 %cmp
+}
+
+; FIXME: The interpretation of nonnull assumes a 0 pointer value, so
+; this really is an incorrect fold.
+define i1 @nonnull_may_be_zero(ptr addrspace(5) nonnull %ptr) {
+; CHECK-LABEL: @nonnull_may_be_zero(
+; CHECK-NEXT:    ret i1 false
+;
+  %cmp = icmp eq ptr addrspace(5) %ptr, null
+  ret i1 %cmp
+}

>From 6425e333280380ac609388340416ae523f719489 Mon Sep 17 00:00:00 2001
From: Rana Pratap Reddy N <RanaPratapReddy.Nimmakayala at amd.com>
Date: Fri, 17 May 2024 14:49:42 +0530
Subject: [PATCH 2/2] Updated the tests with and without datalayout string

---
 llvm/lib/Analysis/ValueTracking.cpp           |    6 +-
 .../ArgumentPromotion/array-dl-sentinel.ll    |   56 -
 .../IPConstantProp/pthreads-dl-sentinel.ll    |   83 +-
 .../Attributor/callbacks-dl-sentinel.ll       |  321 --
 .../Attributor/nocapture-2-dl-sentinel.ll     |  868 +----
 .../Attributor/nofree-dl-sentinel.ll          |  482 +--
 ...rite_returned_arguments_scc-dl-sentinel.ll |  364 +-
 .../Attributor/returned-dl-sentinel.ll        | 1242 +++----
 .../Attributor/value-simplify-dl-sentinel.ll  | 1748 +--------
 .../alloca-cast-debuginfo-dl-sentinel.ll      |   88 -
 .../alloca-in-non-alloca-as-sentinel.ll       |   71 +-
 .../InstCombine/assume-dl-sentinel.ll         |  908 +----
 .../assume-icmp-null-select-dl-sentinel.ll    |   28 +-
 .../InstSimplify/compare-dl-sentinel.ll       | 3260 +----------------
 .../InstSimplify/icmp-dl-sentinel.ll          |  413 +--
 .../null-ptr-is-valid-dl-sentinel.ll          |   75 +-
 16 files changed, 1461 insertions(+), 8552 deletions(-)
 delete mode 100755 llvm/test/Transforms/Attributor/ArgumentPromotion/array-dl-sentinel.ll
 delete mode 100755 llvm/test/Transforms/Attributor/callbacks-dl-sentinel.ll
 delete mode 100755 llvm/test/Transforms/InstCombine/alloca-cast-debuginfo-dl-sentinel.ll

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 51ad01219c6e2..d890ae83d1949 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -3099,12 +3099,10 @@ bool isKnownNonZero(const Value *V, const APInt &DemandedElts,
 
   if (PointerType *PtrTy = dyn_cast<PointerType>(Ty)) {
     const DataLayout &DL = Q.DL;
-    if (DL.isSentinelValueDefined() && PtrTy) {
+    if (DL.isSentinelValueDefined()) {
       unsigned AddrSpace = PtrTy->getPointerAddressSpace();
 
-      if (DL.getSentinelPointerValue(AddrSpace) == 0)
-        return false;
-      return true;
+      return (DL.getSentinelPointerValue(AddrSpace) != 0);
     }
 
     // A byval, inalloca may not be null in a non-default addres space. A
diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/array-dl-sentinel.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/array-dl-sentinel.ll
deleted file mode 100755
index 1f6ee8bbc348a..0000000000000
--- a/llvm/test/Transforms/Attributor/ArgumentPromotion/array-dl-sentinel.ll
+++ /dev/null
@@ -1,56 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
-target datalayout = "e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32-p7:160:256:256:32-p8:128:128-p9:192:256:256:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-z0:1-z2:neg1-z3:neg1-z5:neg1-S32-A5-G1-ni:7:8:9"
-; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal  -attributor-annotate-decl-cs  -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
-; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal  -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
-;
-; FIXME: The GEP + BC + GEP solution we create is not great but correct.
-
-declare void @use(ptr nocapture readonly %arg)
-
-define void @caller() {
-; TUNIT-LABEL: define {{[^@]+}}@caller() {
-; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    [[LEFT:%.*]] = alloca [3 x i32], align 4
-; TUNIT-NEXT:    [[TMP0:%.*]] = load i32, ptr [[LEFT]], align 4
-; TUNIT-NEXT:    [[LEFT_B4:%.*]] = getelementptr i8, ptr [[LEFT]], i64 4
-; TUNIT-NEXT:    [[TMP1:%.*]] = load i32, ptr [[LEFT_B4]], align 4
-; TUNIT-NEXT:    [[LEFT_B8:%.*]] = getelementptr i8, ptr [[LEFT]], i64 8
-; TUNIT-NEXT:    [[TMP2:%.*]] = load i32, ptr [[LEFT_B8]], align 4
-; TUNIT-NEXT:    call void @callee(i32 [[TMP0]], i32 [[TMP1]], i32 [[TMP2]])
-; TUNIT-NEXT:    ret void
-;
-; CGSCC-LABEL: define {{[^@]+}}@caller() {
-; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    call void @callee(i32 undef, i32 undef, i32 undef)
-; CGSCC-NEXT:    ret void
-;
-entry:
-  %left = alloca [3 x i32], align 4
-  call void @callee(ptr %left)
-  ret void
-}
-
-define internal void @callee(ptr noalias %arg) {
-; CHECK: Function Attrs: memory(readwrite, argmem: none)
-; CHECK-LABEL: define {{[^@]+}}@callee
-; CHECK-SAME: (i32 [[TMP0:%.*]], i32 [[TMP1:%.*]], i32 [[TMP2:%.*]]) #[[ATTR0:[0-9]+]] {
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[ARG_PRIV:%.*]] = alloca [3 x i32], align 4, addrspace(5)
-; CHECK-NEXT:    store i32 [[TMP0]], ptr addrspace(5) [[ARG_PRIV]], align 4
-; CHECK-NEXT:    [[ARG_PRIV_B4:%.*]] = getelementptr i8, ptr addrspace(5) [[ARG_PRIV]], i64 4
-; CHECK-NEXT:    store i32 [[TMP1]], ptr addrspace(5) [[ARG_PRIV_B4]], align 4
-; CHECK-NEXT:    [[ARG_PRIV_B8:%.*]] = getelementptr i8, ptr addrspace(5) [[ARG_PRIV]], i64 8
-; CHECK-NEXT:    store i32 [[TMP2]], ptr addrspace(5) [[ARG_PRIV_B8]], align 4
-; CHECK-NEXT:    [[TMP3:%.*]] = addrspacecast ptr addrspace(5) [[ARG_PRIV]] to ptr
-; CHECK-NEXT:    call void @use(ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(12) [[TMP3]])
-; CHECK-NEXT:    ret void
-;
-entry:
-  call void @use(ptr %arg)
-  ret void
-}
-;.
-; TUNIT: attributes #[[ATTR0]] = { memory(readwrite, argmem: none) }
-;.
-; CGSCC: attributes #[[ATTR0]] = { memory(readwrite, argmem: none) }
-;.
diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/pthreads-dl-sentinel.ll b/llvm/test/Transforms/Attributor/IPConstantProp/pthreads-dl-sentinel.ll
index b93017bd58986..da05e40e09f5d 100755
--- a/llvm/test/Transforms/Attributor/IPConstantProp/pthreads-dl-sentinel.ll
+++ b/llvm/test/Transforms/Attributor/IPConstantProp/pthreads-dl-sentinel.ll
@@ -1,6 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
-; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal  -attributor-annotate-decl-cs  -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
 ; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal  -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal  -attributor-annotate-decl-cs -data-layout=z0:1-z2:neg1-z3:neg1-z5:neg1 -S < %s | FileCheck %s --check-prefixes=CHECK-DL,CGSCC-DL
 ;
 ;    #include <pthread.h>
 ;
@@ -19,7 +19,6 @@
 ; Verify the constant values NULL and &GlobalVPtr are propagated into foo and
 ; bar, respectively.
 ;
-target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-z0:1-z2:neg1-z3:neg1-z5:neg1-S128"
 
 %union.pthread_attr_t = type { i64, [48 x i8] }
 
@@ -31,24 +30,26 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-z0:1-z2:neg1-z3:neg1-z5:ne
 ;.
 ; CHECK: @GlobalVPtr = common dso_local global ptr null, align 8
 ;.
+; CHECK-DL: @GlobalVPtr = common dso_local global ptr null, align 8
+;.
 define dso_local i32 @main() {
-; TUNIT-LABEL: define {{[^@]+}}@main() {
-; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    [[ALLOC11:%.*]] = alloca i8, i32 0, align 8
-; TUNIT-NEXT:    [[ALLOC22:%.*]] = alloca i8, i32 0, align 8
-; TUNIT-NEXT:    [[THREAD:%.*]] = alloca i64, align 8
-; TUNIT-NEXT:    [[CALL:%.*]] = call i32 @pthread_create(ptr noundef nonnull align 8 dereferenceable(8) [[THREAD]], ptr noundef align 4294967296 null, ptr noundef nonnull @foo, ptr nofree readnone align 4294967296 undef)
-; TUNIT-NEXT:    [[CALL1:%.*]] = call i32 @pthread_create(ptr noundef nonnull align 8 dereferenceable(8) [[THREAD]], ptr noundef align 4294967296 null, ptr noundef nonnull @bar, ptr noalias nocapture nofree nonnull readnone align 8 dereferenceable(8) undef)
-; TUNIT-NEXT:    [[CALL2:%.*]] = call i32 @pthread_create(ptr noundef nonnull align 8 dereferenceable(8) [[THREAD]], ptr noundef align 4294967296 null, ptr noundef nonnull @baz, ptr noalias nocapture nofree noundef nonnull readnone align 8 dereferenceable(1) [[ALLOC11]])
-; TUNIT-NEXT:    [[CALL3:%.*]] = call i32 @pthread_create(ptr noundef nonnull align 8 dereferenceable(8) [[THREAD]], ptr noundef align 4294967296 null, ptr noundef nonnull @buz, ptr noalias nofree noundef nonnull readnone align 8 dereferenceable(1) "no-capture-maybe-returned" [[ALLOC22]])
-; TUNIT-NEXT:    ret i32 0
-;
-; CGSCC-LABEL: define {{[^@]+}}@main() {
-; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    [[ALLOC1:%.*]] = alloca i8, align 8
-; CGSCC-NEXT:    [[ALLOC2:%.*]] = alloca i8, align 8
-; CGSCC-NEXT:    [[THREAD:%.*]] = alloca i64, align 8
-; CGSCC-NEXT:    unreachable
+; CHECK-LABEL: define {{[^@]+}}@main() {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[ALLOC1:%.*]] = alloca i8, align 8
+; CHECK-NEXT:    [[ALLOC2:%.*]] = alloca i8, align 8
+; CHECK-NEXT:    [[THREAD:%.*]] = alloca i64, align 8
+; CHECK-NEXT:    [[CALL:%.*]] = call i32 @pthread_create(ptr noundef nonnull align 8 dereferenceable(8) [[THREAD]], ptr noundef align 4294967296 null, ptr noundef nonnull @foo, ptr nofree noundef readnone align 4294967296 null)
+; CHECK-NEXT:    [[CALL1:%.*]] = call i32 @pthread_create(ptr noundef nonnull align 8 dereferenceable(8) [[THREAD]], ptr noundef align 4294967296 null, ptr noundef nonnull @bar, ptr noalias nocapture nofree noundef nonnull readnone align 8 dereferenceable(8) @GlobalVPtr)
+; CHECK-NEXT:    [[CALL2:%.*]] = call i32 @pthread_create(ptr noundef nonnull align 8 dereferenceable(8) [[THREAD]], ptr noundef align 4294967296 null, ptr noundef nonnull @baz, ptr noalias nocapture nofree noundef nonnull readnone align 8 dereferenceable(1) [[ALLOC1]])
+; CHECK-NEXT:    [[CALL3:%.*]] = call i32 @pthread_create(ptr noundef nonnull align 8 dereferenceable(8) [[THREAD]], ptr noundef align 4294967296 null, ptr noundef nonnull @buz, ptr noalias nofree noundef nonnull readnone align 8 dereferenceable(1) [[ALLOC2]])
+; CHECK-NEXT:    ret i32 0
+;
+; CHECK-DL-LABEL: define {{[^@]+}}@main() {
+; CHECK-DL-NEXT:  entry:
+; CHECK-DL-NEXT:    [[ALLOC1:%.*]] = alloca i8, align 8
+; CHECK-DL-NEXT:    [[ALLOC2:%.*]] = alloca i8, align 8
+; CHECK-DL-NEXT:    [[THREAD:%.*]] = alloca i64, align 8
+; CHECK-DL-NEXT:    unreachable
 ;
 entry:
   %alloc1 = alloca i8, align 8
@@ -66,14 +67,21 @@ declare !callback !0 dso_local i32 @pthread_create(ptr, ptr, ptr, ptr)
 define internal ptr @foo(ptr %arg) {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
 ; CHECK-LABEL: define {{[^@]+}}@foo
-; CHECK-SAME: (ptr noalias nocapture nofree nonnull readnone align 4294967296 [[ARG:%.*]]) #[[ATTR0:[0-9]+]] {
+; CHECK-SAME: (ptr noalias nocapture nofree readnone align 4294967296 [[ARG:%.*]]) #[[ATTR0:[0-9]+]] {
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    unreachable
+; CHECK-NEXT:    ret ptr null
+;
+; CHECK-DL: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CHECK-DL-LABEL: define {{[^@]+}}@foo
+; CHECK-DL-SAME: (ptr noalias nocapture nofree nonnull readnone align 4294967296 [[ARG:%.*]]) #[[ATTR0:[0-9]+]] {
+; CHECK-DL-NEXT:  entry:
+; CHECK-DL-NEXT:    unreachable
 ;
 entry:
   ret ptr %arg
 }
 
+
 define internal ptr @bar(ptr %arg) {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
 ; CHECK-LABEL: define {{[^@]+}}@bar
@@ -81,6 +89,12 @@ define internal ptr @bar(ptr %arg) {
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    ret ptr @GlobalVPtr
 ;
+; CHECK-DL: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CHECK-DL-LABEL: define {{[^@]+}}@bar
+; CHECK-DL-SAME: (ptr noalias nocapture nofree nonnull readnone align 8 dereferenceable(8) [[ARG:%.*]]) #[[ATTR0]] {
+; CHECK-DL-NEXT:  entry:
+; CHECK-DL-NEXT:    ret ptr @GlobalVPtr
+;
 entry:
   ret ptr %arg
 }
@@ -92,6 +106,12 @@ define internal ptr @baz(ptr %arg) {
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    ret ptr [[ARG]]
 ;
+; CHECK-DL: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CHECK-DL-LABEL: define {{[^@]+}}@baz
+; CHECK-DL-SAME: (ptr noalias nofree noundef nonnull readnone returned align 8 dereferenceable(1) "no-capture-maybe-returned" [[ARG:%.*]]) #[[ATTR0]] {
+; CHECK-DL-NEXT:  entry:
+; CHECK-DL-NEXT:    ret ptr [[ARG]]
+;
 entry:
   ret ptr %arg
 }
@@ -103,6 +123,12 @@ define internal ptr @buz(ptr %arg) {
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    ret ptr [[ARG]]
 ;
+; CHECK-DL: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CHECK-DL-LABEL: define {{[^@]+}}@buz
+; CHECK-DL-SAME: (ptr noalias nofree noundef nonnull readnone returned align 8 dereferenceable(1) "no-capture-maybe-returned" [[ARG:%.*]]) #[[ATTR0]] {
+; CHECK-DL-NEXT:  entry:
+; CHECK-DL-NEXT:    ret ptr [[ARG]]
+;
 entry:
   ret ptr %arg
 }
@@ -110,13 +136,16 @@ entry:
 !1 = !{i64 2, i64 3, i1 false}
 !0 = !{!1}
 ;.
-; TUNIT: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
+; CHECK: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
 ;.
-; CGSCC: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
+; CHECK-DL: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
 ;.
-; TUNIT: [[META0:![0-9]+]] = !{[[META1:![0-9]+]]}
-; TUNIT: [[META1]] = !{i64 2, i64 3, i1 false}
+; CHECK: [[META0:![0-9]+]] = !{[[META1:![0-9]+]]}
+; CHECK: [[META1]] = !{i64 2, i64 3, i1 false}
 ;.
-; CGSCC: [[META0:![0-9]+]] = !{[[META1:![0-9]+]]}
-; CGSCC: [[META1]] = !{i64 2, i64 3, i1 false}
+; CHECK-DL: [[META0:![0-9]+]] = !{[[META1:![0-9]+]]}
+; CHECK-DL: [[META1]] = !{i64 2, i64 3, i1 false}
 ;.
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CGSCC: {{.*}}
+; CGSCC-DL: {{.*}}
diff --git a/llvm/test/Transforms/Attributor/callbacks-dl-sentinel.ll b/llvm/test/Transforms/Attributor/callbacks-dl-sentinel.ll
deleted file mode 100755
index 1e66ba25f166a..0000000000000
--- a/llvm/test/Transforms/Attributor/callbacks-dl-sentinel.ll
+++ /dev/null
@@ -1,321 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
-; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal  -attributor-annotate-decl-cs  -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
-; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal  -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
-
-target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-z0:1-z2:neg1-z3:neg1-z5:neg1-S128"
-
-; Test 0
-;
-; Make sure we propagate information from the caller to the callback callee but
-; only for arguments that are mapped through the callback metadata. Here, the
-; first two arguments of the call and the callback callee do not correspond to
-; each other but argument 3-5 of the transitive call site in the caller match
-; arguments 2-4 of the callback callee. Here we should see information and value
-; transfer in both directions.
-
-define void @t0_caller(ptr %a) {
-; TUNIT-LABEL: define {{[^@]+}}@t0_caller
-; TUNIT-SAME: (ptr nonnull align 256 [[A:%.*]]) {
-; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    [[B:%.*]] = alloca i32, align 32
-; TUNIT-NEXT:    [[C:%.*]] = alloca ptr, align 64
-; TUNIT-NEXT:    [[PTR:%.*]] = alloca i32, align 128
-; TUNIT-NEXT:    store i32 42, ptr [[B]], align 32
-; TUNIT-NEXT:    store ptr [[B]], ptr [[C]], align 64
-; TUNIT-NEXT:    call void (ptr, ptr, ptr, ...) @t0_callback_broker(ptr noundef align 4294967296 null, ptr noundef nonnull align 128 dereferenceable(4) [[PTR]], ptr noundef nonnull @t0_callback_callee, ptr nonnull align 256 [[A]], i64 undef, ptr noalias nocapture nofree noundef nonnull readonly align 64 dereferenceable(8) [[C]])
-; TUNIT-NEXT:    ret void
-;
-; CGSCC-LABEL: define {{[^@]+}}@t0_caller
-; CGSCC-SAME: (ptr nonnull align 256 [[A:%.*]]) {
-; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    [[B:%.*]] = alloca i32, align 32
-; CGSCC-NEXT:    [[C:%.*]] = alloca ptr, align 64
-; CGSCC-NEXT:    [[PTR:%.*]] = alloca i32, align 128
-; CGSCC-NEXT:    store i32 42, ptr [[B]], align 32
-; CGSCC-NEXT:    store ptr [[B]], ptr [[C]], align 64
-; CGSCC-NEXT:    call void (ptr, ptr, ptr, ...) @t0_callback_broker(ptr noundef align 4294967296 null, ptr noundef nonnull align 128 dereferenceable(4) [[PTR]], ptr noundef nonnull @t0_callback_callee, ptr nonnull align 256 [[A]], i64 noundef 99, ptr noalias nocapture nofree noundef nonnull readonly align 64 dereferenceable(8) [[C]])
-; CGSCC-NEXT:    ret void
-;
-entry:
-  %b = alloca i32, align 32
-  %c = alloca ptr, align 64
-  %ptr = alloca i32, align 128
-  store i32 42, ptr %b, align 4
-  store ptr %b, ptr %c, align 8
-  call void (ptr, ptr, ptr, ...) @t0_callback_broker(ptr null, ptr %ptr, ptr @t0_callback_callee, ptr %a, i64 99, ptr %c)
-  ret void
-}
-
-; Note that the first two arguments are provided by the callback_broker according to the callback in !1 below!
-; The others are annotated with alignment information, amongst others, or even replaced by the constants passed to the call.
-define internal void @t0_callback_callee(ptr %is_not_null, ptr %ptr, ptr %a, i64 %b, ptr %c) {
-;
-; TUNIT-LABEL: define {{[^@]+}}@t0_callback_callee
-; TUNIT-SAME: (ptr nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], ptr nocapture nofree noundef nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], ptr nonnull align 256 [[A:%.*]], i64 [[B:%.*]], ptr noalias nocapture nofree noundef nonnull readonly align 64 dereferenceable(8) [[C:%.*]]) {
-; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    [[PTR_VAL:%.*]] = load i32, ptr [[PTR]], align 8
-; TUNIT-NEXT:    store i32 [[PTR_VAL]], ptr [[IS_NOT_NULL]], align 4
-; TUNIT-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[C]], align 64
-; TUNIT-NEXT:    tail call void @t0_check(ptr nonnull align 256 [[A]], i64 noundef 99, ptr nonnull align 32 [[TMP0]])
-; TUNIT-NEXT:    ret void
-;
-; CGSCC-LABEL: define {{[^@]+}}@t0_callback_callee
-; CGSCC-SAME: (ptr nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], ptr nocapture nofree noundef nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], ptr nonnull align 256 [[A:%.*]], i64 [[B:%.*]], ptr noalias nocapture nofree noundef nonnull readonly align 64 dereferenceable(8) [[C:%.*]]) {
-; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    [[PTR_VAL:%.*]] = load i32, ptr [[PTR]], align 8
-; CGSCC-NEXT:    store i32 [[PTR_VAL]], ptr [[IS_NOT_NULL]], align 4
-; CGSCC-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[C]], align 64
-; CGSCC-NEXT:    tail call void @t0_check(ptr nonnull align 256 [[A]], i64 noundef 99, ptr nonnull [[TMP0]])
-; CGSCC-NEXT:    ret void
-;
-entry:
-  %ptr_val = load i32, ptr %ptr, align 8
-  store i32 %ptr_val, ptr %is_not_null
-  %0 = load ptr, ptr %c, align 8
-  tail call void @t0_check(ptr %a, i64 %b, ptr %0)
-  ret void
-}
-
-declare void @t0_check(ptr align 256, i64, ptr)
-
-declare !callback !0 void @t0_callback_broker(ptr, ptr, ptr, ...)
-
-; Test 1
-;
-; Similar to test 0 but with some additional annotations (noalias/nocapute) to make sure
-; we deduce and propagate noalias and others properly.
-
-define void @t1_caller(ptr noalias %a) {
-;
-; TUNIT-LABEL: define {{[^@]+}}@t1_caller
-; TUNIT-SAME: (ptr noalias nocapture nonnull align 256 [[A:%.*]]) {
-; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    [[B:%.*]] = alloca i32, align 32
-; TUNIT-NEXT:    [[C:%.*]] = alloca ptr, align 64
-; TUNIT-NEXT:    [[PTR:%.*]] = alloca i32, align 128
-; TUNIT-NEXT:    store i32 42, ptr [[B]], align 32
-; TUNIT-NEXT:    store ptr [[B]], ptr [[C]], align 64
-; TUNIT-NEXT:    call void (ptr, ptr, ptr, ...) @t1_callback_broker(ptr noundef align 4294967296 null, ptr noalias nocapture noundef nonnull align 128 dereferenceable(4) [[PTR]], ptr nocapture noundef nonnull @t1_callback_callee, ptr nocapture nonnull align 256 [[A]], i64 undef, ptr noalias nocapture nofree noundef nonnull readonly align 64 dereferenceable(8) [[C]])
-; TUNIT-NEXT:    ret void
-;
-; CGSCC-LABEL: define {{[^@]+}}@t1_caller
-; CGSCC-SAME: (ptr noalias nocapture nonnull align 256 [[A:%.*]]) {
-; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    [[B:%.*]] = alloca i32, align 32
-; CGSCC-NEXT:    [[C:%.*]] = alloca ptr, align 64
-; CGSCC-NEXT:    [[PTR:%.*]] = alloca i32, align 128
-; CGSCC-NEXT:    store i32 42, ptr [[B]], align 32
-; CGSCC-NEXT:    store ptr [[B]], ptr [[C]], align 64
-; CGSCC-NEXT:    call void (ptr, ptr, ptr, ...) @t1_callback_broker(ptr noundef align 4294967296 null, ptr noalias nocapture noundef nonnull align 128 dereferenceable(4) [[PTR]], ptr nocapture noundef nonnull @t1_callback_callee, ptr nocapture nonnull align 256 [[A]], i64 noundef 99, ptr noalias nocapture nofree noundef nonnull readonly align 64 dereferenceable(8) [[C]])
-; CGSCC-NEXT:    ret void
-;
-entry:
-  %b = alloca i32, align 32
-  %c = alloca ptr, align 64
-  %ptr = alloca i32, align 128
-  store i32 42, ptr %b, align 4
-  store ptr %b, ptr %c, align 8
-  call void (ptr, ptr, ptr, ...) @t1_callback_broker(ptr null, ptr %ptr, ptr @t1_callback_callee, ptr %a, i64 99, ptr %c)
-  ret void
-}
-
-; Note that the first two arguments are provided by the callback_broker according to the callback in !1 below!
-; The others are annotated with alignment information, amongst others, or even replaced by the constants passed to the call.
-define internal void @t1_callback_callee(ptr %is_not_null, ptr %ptr, ptr %a, i64 %b, ptr %c) {
-;
-; TUNIT: Function Attrs: nosync
-; TUNIT-LABEL: define {{[^@]+}}@t1_callback_callee
-; TUNIT-SAME: (ptr nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], ptr nocapture nofree noundef nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], ptr nocapture nonnull align 256 [[A:%.*]], i64 [[B:%.*]], ptr noalias nocapture nofree noundef nonnull readonly align 64 dereferenceable(8) [[C:%.*]]) #[[ATTR0:[0-9]+]] {
-; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    [[PTR_VAL:%.*]] = load i32, ptr [[PTR]], align 8
-; TUNIT-NEXT:    store i32 [[PTR_VAL]], ptr [[IS_NOT_NULL]], align 4
-; TUNIT-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[C]], align 64
-; TUNIT-NEXT:    tail call void @t1_check(ptr nocapture nonnull align 256 [[A]], i64 noundef 99, ptr nocapture nonnull align 32 [[TMP0]])
-; TUNIT-NEXT:    ret void
-;
-; CGSCC: Function Attrs: nosync
-; CGSCC-LABEL: define {{[^@]+}}@t1_callback_callee
-; CGSCC-SAME: (ptr nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], ptr nocapture nofree noundef nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], ptr nocapture nonnull align 256 [[A:%.*]], i64 [[B:%.*]], ptr noalias nocapture nofree noundef nonnull readonly align 64 dereferenceable(8) [[C:%.*]]) #[[ATTR0:[0-9]+]] {
-; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    [[PTR_VAL:%.*]] = load i32, ptr [[PTR]], align 8
-; CGSCC-NEXT:    store i32 [[PTR_VAL]], ptr [[IS_NOT_NULL]], align 4
-; CGSCC-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[C]], align 64
-; CGSCC-NEXT:    tail call void @t1_check(ptr nocapture nonnull align 256 [[A]], i64 noundef 99, ptr nocapture nonnull [[TMP0]])
-; CGSCC-NEXT:    ret void
-;
-entry:
-  %ptr_val = load i32, ptr %ptr, align 8
-  store i32 %ptr_val, ptr %is_not_null
-  %0 = load ptr, ptr %c, align 8
-  tail call void @t1_check(ptr %a, i64 %b, ptr %0)
-  ret void
-}
-
-declare void @t1_check(ptr nocapture align 256, i64, ptr nocapture) nosync
-
-declare !callback !0 void @t1_callback_broker(ptr nocapture , ptr nocapture , ptr nocapture, ...)
-
-; Test 2
-;
-; Similar to test 1 but checking that the noalias is only placed if potential synchronization through @t2_check is preserved.
-
-define void @t2_caller(ptr noalias %a) {
-; TUNIT-LABEL: define {{[^@]+}}@t2_caller
-; TUNIT-SAME: (ptr noalias nocapture nonnull align 256 [[A:%.*]]) {
-; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    [[B:%.*]] = alloca i32, align 32
-; TUNIT-NEXT:    [[C:%.*]] = alloca ptr, align 64
-; TUNIT-NEXT:    [[PTR:%.*]] = alloca i32, align 128
-; TUNIT-NEXT:    store i32 42, ptr [[B]], align 32
-; TUNIT-NEXT:    store ptr [[B]], ptr [[C]], align 64
-; TUNIT-NEXT:    call void (ptr, ptr, ptr, ...) @t2_callback_broker(ptr noundef align 4294967296 null, ptr noalias nocapture noundef nonnull align 128 dereferenceable(4) [[PTR]], ptr nocapture noundef nonnull @t2_callback_callee, ptr nocapture nonnull align 256 [[A]], i64 undef, ptr noalias nocapture nofree noundef nonnull readonly align 64 dereferenceable(8) [[C]])
-; TUNIT-NEXT:    ret void
-;
-; CGSCC-LABEL: define {{[^@]+}}@t2_caller
-; CGSCC-SAME: (ptr noalias nocapture nonnull align 256 [[A:%.*]]) {
-; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    [[B:%.*]] = alloca i32, align 32
-; CGSCC-NEXT:    [[C:%.*]] = alloca ptr, align 64
-; CGSCC-NEXT:    [[PTR:%.*]] = alloca i32, align 128
-; CGSCC-NEXT:    store i32 42, ptr [[B]], align 32
-; CGSCC-NEXT:    store ptr [[B]], ptr [[C]], align 64
-; CGSCC-NEXT:    call void (ptr, ptr, ptr, ...) @t2_callback_broker(ptr noundef align 4294967296 null, ptr noalias nocapture noundef nonnull align 128 dereferenceable(4) [[PTR]], ptr nocapture noundef nonnull @t2_callback_callee, ptr nocapture nonnull align 256 [[A]], i64 noundef 99, ptr noalias nocapture nofree noundef nonnull readonly align 64 dereferenceable(8) [[C]])
-; CGSCC-NEXT:    ret void
-;
-entry:
-  %b = alloca i32, align 32
-  %c = alloca ptr, align 64
-  %ptr = alloca i32, align 128
-  store i32 42, ptr %b, align 4
-  store ptr %b, ptr %c, align 8
-  call void (ptr, ptr, ptr, ...) @t2_callback_broker(ptr null, ptr %ptr, ptr @t2_callback_callee, ptr %a, i64 99, ptr %c)
-  ret void
-}
-
-; Note that the first two arguments are provided by the callback_broker according to the callback in !1 below!
-; The others are annotated with alignment information, amongst others, or even replaced by the constants passed to the call.
-;
-; FIXME: We should derive noalias for %a and add a "fake use" of %a in all potentially synchronizing calls.
-define internal void @t2_callback_callee(ptr %is_not_null, ptr %ptr, ptr %a, i64 %b, ptr %c) {
-;
-; TUNIT-LABEL: define {{[^@]+}}@t2_callback_callee
-; TUNIT-SAME: (ptr nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], ptr nocapture nofree noundef nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], ptr nocapture nonnull align 256 [[A:%.*]], i64 [[B:%.*]], ptr noalias nocapture nofree noundef nonnull readonly align 64 dereferenceable(8) [[C:%.*]]) {
-; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    [[PTR_VAL:%.*]] = load i32, ptr [[PTR]], align 8
-; TUNIT-NEXT:    store i32 [[PTR_VAL]], ptr [[IS_NOT_NULL]], align 4
-; TUNIT-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[C]], align 64
-; TUNIT-NEXT:    tail call void @t2_check(ptr nocapture nonnull align 256 [[A]], i64 noundef 99, ptr nocapture nonnull align 32 [[TMP0]])
-; TUNIT-NEXT:    ret void
-;
-; CGSCC-LABEL: define {{[^@]+}}@t2_callback_callee
-; CGSCC-SAME: (ptr nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], ptr nocapture nofree noundef nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], ptr nocapture nonnull align 256 [[A:%.*]], i64 [[B:%.*]], ptr noalias nocapture nofree noundef nonnull readonly align 64 dereferenceable(8) [[C:%.*]]) {
-; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    [[PTR_VAL:%.*]] = load i32, ptr [[PTR]], align 8
-; CGSCC-NEXT:    store i32 [[PTR_VAL]], ptr [[IS_NOT_NULL]], align 4
-; CGSCC-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[C]], align 64
-; CGSCC-NEXT:    tail call void @t2_check(ptr nocapture nonnull align 256 [[A]], i64 noundef 99, ptr nocapture nonnull [[TMP0]])
-; CGSCC-NEXT:    ret void
-;
-entry:
-  %ptr_val = load i32, ptr %ptr, align 8
-  store i32 %ptr_val, ptr %is_not_null
-  %0 = load ptr, ptr %c, align 8
-  tail call void @t2_check(ptr %a, i64 %b, ptr %0)
-  ret void
-}
-
-declare void @t2_check(ptr nocapture align 256, i64, ptr nocapture)
-
-declare !callback !0 void @t2_callback_broker(ptr nocapture , ptr nocapture , ptr nocapture, ...)
-
-; Test 3
-;
-; Basically test 2 with the casted callback callee used twice.
-
-define void @t3_caller(ptr noalias %a) {
-; TUNIT-LABEL: define {{[^@]+}}@t3_caller
-; TUNIT-SAME: (ptr noalias nocapture nonnull align 256 [[A:%.*]]) {
-; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    [[B:%.*]] = alloca i32, align 32
-; TUNIT-NEXT:    [[C:%.*]] = alloca ptr, align 64
-; TUNIT-NEXT:    [[PTR:%.*]] = alloca i32, align 128
-; TUNIT-NEXT:    store i32 42, ptr [[B]], align 32
-; TUNIT-NEXT:    store ptr [[B]], ptr [[C]], align 64
-; TUNIT-NEXT:    call void (ptr, ptr, ptr, ...) @t3_callback_broker(ptr noundef align 4294967296 null, ptr noalias nocapture noundef nonnull align 128 dereferenceable(4) [[PTR]], ptr nocapture noundef nonnull @t3_callback_callee, ptr nocapture nonnull align 256 [[A]], i64 undef, ptr noalias nocapture nofree noundef nonnull readonly align 64 dereferenceable(8) [[C]])
-; TUNIT-NEXT:    call void (ptr, ptr, ptr, ...) @t3_callback_broker(ptr noundef align 4294967296 null, ptr noalias nocapture noundef nonnull align 128 dereferenceable(4) [[PTR]], ptr nocapture noundef nonnull @t3_callback_callee, ptr nocapture nonnull align 256 [[A]], i64 undef, ptr noalias nocapture nofree noundef nonnull readonly align 64 dereferenceable(8) [[C]])
-; TUNIT-NEXT:    ret void
-;
-; CGSCC-LABEL: define {{[^@]+}}@t3_caller
-; CGSCC-SAME: (ptr noalias nocapture nonnull align 256 [[A:%.*]]) {
-; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    [[B:%.*]] = alloca i32, align 32
-; CGSCC-NEXT:    [[C:%.*]] = alloca ptr, align 64
-; CGSCC-NEXT:    [[PTR:%.*]] = alloca i32, align 128
-; CGSCC-NEXT:    store i32 42, ptr [[B]], align 32
-; CGSCC-NEXT:    store ptr [[B]], ptr [[C]], align 64
-; CGSCC-NEXT:    call void (ptr, ptr, ptr, ...) @t3_callback_broker(ptr noundef align 4294967296 null, ptr noalias nocapture noundef nonnull align 128 dereferenceable(4) [[PTR]], ptr nocapture noundef nonnull @t3_callback_callee, ptr nocapture nonnull align 256 [[A]], i64 noundef 99, ptr noalias nocapture nofree noundef nonnull readonly align 64 dereferenceable(8) [[C]])
-; CGSCC-NEXT:    call void (ptr, ptr, ptr, ...) @t3_callback_broker(ptr noundef align 4294967296 null, ptr noalias nocapture noundef nonnull align 128 dereferenceable(4) [[PTR]], ptr nocapture noundef nonnull @t3_callback_callee, ptr nocapture nonnull align 256 [[A]], i64 noundef 99, ptr noalias nocapture nofree noundef nonnull readonly align 64 dereferenceable(8) [[C]])
-; CGSCC-NEXT:    ret void
-;
-entry:
-  %b = alloca i32, align 32
-  %c = alloca ptr, align 64
-  %ptr = alloca i32, align 128
-  store i32 42, ptr %b, align 4
-  store ptr %b, ptr %c, align 8
-  call void (ptr, ptr, ptr, ...) @t3_callback_broker(ptr null, ptr %ptr, ptr @t3_callback_callee, ptr %a, i64 99, ptr %c)
-  call void (ptr, ptr, ptr, ...) @t3_callback_broker(ptr null, ptr %ptr, ptr @t3_callback_callee, ptr %a, i64 99, ptr %c)
-  ret void
-}
-
-; Note that the first two arguments are provided by the callback_broker according to the callback in !1 below!
-; The others are annotated with alignment information, amongst others, or even replaced by the constants passed to the call.
-;
-; FIXME: We should derive noalias for %a and add a "fake use" of %a in all potentially synchronizing calls.
-define internal void @t3_callback_callee(ptr %is_not_null, ptr %ptr, ptr %a, i64 %b, ptr %c) {
-;
-; TUNIT-LABEL: define {{[^@]+}}@t3_callback_callee
-; TUNIT-SAME: (ptr nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], ptr nocapture nofree noundef nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], ptr nocapture nonnull align 256 [[A:%.*]], i64 [[B:%.*]], ptr noalias nocapture nofree noundef nonnull readonly align 64 dereferenceable(8) [[C:%.*]]) {
-; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    [[PTR_VAL:%.*]] = load i32, ptr [[PTR]], align 8
-; TUNIT-NEXT:    store i32 [[PTR_VAL]], ptr [[IS_NOT_NULL]], align 4
-; TUNIT-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[C]], align 64
-; TUNIT-NEXT:    tail call void @t3_check(ptr nocapture nonnull align 256 [[A]], i64 noundef 99, ptr nocapture nonnull align 32 [[TMP0]])
-; TUNIT-NEXT:    ret void
-;
-; CGSCC-LABEL: define {{[^@]+}}@t3_callback_callee
-; CGSCC-SAME: (ptr nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], ptr nocapture nofree noundef nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], ptr nocapture nonnull align 256 [[A:%.*]], i64 [[B:%.*]], ptr noalias nocapture nofree noundef nonnull readonly align 64 dereferenceable(8) [[C:%.*]]) {
-; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    [[PTR_VAL:%.*]] = load i32, ptr [[PTR]], align 8
-; CGSCC-NEXT:    store i32 [[PTR_VAL]], ptr [[IS_NOT_NULL]], align 4
-; CGSCC-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[C]], align 64
-; CGSCC-NEXT:    tail call void @t3_check(ptr nocapture nonnull align 256 [[A]], i64 noundef 99, ptr nocapture nonnull [[TMP0]])
-; CGSCC-NEXT:    ret void
-;
-entry:
-  %ptr_val = load i32, ptr %ptr, align 8
-  store i32 %ptr_val, ptr %is_not_null
-  %0 = load ptr, ptr %c, align 8
-  tail call void @t3_check(ptr %a, i64 %b, ptr %0)
-  ret void
-}
-
-declare void @t3_check(ptr nocapture align 256, i64, ptr nocapture)
-
-declare !callback !0 void @t3_callback_broker(ptr nocapture , ptr nocapture , ptr nocapture, ...)
-
-!0 = !{!1}
-!1 = !{i64 2, i64 -1, i64 -1, i1 true}
-;.
-; TUNIT: attributes #[[ATTR0]] = { nosync }
-;.
-; CGSCC: attributes #[[ATTR0]] = { nosync }
-;.
-; TUNIT: [[META0:![0-9]+]] = !{[[META1:![0-9]+]]}
-; TUNIT: [[META1]] = !{i64 2, i64 -1, i64 -1, i1 true}
-;.
-; CGSCC: [[META0:![0-9]+]] = !{[[META1:![0-9]+]]}
-; CGSCC: [[META1]] = !{i64 2, i64 -1, i64 -1, i1 true}
-;.
-;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
-; CHECK: {{.*}}
diff --git a/llvm/test/Transforms/Attributor/nocapture-2-dl-sentinel.ll b/llvm/test/Transforms/Attributor/nocapture-2-dl-sentinel.ll
index cb9ab54b6da7c..1775681ec5f48 100755
--- a/llvm/test/Transforms/Attributor/nocapture-2-dl-sentinel.ll
+++ b/llvm/test/Transforms/Attributor/nocapture-2-dl-sentinel.ll
@@ -1,11 +1,11 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-attributes --check-globals --version 2
-; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal  -attributor-annotate-decl-cs  -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
-; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal  -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal  -attributor-annotate-decl-cs  -S < %s | FileCheck %s --check-prefixes=CHECK
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal  -attributor-annotate-decl-cs -data-layout=z0:1-z2:neg1-z3:neg1-z5:neg1 -S < %s | FileCheck %s --check-prefixes=CHECK-DL
 ;
 ; Test cases specifically designed for the "no-capture" argument attribute.
 ; We use FIXME's to indicate problems and missing attributes.
 ;
-target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-z0:1-z2:neg1-z3:neg1-z5:neg1-S128"
+
 declare ptr @unknown()
 
 ; TEST comparison against NULL
@@ -17,10 +17,18 @@ declare ptr @unknown()
 ; no-capture is missing on %p because it is not dereferenceable
 define i32 @is_null_return(ptr %p) #0 {
 ; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
-; CHECK-LABEL: define noundef i32 @is_null_return
-; CHECK-SAME: (ptr nocapture nofree nonnull readnone [[P:%.*]]) #[[ATTR0:[0-9]+]] {
+; CHECK-LABEL: define i32 @is_null_return
+; CHECK-SAME: (ptr nofree readnone [[P:%.*]]) #[[ATTR0:[0-9]+]] {
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    ret i32 0
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[P]], null
+; CHECK-NEXT:    [[CONV:%.*]] = zext i1 [[CMP]] to i32
+; CHECK-NEXT:    ret i32 [[CONV]]
+;
+; CHECK-DL: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
+; CHECK-DL-LABEL: define noundef i32 @is_null_return
+; CHECK-DL-SAME: (ptr nocapture nofree nonnull readnone [[P:%.*]]) #[[ATTR0:[0-9]+]] {
+; CHECK-DL-NEXT:  entry:
+; CHECK-DL-NEXT:    ret i32 0
 ;
 entry:
   %cmp = icmp eq ptr %p, null
@@ -42,20 +50,41 @@ entry:
 define i32 @is_null_control(ptr %p) #0 {
 ; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
 ; CHECK-LABEL: define i32 @is_null_control
-; CHECK-SAME: (ptr nocapture nofree nonnull readnone [[P:%.*]]) #[[ATTR0]] {
+; CHECK-SAME: (ptr nofree [[P:%.*]]) #[[ATTR0]] {
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[RETVAL:%.*]] = alloca i32, align 4
-; CHECK-NEXT:    br label [[IF_END:%.*]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[P]], null
+; CHECK-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
 ; CHECK:       if.then:
-; CHECK-NEXT:    unreachable
+; CHECK-NEXT:    store i32 1, ptr [[RETVAL]], align 4
+; CHECK-NEXT:    br label [[RETURN:%.*]]
 ; CHECK:       if.end:
 ; CHECK-NEXT:    br label [[IF_END3:%.*]]
 ; CHECK:       if.then2:
 ; CHECK-NEXT:    unreachable
 ; CHECK:       if.end3:
-; CHECK-NEXT:    br label [[RETURN:%.*]]
+; CHECK-NEXT:    store i32 0, ptr [[RETVAL]], align 4
+; CHECK-NEXT:    br label [[RETURN]]
 ; CHECK:       return:
-; CHECK-NEXT:    ret i32 0
+; CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr [[RETVAL]], align 4
+; CHECK-NEXT:    ret i32 [[TMP0]]
+;
+; CHECK-DL: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
+; CHECK-DL-LABEL: define i32 @is_null_control
+; CHECK-DL-SAME: (ptr nocapture nofree nonnull readnone [[P:%.*]]) #[[ATTR0]] {
+; CHECK-DL-NEXT:  entry:
+; CHECK-DL-NEXT:    [[RETVAL:%.*]] = alloca i32, align 4
+; CHECK-DL-NEXT:    br label [[IF_END:%.*]]
+; CHECK-DL:       if.then:
+; CHECK-DL-NEXT:    unreachable
+; CHECK-DL:       if.end:
+; CHECK-DL-NEXT:    br label [[IF_END3:%.*]]
+; CHECK-DL:       if.then2:
+; CHECK-DL-NEXT:    unreachable
+; CHECK-DL:       if.end3:
+; CHECK-DL-NEXT:    br label [[RETURN:%.*]]
+; CHECK-DL:       return:
+; CHECK-DL-NEXT:    ret i32 0
 ;
 entry:
   %retval = alloca i32, align 4
@@ -83,65 +112,6 @@ return:                                           ; preds = %if.end3, %if.then2,
   ret i32 %0
 }
 
-; TEST singleton SCC
-;
-; double *srec0(double *a) {
-;   srec0(a);
-;   return 0;
-; }
-;
-define ptr @srec0(ptr %a) #0 {
-; CHECK: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable
-; CHECK-LABEL: define noalias noundef align 4294967296 ptr @srec0
-; CHECK-SAME: (ptr nocapture nofree nonnull readnone [[A:%.*]]) #[[ATTR1:[0-9]+]] {
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    ret ptr null
-;
-entry:
-  %call = call ptr @srec0(ptr %a)
-  ret ptr null
-}
-
-; TEST singleton SCC with lots of nested recursive calls
-;
-; int* srec16(int* a) {
-;   return srec16(srec16(srec16(srec16(
-;          srec16(srec16(srec16(srec16(
-;          srec16(srec16(srec16(srec16(
-;          srec16(srec16(srec16(srec16(
-;                        a
-;          ))))))))))))))));
-; }
-;
-; Other arguments are possible here due to the no-return behavior.
-;
-define ptr @srec16(ptr %a) #0 {
-; CHECK: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable
-; CHECK-LABEL: define noalias nonnull align 4294967296 dereferenceable(4294967295) ptr @srec16
-; CHECK-SAME: (ptr nocapture nofree nonnull readnone [[A:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    ret ptr undef
-;
-entry:
-  %call = call ptr @srec16(ptr %a)
-  %call1 = call ptr @srec16(ptr %call)
-  %call2 = call ptr @srec16(ptr %call1)
-  %call3 = call ptr @srec16(ptr %call2)
-  %call4 = call ptr @srec16(ptr %call3)
-  %call5 = call ptr @srec16(ptr %call4)
-  %call6 = call ptr @srec16(ptr %call5)
-  %call7 = call ptr @srec16(ptr %call6)
-  %call8 = call ptr @srec16(ptr %call7)
-  %call9 = call ptr @srec16(ptr %call8)
-  %call10 = call ptr @srec16(ptr %call9)
-  %call11 = call ptr @srec16(ptr %call10)
-  %call12 = call ptr @srec16(ptr %call11)
-  %call13 = call ptr @srec16(ptr %call12)
-  %call14 = call ptr @srec16(ptr %call13)
-  %call15 = call ptr @srec16(ptr %call14)
-  ret ptr %call15
-}
-
 ; TEST SCC with various calls, casts, and comparisons agains NULL
 ;
 ; float *scc_A(int *a) {
@@ -156,17 +126,34 @@ entry:
 ;   return scc_A((int*)(scc_A(a) ? scc_B((double*)a) : scc_C(a)));
 ; }
 define ptr @scc_A(ptr dereferenceable_or_null(4) %a) {
-; CHECK: Function Attrs: mustprogress nofree noreturn nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define noalias nonnull align 4294967296 dereferenceable(4294967295) ptr @scc_A
-; CHECK-SAME: (ptr nocapture nofree nonnull readnone dereferenceable(4) [[A:%.*]]) #[[ATTR2:[0-9]+]] {
+; CHECK: Function Attrs: nofree nosync nounwind memory(none)
+; CHECK-LABEL: define noundef dereferenceable_or_null(4) ptr @scc_A
+; CHECK-SAME: (ptr nofree noundef readnone returned dereferenceable_or_null(4) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR1:[0-9]+]] {
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    br label [[COND_TRUE:%.*]]
+; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp ne ptr [[A]], null
+; CHECK-NEXT:    br i1 [[TOBOOL]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
 ; CHECK:       cond.true:
-; CHECK-NEXT:    unreachable
+; CHECK-NEXT:    [[CALL:%.*]] = call dereferenceable_or_null(4) ptr @scc_C(ptr noalias nofree noundef nonnull readnone dereferenceable(4) "no-capture-maybe-returned" [[A]]) #[[ATTR1]]
+; CHECK-NEXT:    [[CALL1:%.*]] = call dereferenceable_or_null(8) ptr @scc_B(ptr noalias nofree noundef readnone dereferenceable_or_null(8) "no-capture-maybe-returned" [[A]]) #[[ATTR1]]
+; CHECK-NEXT:    [[CALL2:%.*]] = call ptr @scc_A(ptr noalias nofree noundef readnone dereferenceable_or_null(8) "no-capture-maybe-returned" [[A]]) #[[ATTR1]]
+; CHECK-NEXT:    br label [[COND_END:%.*]]
 ; CHECK:       cond.false:
-; CHECK-NEXT:    unreachable
+; CHECK-NEXT:    br label [[COND_END]]
 ; CHECK:       cond.end:
-; CHECK-NEXT:    unreachable
+; CHECK-NEXT:    [[COND:%.*]] = phi ptr [ [[A]], [[COND_TRUE]] ], [ [[A]], [[COND_FALSE]] ]
+; CHECK-NEXT:    ret ptr [[A]]
+;
+; CHECK-DL: Function Attrs: mustprogress nofree noreturn nosync nounwind willreturn memory(none)
+; CHECK-DL-LABEL: define noalias nonnull align 4294967296 dereferenceable(4294967295) ptr @scc_A
+; CHECK-DL-SAME: (ptr nocapture nofree nonnull readnone dereferenceable(4) [[A:%.*]]) #[[ATTR1:[0-9]+]] {
+; CHECK-DL-NEXT:  entry:
+; CHECK-DL-NEXT:    br label [[COND_TRUE:%.*]]
+; CHECK-DL:       cond.true:
+; CHECK-DL-NEXT:    unreachable
+; CHECK-DL:       cond.false:
+; CHECK-DL-NEXT:    unreachable
+; CHECK-DL:       cond.end:
+; CHECK-DL-NEXT:    unreachable
 ;
 entry:
   %tobool = icmp ne ptr %a, null
@@ -188,29 +175,34 @@ cond.end:                                         ; preds = %cond.false, %cond.t
 
 ; FIXME: the call1 below to scc_B should return dereferenceable_or_null(8) (as the callee does). Something prevented that deduction and needs to be investigated.
 define ptr @scc_B(ptr dereferenceable_or_null(8) %a) {
-; TUNIT: Function Attrs: mustprogress nofree noreturn nosync nounwind willreturn memory(none)
-; TUNIT-LABEL: define noalias nonnull align 4294967296 dereferenceable(4294967295) ptr @scc_B
-; TUNIT-SAME: (ptr nocapture nofree nonnull readnone dereferenceable(8) [[A:%.*]]) #[[ATTR2]] {
-; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    br label [[COND_TRUE:%.*]]
-; TUNIT:       cond.true:
-; TUNIT-NEXT:    unreachable
-; TUNIT:       cond.false:
-; TUNIT-NEXT:    unreachable
-; TUNIT:       cond.end:
-; TUNIT-NEXT:    unreachable
-;
-; CGSCC: Function Attrs: mustprogress nofree norecurse noreturn nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define noalias nonnull align 4294967296 dereferenceable(4294967295) ptr @scc_B
-; CGSCC-SAME: (ptr nocapture nofree noundef nonnull readnone dereferenceable(8) [[A:%.*]]) #[[ATTR3:[0-9]+]] {
-; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    br label [[COND_TRUE:%.*]]
-; CGSCC:       cond.true:
-; CGSCC-NEXT:    unreachable
-; CGSCC:       cond.false:
-; CGSCC-NEXT:    unreachable
-; CGSCC:       cond.end:
-; CGSCC-NEXT:    unreachable
+; CHECK: Function Attrs: nofree nosync nounwind memory(none)
+; CHECK-LABEL: define noundef dereferenceable_or_null(8) ptr @scc_B
+; CHECK-SAME: (ptr nofree noundef readnone returned dereferenceable_or_null(8) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp ne ptr [[A]], null
+; CHECK-NEXT:    br i1 [[TOBOOL]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
+; CHECK:       cond.true:
+; CHECK-NEXT:    [[CALL:%.*]] = call dereferenceable_or_null(4) ptr @scc_A(ptr noalias nofree noundef nonnull readnone dereferenceable(8) "no-capture-maybe-returned" [[A]]) #[[ATTR1]]
+; CHECK-NEXT:    [[CALL1:%.*]] = call dereferenceable_or_null(8) ptr @scc_B(ptr noalias nofree noundef readnone dereferenceable_or_null(8) "no-capture-maybe-returned" [[A]]) #[[ATTR1]]
+; CHECK-NEXT:    [[CALL2:%.*]] = call ptr @scc_C(ptr noalias nofree noundef readnone dereferenceable_or_null(8) "no-capture-maybe-returned" [[A]]) #[[ATTR1]]
+; CHECK-NEXT:    br label [[COND_END:%.*]]
+; CHECK:       cond.false:
+; CHECK-NEXT:    br label [[COND_END]]
+; CHECK:       cond.end:
+; CHECK-NEXT:    [[COND:%.*]] = phi ptr [ [[A]], [[COND_TRUE]] ], [ [[A]], [[COND_FALSE]] ]
+; CHECK-NEXT:    ret ptr [[A]]
+;
+; CHECK-DL: Function Attrs: mustprogress nofree noreturn nosync nounwind willreturn memory(none)
+; CHECK-DL-LABEL: define noalias nonnull align 4294967296 dereferenceable(4294967295) ptr @scc_B
+; CHECK-DL-SAME: (ptr nocapture nofree nonnull readnone dereferenceable(8) [[A:%.*]]) #[[ATTR1]] {
+; CHECK-DL-NEXT:  entry:
+; CHECK-DL-NEXT:    br label [[COND_TRUE:%.*]]
+; CHECK-DL:       cond.true:
+; CHECK-DL-NEXT:    unreachable
+; CHECK-DL:       cond.false:
+; CHECK-DL-NEXT:    unreachable
+; CHECK-DL:       cond.end:
+; CHECK-DL-NEXT:    unreachable
 ;
 entry:
   %tobool = icmp ne ptr %a, null
@@ -231,29 +223,35 @@ cond.end:                                         ; preds = %cond.false, %cond.t
 }
 
 define ptr @scc_C(ptr dereferenceable_or_null(2) %a) {
-; TUNIT: Function Attrs: mustprogress nofree noreturn nosync nounwind willreturn memory(none)
-; TUNIT-LABEL: define noalias nonnull align 4294967296 dereferenceable(4294967295) ptr @scc_C
-; TUNIT-SAME: (ptr nocapture nofree nonnull readnone dereferenceable(4) [[A:%.*]]) #[[ATTR2]] {
-; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    unreachable
-; TUNIT:       cond.true:
-; TUNIT-NEXT:    unreachable
-; TUNIT:       cond.false:
-; TUNIT-NEXT:    unreachable
-; TUNIT:       cond.end:
-; TUNIT-NEXT:    unreachable
-;
-; CGSCC: Function Attrs: mustprogress nofree norecurse noreturn nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define noalias nonnull align 4294967296 dereferenceable(4294967295) ptr @scc_C
-; CGSCC-SAME: (ptr nocapture nofree noundef nonnull readnone dereferenceable(4) [[A:%.*]]) #[[ATTR3]] {
-; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    unreachable
-; CGSCC:       cond.true:
-; CGSCC-NEXT:    unreachable
-; CGSCC:       cond.false:
-; CGSCC-NEXT:    unreachable
-; CGSCC:       cond.end:
-; CGSCC-NEXT:    unreachable
+; CHECK: Function Attrs: nofree nosync nounwind memory(none)
+; CHECK-LABEL: define noundef dereferenceable_or_null(4) ptr @scc_C
+; CHECK-SAME: (ptr nofree noundef readnone returned dereferenceable_or_null(4) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CALL:%.*]] = call dereferenceable_or_null(4) ptr @scc_A(ptr noalias nofree noundef readnone dereferenceable_or_null(4) "no-capture-maybe-returned" [[A]]) #[[ATTR1]]
+; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp ne ptr [[A]], null
+; CHECK-NEXT:    br i1 [[TOBOOL]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
+; CHECK:       cond.true:
+; CHECK-NEXT:    [[CALL1:%.*]] = call ptr @scc_B(ptr noalias nofree noundef readnone dereferenceable_or_null(8) "no-capture-maybe-returned" [[A]]) #[[ATTR1]]
+; CHECK-NEXT:    br label [[COND_END:%.*]]
+; CHECK:       cond.false:
+; CHECK-NEXT:    [[CALL2:%.*]] = call ptr @scc_C(ptr noalias nofree noundef readnone dereferenceable_or_null(4) "no-capture-maybe-returned" [[A]]) #[[ATTR1]]
+; CHECK-NEXT:    br label [[COND_END]]
+; CHECK:       cond.end:
+; CHECK-NEXT:    [[COND:%.*]] = phi ptr [ [[A]], [[COND_TRUE]] ], [ [[A]], [[COND_FALSE]] ]
+; CHECK-NEXT:    [[CALL3:%.*]] = call ptr @scc_A(ptr noalias nofree noundef readnone dereferenceable_or_null(4) "no-capture-maybe-returned" [[A]]) #[[ATTR1]]
+; CHECK-NEXT:    ret ptr [[A]]
+;
+; CHECK-DL: Function Attrs: mustprogress nofree noreturn nosync nounwind willreturn memory(none)
+; CHECK-DL-LABEL: define noalias nonnull align 4294967296 dereferenceable(4294967295) ptr @scc_C
+; CHECK-DL-SAME: (ptr nocapture nofree nonnull readnone dereferenceable(4) [[A:%.*]]) #[[ATTR1]] {
+; CHECK-DL-NEXT:  entry:
+; CHECK-DL-NEXT:    unreachable
+; CHECK-DL:       cond.true:
+; CHECK-DL-NEXT:    unreachable
+; CHECK-DL:       cond.false:
+; CHECK-DL-NEXT:    unreachable
+; CHECK-DL:       cond.end:
+; CHECK-DL-NEXT:    unreachable
 ;
 entry:
   %call = call ptr @scc_A(ptr %a)
@@ -274,274 +272,6 @@ cond.end:                                         ; preds = %cond.false, %cond.t
   ret ptr %call3
 }
 
-
-; TEST call to external function, marked no-capture
-;
-; void external_no_capture(int /* no-capture */ *p);
-; void test_external_no_capture(int *p) {
-;   external_no_capture(p);
-; }
-;
-declare void @external_no_capture(ptr nocapture)
-
-define void @test_external_no_capture(ptr %p) #0 {
-; TUNIT: Function Attrs: noinline nounwind uwtable
-; TUNIT-LABEL: define void @test_external_no_capture
-; TUNIT-SAME: (ptr nocapture nonnull [[P:%.*]]) #[[ATTR3:[0-9]+]] {
-; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    call void @external_no_capture(ptr nocapture nonnull [[P]])
-; TUNIT-NEXT:    ret void
-;
-; CGSCC: Function Attrs: noinline nounwind uwtable
-; CGSCC-LABEL: define void @test_external_no_capture
-; CGSCC-SAME: (ptr nocapture nonnull [[P:%.*]]) #[[ATTR4:[0-9]+]] {
-; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    call void @external_no_capture(ptr nocapture nonnull [[P]])
-; CGSCC-NEXT:    ret void
-;
-entry:
-  call void @external_no_capture(ptr %p)
-  ret void
-}
-
-; TEST call to external var-args function, marked no-capture
-;
-; void test_var_arg_call(char *p, int a) {
-;   printf(p, a);
-; }
-;
-define void @test_var_arg_call(ptr %p, i32 %a) #0 {
-; TUNIT: Function Attrs: noinline nounwind uwtable
-; TUNIT-LABEL: define void @test_var_arg_call
-; TUNIT-SAME: (ptr nocapture nonnull [[P:%.*]], i32 [[A:%.*]]) #[[ATTR3]] {
-; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    [[CALL:%.*]] = call i32 (ptr, ...) @printf(ptr nocapture nonnull [[P]], i32 [[A]])
-; TUNIT-NEXT:    ret void
-;
-; CGSCC: Function Attrs: noinline nounwind uwtable
-; CGSCC-LABEL: define void @test_var_arg_call
-; CGSCC-SAME: (ptr nocapture nonnull [[P:%.*]], i32 [[A:%.*]]) #[[ATTR4]] {
-; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    [[CALL:%.*]] = call i32 (ptr, ...) @printf(ptr nocapture nonnull [[P]], i32 [[A]])
-; CGSCC-NEXT:    ret void
-;
-entry:
-  %call = call i32 (ptr, ...) @printf(ptr %p, i32 %a)
-  ret void
-}
-
-declare i32 @printf(ptr nocapture, ...)
-
-
-; TEST "captured" only through return
-;
-; long *not_captured_but_returned_0(long *a) {
-;   *a1 = 0;
-;   return a;
-; }
-;
-; There should *not* be a no-capture attribute on %a
-define ptr @not_captured_but_returned_0(ptr %a) #0 {
-; TUNIT: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(argmem: write) uwtable
-; TUNIT-LABEL: define noundef nonnull align 8 dereferenceable(8) ptr @not_captured_but_returned_0
-; TUNIT-SAME: (ptr nofree noundef nonnull returned writeonly align 8 dereferenceable(8) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR4:[0-9]+]] {
-; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    store i64 0, ptr [[A]], align 8
-; TUNIT-NEXT:    ret ptr [[A]]
-;
-; CGSCC: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(argmem: write) uwtable
-; CGSCC-LABEL: define noundef nonnull align 8 dereferenceable(8) ptr @not_captured_but_returned_0
-; CGSCC-SAME: (ptr nofree noundef nonnull returned writeonly align 8 dereferenceable(8) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR5:[0-9]+]] {
-; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    store i64 0, ptr [[A]], align 8
-; CGSCC-NEXT:    ret ptr [[A]]
-;
-entry:
-  store i64 0, ptr %a, align 8
-  ret ptr %a
-}
-
-; TEST "captured" only through return
-;
-; long *not_captured_but_returned_1(long *a) {
-;   *(a+1) = 1;
-;   return a + 1;
-; }
-;
-; There should *not* be a no-capture attribute on %a
-define ptr @not_captured_but_returned_1(ptr %a) #0 {
-; TUNIT: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(argmem: write) uwtable
-; TUNIT-LABEL: define noundef nonnull align 8 dereferenceable(8) ptr @not_captured_but_returned_1
-; TUNIT-SAME: (ptr nofree nonnull writeonly align 8 dereferenceable(16) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR4]] {
-; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    [[ADD_PTR:%.*]] = getelementptr inbounds i64, ptr [[A]], i64 1
-; TUNIT-NEXT:    store i64 1, ptr [[ADD_PTR]], align 8
-; TUNIT-NEXT:    ret ptr [[ADD_PTR]]
-;
-; CGSCC: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(argmem: write) uwtable
-; CGSCC-LABEL: define noundef nonnull align 8 dereferenceable(8) ptr @not_captured_but_returned_1
-; CGSCC-SAME: (ptr nofree nonnull writeonly align 8 dereferenceable(16) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR5]] {
-; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    [[ADD_PTR:%.*]] = getelementptr inbounds i64, ptr [[A]], i64 1
-; CGSCC-NEXT:    store i64 1, ptr [[ADD_PTR]], align 8
-; CGSCC-NEXT:    ret ptr [[ADD_PTR]]
-;
-entry:
-  %add.ptr = getelementptr inbounds i64, ptr %a, i64 1
-  store i64 1, ptr %add.ptr, align 8
-  ret ptr %add.ptr
-}
-
-; TEST calls to "captured" only through return functions
-;
-; void test_not_captured_but_returned_calls(long *a) {
-;   not_captured_but_returned_0(a);
-;   not_captured_but_returned_1(a);
-; }
-;
-define void @test_not_captured_but_returned_calls(ptr %a) #0 {
-; TUNIT: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(argmem: write) uwtable
-; TUNIT-LABEL: define void @test_not_captured_but_returned_calls
-; TUNIT-SAME: (ptr nocapture nofree nonnull writeonly align 8 [[A:%.*]]) #[[ATTR4]] {
-; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    [[CALL:%.*]] = call ptr @not_captured_but_returned_0(ptr nofree noundef nonnull writeonly align 8 "no-capture-maybe-returned" [[A]]) #[[ATTR12:[0-9]+]]
-; TUNIT-NEXT:    [[CALL1:%.*]] = call ptr @not_captured_but_returned_1(ptr nofree nonnull writeonly align 8 "no-capture-maybe-returned" [[A]]) #[[ATTR12]]
-; TUNIT-NEXT:    ret void
-;
-; CGSCC: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(argmem: write) uwtable
-; CGSCC-LABEL: define void @test_not_captured_but_returned_calls
-; CGSCC-SAME: (ptr nofree noundef nonnull writeonly align 8 dereferenceable(16) [[A:%.*]]) #[[ATTR6:[0-9]+]] {
-; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    [[CALL:%.*]] = call ptr @not_captured_but_returned_0(ptr nofree noundef nonnull writeonly align 8 dereferenceable(16) [[A]]) #[[ATTR15:[0-9]+]]
-; CGSCC-NEXT:    [[CALL1:%.*]] = call ptr @not_captured_but_returned_1(ptr nofree noundef nonnull writeonly align 8 dereferenceable(16) [[A]]) #[[ATTR15]]
-; CGSCC-NEXT:    ret void
-;
-entry:
-  %call = call ptr @not_captured_but_returned_0(ptr %a)
-  %call1 = call ptr @not_captured_but_returned_1(ptr %a)
-  ret void
-}
-
-; TEST "captured" only through transitive return
-;
-; long* negative_test_not_captured_but_returned_call_0a(long *a) {
-;   return not_captured_but_returned_0(a);
-; }
-;
-; There should *not* be a no-capture attribute on %a
-define ptr @negative_test_not_captured_but_returned_call_0a(ptr %a) #0 {
-; TUNIT: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(argmem: write) uwtable
-; TUNIT-LABEL: define nonnull align 8 ptr @negative_test_not_captured_but_returned_call_0a
-; TUNIT-SAME: (ptr nofree nonnull returned writeonly align 8 "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR4]] {
-; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    [[CALL:%.*]] = call ptr @not_captured_but_returned_0(ptr nofree noundef nonnull writeonly align 8 "no-capture-maybe-returned" [[A]]) #[[ATTR12]]
-; TUNIT-NEXT:    ret ptr [[A]]
-;
-; CGSCC: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(argmem: write) uwtable
-; CGSCC-LABEL: define noundef nonnull align 8 dereferenceable(8) ptr @negative_test_not_captured_but_returned_call_0a
-; CGSCC-SAME: (ptr nofree noundef nonnull writeonly align 8 dereferenceable(8) [[A:%.*]]) #[[ATTR6]] {
-; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    [[CALL:%.*]] = call noundef nonnull align 8 dereferenceable(8) ptr @not_captured_but_returned_0(ptr nofree noundef nonnull writeonly align 8 dereferenceable(8) [[A]]) #[[ATTR15]]
-; CGSCC-NEXT:    ret ptr [[CALL]]
-;
-entry:
-  %call = call ptr @not_captured_but_returned_0(ptr %a)
-  ret ptr %call
-}
-
-; TEST captured through write
-;
-; void negative_test_not_captured_but_returned_call_0b(long *a) {
-;   *a = (long)not_captured_but_returned_0(a);
-; }
-;
-; There should *not* be a no-capture attribute on %a
-define void @negative_test_not_captured_but_returned_call_0b(ptr %a) #0 {
-; TUNIT: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(argmem: write) uwtable
-; TUNIT-LABEL: define void @negative_test_not_captured_but_returned_call_0b
-; TUNIT-SAME: (ptr nofree nonnull writeonly align 8 [[A:%.*]]) #[[ATTR4]] {
-; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    [[CALL:%.*]] = call ptr @not_captured_but_returned_0(ptr nofree noundef nonnull writeonly align 8 "no-capture-maybe-returned" [[A]]) #[[ATTR12]]
-; TUNIT-NEXT:    [[TMP0:%.*]] = ptrtoint ptr [[A]] to i64
-; TUNIT-NEXT:    store i64 [[TMP0]], ptr [[A]], align 8
-; TUNIT-NEXT:    ret void
-;
-; CGSCC: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(argmem: write) uwtable
-; CGSCC-LABEL: define void @negative_test_not_captured_but_returned_call_0b
-; CGSCC-SAME: (ptr nofree noundef nonnull writeonly align 8 dereferenceable(8) [[A:%.*]]) #[[ATTR6]] {
-; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    [[CALL:%.*]] = call ptr @not_captured_but_returned_0(ptr nofree noundef nonnull writeonly align 8 dereferenceable(8) [[A]]) #[[ATTR15]]
-; CGSCC-NEXT:    [[TMP0:%.*]] = ptrtoint ptr [[CALL]] to i64
-; CGSCC-NEXT:    store i64 [[TMP0]], ptr [[A]], align 8
-; CGSCC-NEXT:    ret void
-;
-entry:
-  %call = call ptr @not_captured_but_returned_0(ptr %a)
-  %0 = ptrtoint ptr %call to i64
-  store i64 %0, ptr %a, align 8
-  ret void
-}
-
-; TEST "captured" only through transitive return
-;
-; long* negative_test_not_captured_but_returned_call_1a(long *a) {
-;   return not_captured_but_returned_1(a);
-; }
-;
-; There should *not* be a no-capture attribute on %a
-define ptr @negative_test_not_captured_but_returned_call_1a(ptr %a) #0 {
-; TUNIT: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(argmem: write) uwtable
-; TUNIT-LABEL: define noundef nonnull align 8 dereferenceable(8) ptr @negative_test_not_captured_but_returned_call_1a
-; TUNIT-SAME: (ptr nofree nonnull writeonly align 8 "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR4]] {
-; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    [[CALL:%.*]] = call noundef nonnull align 8 dereferenceable(8) ptr @not_captured_but_returned_1(ptr nofree nonnull writeonly align 8 "no-capture-maybe-returned" [[A]]) #[[ATTR12]]
-; TUNIT-NEXT:    ret ptr [[CALL]]
-;
-; CGSCC: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(argmem: write) uwtable
-; CGSCC-LABEL: define noundef nonnull align 8 dereferenceable(8) ptr @negative_test_not_captured_but_returned_call_1a
-; CGSCC-SAME: (ptr nofree noundef nonnull writeonly align 8 dereferenceable(16) [[A:%.*]]) #[[ATTR6]] {
-; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    [[CALL:%.*]] = call noundef nonnull align 8 dereferenceable(8) ptr @not_captured_but_returned_1(ptr nofree noundef nonnull writeonly align 8 dereferenceable(16) [[A]]) #[[ATTR15]]
-; CGSCC-NEXT:    ret ptr [[CALL]]
-;
-entry:
-  %call = call ptr @not_captured_but_returned_1(ptr %a)
-  ret ptr %call
-}
-
-; TEST captured through write
-;
-; void negative_test_not_captured_but_returned_call_1b(long *a) {
-;   *a = (long)not_captured_but_returned_1(a);
-; }
-;
-; There should *not* be a no-capture attribute on %a
-define void @negative_test_not_captured_but_returned_call_1b(ptr %a) #0 {
-; TUNIT: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(write) uwtable
-; TUNIT-LABEL: define void @negative_test_not_captured_but_returned_call_1b
-; TUNIT-SAME: (ptr nofree nonnull writeonly align 8 [[A:%.*]]) #[[ATTR5:[0-9]+]] {
-; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    [[CALL:%.*]] = call align 8 ptr @not_captured_but_returned_1(ptr nofree nonnull writeonly align 8 "no-capture-maybe-returned" [[A]]) #[[ATTR12]]
-; TUNIT-NEXT:    [[TMP0:%.*]] = ptrtoint ptr [[CALL]] to i64
-; TUNIT-NEXT:    store i64 [[TMP0]], ptr [[CALL]], align 8
-; TUNIT-NEXT:    ret void
-;
-; CGSCC: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(write) uwtable
-; CGSCC-LABEL: define void @negative_test_not_captured_but_returned_call_1b
-; CGSCC-SAME: (ptr nofree noundef nonnull writeonly align 8 dereferenceable(16) [[A:%.*]]) #[[ATTR7:[0-9]+]] {
-; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    [[CALL:%.*]] = call align 8 ptr @not_captured_but_returned_1(ptr nofree noundef nonnull writeonly align 8 dereferenceable(16) [[A]]) #[[ATTR15]]
-; CGSCC-NEXT:    [[TMP0:%.*]] = ptrtoint ptr [[CALL]] to i64
-; CGSCC-NEXT:    store i64 [[TMP0]], ptr [[CALL]], align 8
-; CGSCC-NEXT:    ret void
-;
-entry:
-  %call = call ptr @not_captured_but_returned_1(ptr %a)
-  %0 = ptrtoint ptr %call to i64
-  store i64 %0, ptr %call, align 8
-  ret void
-}
-
 ; TEST return argument or unknown call result
 ;
 ; int* ret_arg_or_unknown(int* b) {
@@ -554,27 +284,28 @@ entry:
 ;
 
 define ptr @ret_arg_or_unknown(ptr %b) #0 {
-; TUNIT: Function Attrs: noinline nounwind uwtable
-; TUNIT-LABEL: define nonnull ptr @ret_arg_or_unknown
-; TUNIT-SAME: (ptr nofree nonnull readnone "no-capture-maybe-returned" [[B:%.*]]) #[[ATTR3]] {
-; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    br label [[RET_UNKNOWN:%.*]]
-; TUNIT:       ret_arg:
-; TUNIT-NEXT:    unreachable
-; TUNIT:       ret_unknown:
-; TUNIT-NEXT:    [[CALL:%.*]] = call nonnull ptr @unknown()
-; TUNIT-NEXT:    ret ptr [[CALL]]
-;
-; CGSCC: Function Attrs: noinline nounwind uwtable
-; CGSCC-LABEL: define nonnull ptr @ret_arg_or_unknown
-; CGSCC-SAME: (ptr nofree nonnull readnone "no-capture-maybe-returned" [[B:%.*]]) #[[ATTR4]] {
-; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    br label [[RET_UNKNOWN:%.*]]
-; CGSCC:       ret_arg:
-; CGSCC-NEXT:    unreachable
-; CGSCC:       ret_unknown:
-; CGSCC-NEXT:    [[CALL:%.*]] = call nonnull ptr @unknown()
-; CGSCC-NEXT:    ret ptr [[CALL]]
+; CHECK: Function Attrs: noinline nounwind uwtable
+; CHECK-LABEL: define ptr @ret_arg_or_unknown
+; CHECK-SAME: (ptr [[B:%.*]]) #[[ATTR2:[0-9]+]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[B]], null
+; CHECK-NEXT:    br i1 [[CMP]], label [[RET_ARG:%.*]], label [[RET_UNKNOWN:%.*]]
+; CHECK:       ret_arg:
+; CHECK-NEXT:    ret ptr [[B]]
+; CHECK:       ret_unknown:
+; CHECK-NEXT:    [[CALL:%.*]] = call ptr @unknown()
+; CHECK-NEXT:    ret ptr [[CALL]]
+;
+; CHECK-DL: Function Attrs: noinline nounwind uwtable
+; CHECK-DL-LABEL: define nonnull ptr @ret_arg_or_unknown
+; CHECK-DL-SAME: (ptr nofree nonnull readnone "no-capture-maybe-returned" [[B:%.*]]) #[[ATTR2:[0-9]+]] {
+; CHECK-DL-NEXT:  entry:
+; CHECK-DL-NEXT:    br label [[RET_UNKNOWN:%.*]]
+; CHECK-DL:       ret_arg:
+; CHECK-DL-NEXT:    unreachable
+; CHECK-DL:       ret_unknown:
+; CHECK-DL-NEXT:    [[CALL:%.*]] = call nonnull ptr @unknown()
+; CHECK-DL-NEXT:    ret ptr [[CALL]]
 ;
 entry:
   %cmp = icmp eq ptr %b, null
@@ -589,31 +320,33 @@ ret_unknown:
 }
 
 define ptr @ret_arg_or_unknown_through_phi(ptr %b) #0 {
-; TUNIT: Function Attrs: noinline nounwind uwtable
-; TUNIT-LABEL: define nonnull ptr @ret_arg_or_unknown_through_phi
-; TUNIT-SAME: (ptr nocapture nofree nonnull readnone [[B:%.*]]) #[[ATTR3]] {
-; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    br label [[RET_UNKNOWN:%.*]]
-; TUNIT:       ret_arg:
-; TUNIT-NEXT:    unreachable
-; TUNIT:       ret_unknown:
-; TUNIT-NEXT:    [[CALL:%.*]] = call nonnull ptr @unknown()
-; TUNIT-NEXT:    br label [[R:%.*]]
-; TUNIT:       r:
-; TUNIT-NEXT:    ret ptr [[CALL]]
-;
-; CGSCC: Function Attrs: noinline nounwind uwtable
-; CGSCC-LABEL: define nonnull ptr @ret_arg_or_unknown_through_phi
-; CGSCC-SAME: (ptr nocapture nofree nonnull readnone [[B:%.*]]) #[[ATTR4]] {
-; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    br label [[RET_UNKNOWN:%.*]]
-; CGSCC:       ret_arg:
-; CGSCC-NEXT:    unreachable
-; CGSCC:       ret_unknown:
-; CGSCC-NEXT:    [[CALL:%.*]] = call nonnull ptr @unknown()
-; CGSCC-NEXT:    br label [[R:%.*]]
-; CGSCC:       r:
-; CGSCC-NEXT:    ret ptr [[CALL]]
+; CHECK: Function Attrs: noinline nounwind uwtable
+; CHECK-LABEL: define ptr @ret_arg_or_unknown_through_phi
+; CHECK-SAME: (ptr [[B:%.*]]) #[[ATTR2]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[B]], null
+; CHECK-NEXT:    br i1 [[CMP]], label [[RET_ARG:%.*]], label [[RET_UNKNOWN:%.*]]
+; CHECK:       ret_arg:
+; CHECK-NEXT:    br label [[R:%.*]]
+; CHECK:       ret_unknown:
+; CHECK-NEXT:    [[CALL:%.*]] = call ptr @unknown()
+; CHECK-NEXT:    br label [[R]]
+; CHECK:       r:
+; CHECK-NEXT:    [[PHI:%.*]] = phi ptr [ [[B]], [[RET_ARG]] ], [ [[CALL]], [[RET_UNKNOWN]] ]
+; CHECK-NEXT:    ret ptr [[PHI]]
+;
+; CHECK-DL: Function Attrs: noinline nounwind uwtable
+; CHECK-DL-LABEL: define nonnull ptr @ret_arg_or_unknown_through_phi
+; CHECK-DL-SAME: (ptr nocapture nofree nonnull readnone [[B:%.*]]) #[[ATTR2]] {
+; CHECK-DL-NEXT:  entry:
+; CHECK-DL-NEXT:    br label [[RET_UNKNOWN:%.*]]
+; CHECK-DL:       ret_arg:
+; CHECK-DL-NEXT:    unreachable
+; CHECK-DL:       ret_unknown:
+; CHECK-DL-NEXT:    [[CALL:%.*]] = call nonnull ptr @unknown()
+; CHECK-DL-NEXT:    br label [[R:%.*]]
+; CHECK-DL:       r:
+; CHECK-DL-NEXT:    ret ptr [[CALL]]
 ;
 entry:
   %cmp = icmp eq ptr %b, null
@@ -631,262 +364,13 @@ r:
   ret ptr %phi
 }
 
-
-; TEST not captured by readonly external function
-;
-declare ptr @readonly_unknown(ptr, ptr) readonly
-
-define void @not_captured_by_readonly_call(ptr %b) #0 {
-; TUNIT: Function Attrs: noinline nosync nounwind memory(read) uwtable
-; TUNIT-LABEL: define void @not_captured_by_readonly_call
-; TUNIT-SAME: (ptr nocapture nonnull readonly [[B:%.*]]) #[[ATTR7:[0-9]+]] {
-; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    [[CALL:%.*]] = call ptr @readonly_unknown(ptr nonnull readonly [[B]], ptr nonnull readonly [[B]]) #[[ATTR13:[0-9]+]]
-; TUNIT-NEXT:    ret void
-;
-; CGSCC: Function Attrs: noinline nosync nounwind memory(read) uwtable
-; CGSCC-LABEL: define void @not_captured_by_readonly_call
-; CGSCC-SAME: (ptr nocapture nonnull readonly [[B:%.*]]) #[[ATTR9:[0-9]+]] {
-; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    [[CALL:%.*]] = call ptr @readonly_unknown(ptr nonnull readonly [[B]], ptr nonnull readonly [[B]]) #[[ATTR16:[0-9]+]]
-; CGSCC-NEXT:    ret void
-;
-entry:
-  %call = call ptr @readonly_unknown(ptr %b, ptr %b)
-  ret void
-}
-
-
-; TEST not captured by readonly external function if return chain is known
-;
-; Make sure the returned flag on %r is strong enough to justify nocapture on %b but **not** on %r.
-;
-define ptr @not_captured_by_readonly_call_not_returned_either1(ptr %b, ptr returned %r) {
-; TUNIT: Function Attrs: nosync nounwind memory(read)
-; TUNIT-LABEL: define nonnull ptr @not_captured_by_readonly_call_not_returned_either1
-; TUNIT-SAME: (ptr nocapture nonnull readonly [[B:%.*]], ptr nonnull readonly returned [[R:%.*]]) #[[ATTR8:[0-9]+]] {
-; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    [[CALL:%.*]] = call ptr @readonly_unknown(ptr nonnull readonly [[B]], ptr nonnull readonly [[R]]) #[[ATTR8]]
-; TUNIT-NEXT:    ret ptr [[CALL]]
-;
-; CGSCC: Function Attrs: nosync nounwind memory(read)
-; CGSCC-LABEL: define nonnull ptr @not_captured_by_readonly_call_not_returned_either1
-; CGSCC-SAME: (ptr nocapture nonnull readonly [[B:%.*]], ptr nonnull readonly returned [[R:%.*]]) #[[ATTR10:[0-9]+]] {
-; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    [[CALL:%.*]] = call ptr @readonly_unknown(ptr nonnull readonly [[B]], ptr nonnull readonly [[R]]) #[[ATTR10]]
-; CGSCC-NEXT:    ret ptr [[CALL]]
-;
-entry:
-  %call = call ptr @readonly_unknown(ptr %b, ptr %r) nounwind
-  ret ptr %call
-}
-
-declare ptr @readonly_unknown_r1a(ptr, ptr returned) readonly
-define ptr @not_captured_by_readonly_call_not_returned_either2(ptr %b, ptr %r) {
-; TUNIT: Function Attrs: nosync nounwind memory(read)
-; TUNIT-LABEL: define nonnull ptr @not_captured_by_readonly_call_not_returned_either2
-; TUNIT-SAME: (ptr nonnull readonly [[B:%.*]], ptr nonnull readonly [[R:%.*]]) #[[ATTR8]] {
-; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    [[CALL:%.*]] = call nonnull ptr @readonly_unknown_r1a(ptr nonnull readonly [[B]], ptr nonnull readonly [[R]]) #[[ATTR8]]
-; TUNIT-NEXT:    ret ptr [[CALL]]
-;
-; CGSCC: Function Attrs: nosync nounwind memory(read)
-; CGSCC-LABEL: define nonnull ptr @not_captured_by_readonly_call_not_returned_either2
-; CGSCC-SAME: (ptr nonnull readonly [[B:%.*]], ptr nonnull readonly [[R:%.*]]) #[[ATTR10]] {
-; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    [[CALL:%.*]] = call nonnull ptr @readonly_unknown_r1a(ptr nonnull readonly [[B]], ptr nonnull readonly [[R]]) #[[ATTR10]]
-; CGSCC-NEXT:    ret ptr [[CALL]]
-;
-entry:
-  %call = call ptr @readonly_unknown_r1a(ptr %b, ptr %r) nounwind
-  ret ptr %call
-}
-
-declare ptr @readonly_unknown_r1b(ptr, ptr returned) readonly nounwind
-define ptr @not_captured_by_readonly_call_not_returned_either3(ptr %b, ptr %r) {
-; TUNIT: Function Attrs: nosync nounwind memory(read)
-; TUNIT-LABEL: define nonnull ptr @not_captured_by_readonly_call_not_returned_either3
-; TUNIT-SAME: (ptr nocapture nonnull readonly [[B:%.*]], ptr nonnull readonly [[R:%.*]]) #[[ATTR8]] {
-; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    [[CALL:%.*]] = call nonnull ptr @readonly_unknown_r1b(ptr nocapture nonnull readonly [[B]], ptr nonnull readonly [[R]]) #[[ATTR8]]
-; TUNIT-NEXT:    ret ptr [[CALL]]
-;
-; CGSCC: Function Attrs: nosync nounwind memory(read)
-; CGSCC-LABEL: define nonnull ptr @not_captured_by_readonly_call_not_returned_either3
-; CGSCC-SAME: (ptr nocapture nonnull readonly [[B:%.*]], ptr nonnull readonly [[R:%.*]]) #[[ATTR10]] {
-; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    [[CALL:%.*]] = call nonnull ptr @readonly_unknown_r1b(ptr nocapture nonnull readonly [[B]], ptr nonnull readonly [[R]]) #[[ATTR10]]
-; CGSCC-NEXT:    ret ptr [[CALL]]
-;
-entry:
-  %call = call ptr @readonly_unknown_r1b(ptr %b, ptr %r)
-  ret ptr %call
-}
-
-define ptr @not_captured_by_readonly_call_not_returned_either4(ptr %b, ptr %r) nounwind {
-; TUNIT: Function Attrs: nosync nounwind memory(read)
-; TUNIT-LABEL: define nonnull ptr @not_captured_by_readonly_call_not_returned_either4
-; TUNIT-SAME: (ptr nonnull readonly [[B:%.*]], ptr nonnull readonly [[R:%.*]]) #[[ATTR8]] {
-; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    [[CALL:%.*]] = call nonnull ptr @readonly_unknown_r1a(ptr nonnull readonly [[B]], ptr nonnull readonly [[R]]) #[[ATTR13]]
-; TUNIT-NEXT:    ret ptr [[CALL]]
-;
-; CGSCC: Function Attrs: nosync nounwind memory(read)
-; CGSCC-LABEL: define nonnull ptr @not_captured_by_readonly_call_not_returned_either4
-; CGSCC-SAME: (ptr nonnull readonly [[B:%.*]], ptr nonnull readonly [[R:%.*]]) #[[ATTR10]] {
-; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    [[CALL:%.*]] = call nonnull ptr @readonly_unknown_r1a(ptr nonnull readonly [[B]], ptr nonnull readonly [[R]]) #[[ATTR16]]
-; CGSCC-NEXT:    ret ptr [[CALL]]
-;
-entry:
-  %call = call ptr @readonly_unknown_r1a(ptr %b, ptr %r)
-  ret ptr %call
-}
-
-
-declare ptr @unknown_i32p(ptr)
-define void @nocapture_is_not_subsumed_1(ptr nocapture %b) {
-; CHECK-LABEL: define void @nocapture_is_not_subsumed_1
-; CHECK-SAME: (ptr nocapture nonnull [[B:%.*]]) {
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[CALL:%.*]] = call ptr @unknown_i32p(ptr nonnull [[B]])
-; CHECK-NEXT:    store i32 0, ptr [[CALL]], align 4
-; CHECK-NEXT:    ret void
-;
-entry:
-  %call = call ptr @unknown_i32p(ptr %b)
-  store i32 0, ptr %call
-  ret void
-}
-
-declare ptr @readonly_i32p(ptr) readonly
-define void @nocapture_is_not_subsumed_2(ptr nocapture %b) {
-; TUNIT: Function Attrs: nosync
-; TUNIT-LABEL: define void @nocapture_is_not_subsumed_2
-; TUNIT-SAME: (ptr nocapture nonnull [[B:%.*]]) #[[ATTR10:[0-9]+]] {
-; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    [[CALL:%.*]] = call ptr @readonly_i32p(ptr nonnull readonly [[B]]) #[[ATTR13]]
-; TUNIT-NEXT:    store i32 0, ptr [[CALL]], align 4
-; TUNIT-NEXT:    ret void
-;
-; CGSCC: Function Attrs: nosync
-; CGSCC-LABEL: define void @nocapture_is_not_subsumed_2
-; CGSCC-SAME: (ptr nocapture nonnull [[B:%.*]]) #[[ATTR12:[0-9]+]] {
-; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    [[CALL:%.*]] = call ptr @readonly_i32p(ptr nonnull readonly [[B]]) #[[ATTR16]]
-; CGSCC-NEXT:    store i32 0, ptr [[CALL]], align 4
-; CGSCC-NEXT:    ret void
-;
-entry:
-  %call = call ptr @readonly_i32p(ptr %b)
-  store i32 0, ptr %call
-  ret void
-}
-
-; Make sure %p is not not marked nocapture (Bug #64613).
-; Version a failed with the lightweight attributor, b with the full one.
-define ptr @b64613_a(ptr noundef %p) {
-; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; TUNIT-LABEL: define noundef nonnull ptr @b64613_a
-; TUNIT-SAME: (ptr nofree noundef nonnull readnone returned "no-capture-maybe-returned" [[P:%.*]]) #[[ATTR11:[0-9]+]] {
-; TUNIT-NEXT:    [[P_ADDR:%.*]] = alloca ptr, align 1
-; TUNIT-NEXT:    store ptr [[P]], ptr [[P_ADDR]], align 1
-; TUNIT-NEXT:    ret ptr [[P]]
-;
-; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define noundef nonnull ptr @b64613_a
-; CGSCC-SAME: (ptr nofree noundef nonnull readnone returned "no-capture-maybe-returned" [[P:%.*]]) #[[ATTR13:[0-9]+]] {
-; CGSCC-NEXT:    [[P_ADDR:%.*]] = alloca ptr, align 1
-; CGSCC-NEXT:    store ptr [[P]], ptr [[P_ADDR]], align 1
-; CGSCC-NEXT:    ret ptr [[P]]
-;
-  %p.addr = alloca ptr, align 1
-  store ptr %p, ptr %p.addr, align 1
-  %r = load ptr, ptr %p.addr, align 1
-  ret ptr %r
-}
-define ptr @b64613_b(ptr noundef %p, i32 %i) {
-; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; TUNIT-LABEL: define nonnull ptr @b64613_b
-; TUNIT-SAME: (ptr nofree noundef nonnull [[P:%.*]], i32 [[I:%.*]]) #[[ATTR11]] {
-; TUNIT-NEXT:    [[P_ADDR:%.*]] = alloca <2 x ptr>, align 1
-; TUNIT-NEXT:    [[G:%.*]] = getelementptr i8, ptr [[P_ADDR]], i32 [[I]]
-; TUNIT-NEXT:    store ptr [[P]], ptr [[G]], align 1
-; TUNIT-NEXT:    [[R:%.*]] = load ptr, ptr [[P_ADDR]], align 1
-; TUNIT-NEXT:    ret ptr [[R]]
-;
-; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define nonnull ptr @b64613_b
-; CGSCC-SAME: (ptr nofree noundef nonnull [[P:%.*]], i32 [[I:%.*]]) #[[ATTR13]] {
-; CGSCC-NEXT:    [[P_ADDR:%.*]] = alloca <2 x ptr>, align 1
-; CGSCC-NEXT:    [[G:%.*]] = getelementptr i8, ptr [[P_ADDR]], i32 [[I]]
-; CGSCC-NEXT:    store ptr [[P]], ptr [[G]], align 1
-; CGSCC-NEXT:    [[R:%.*]] = load ptr, ptr [[P_ADDR]], align 1
-; CGSCC-NEXT:    ret ptr [[R]]
-;
-  %p.addr = alloca <2 x ptr>, align 1
-  %g = getelementptr i8, ptr %p.addr, i32 %i
-  store ptr %p, ptr %g, align 1
-  %r = load ptr, ptr %p.addr, align 1
-  ret ptr %r
-}
-define void @b64613_positive(ptr noundef %p, i32 %i) {
-; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; TUNIT-LABEL: define void @b64613_positive
-; TUNIT-SAME: (ptr nocapture nofree noundef nonnull [[P:%.*]], i32 [[I:%.*]]) #[[ATTR11]] {
-; TUNIT-NEXT:    [[P_ADDR:%.*]] = alloca <2 x ptr>, align 1
-; TUNIT-NEXT:    [[G:%.*]] = getelementptr i8, ptr [[P_ADDR]], i32 [[I]]
-; TUNIT-NEXT:    store ptr [[P]], ptr [[G]], align 1
-; TUNIT-NEXT:    ret void
-;
-; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define void @b64613_positive
-; CGSCC-SAME: (ptr nocapture nofree noundef nonnull [[P:%.*]], i32 [[I:%.*]]) #[[ATTR14:[0-9]+]] {
-; CGSCC-NEXT:    [[P_ADDR:%.*]] = alloca <2 x ptr>, align 1
-; CGSCC-NEXT:    [[G:%.*]] = getelementptr i8, ptr [[P_ADDR]], i32 [[I]]
-; CGSCC-NEXT:    store ptr [[P]], ptr [[G]], align 1
-; CGSCC-NEXT:    ret void
-;
-  %p.addr = alloca <2 x ptr>, align 1
-  %g = getelementptr i8, ptr %p.addr, i32 %i
-  store ptr %p, ptr %g, align 1
-  %r = load ptr, ptr %p.addr, align 1
-  %q = call ptr @b64613_b(ptr %r, i32 %i)
-  ret void
-}
-
 attributes #0 = { noinline nounwind uwtable }
 ;.
-; TUNIT: attributes #[[ATTR0]] = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable }
-; TUNIT: attributes #[[ATTR1]] = { mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable }
-; TUNIT: attributes #[[ATTR2]] = { mustprogress nofree noreturn nosync nounwind willreturn memory(none) }
-; TUNIT: attributes #[[ATTR3]] = { noinline nounwind uwtable }
-; TUNIT: attributes #[[ATTR4]] = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(argmem: write) uwtable }
-; TUNIT: attributes #[[ATTR5]] = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(write) uwtable }
-; TUNIT: attributes #[[ATTR6:[0-9]+]] = { memory(read) }
-; TUNIT: attributes #[[ATTR7]] = { noinline nosync nounwind memory(read) uwtable }
-; TUNIT: attributes #[[ATTR8]] = { nosync nounwind memory(read) }
-; TUNIT: attributes #[[ATTR9:[0-9]+]] = { nounwind memory(read) }
-; TUNIT: attributes #[[ATTR10]] = { nosync }
-; TUNIT: attributes #[[ATTR11]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
-; TUNIT: attributes #[[ATTR12]] = { nofree nosync nounwind willreturn memory(write) }
-; TUNIT: attributes #[[ATTR13]] = { nosync memory(read) }
+; CHECK: attributes #[[ATTR0]] = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable }
+; CHECK: attributes #[[ATTR1]] = { nofree nosync nounwind memory(none) }
+; CHECK: attributes #[[ATTR2]] = { noinline nounwind uwtable }
 ;.
-; CGSCC: attributes #[[ATTR0]] = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable }
-; CGSCC: attributes #[[ATTR1]] = { mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable }
-; CGSCC: attributes #[[ATTR2]] = { mustprogress nofree noreturn nosync nounwind willreturn memory(none) }
-; CGSCC: attributes #[[ATTR3]] = { mustprogress nofree norecurse noreturn nosync nounwind willreturn memory(none) }
-; CGSCC: attributes #[[ATTR4]] = { noinline nounwind uwtable }
-; CGSCC: attributes #[[ATTR5]] = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(argmem: write) uwtable }
-; CGSCC: attributes #[[ATTR6]] = { mustprogress nofree noinline nosync nounwind willreturn memory(argmem: write) uwtable }
-; CGSCC: attributes #[[ATTR7]] = { mustprogress nofree noinline nosync nounwind willreturn memory(write) uwtable }
-; CGSCC: attributes #[[ATTR8:[0-9]+]] = { memory(read) }
-; CGSCC: attributes #[[ATTR9]] = { noinline nosync nounwind memory(read) uwtable }
-; CGSCC: attributes #[[ATTR10]] = { nosync nounwind memory(read) }
-; CGSCC: attributes #[[ATTR11:[0-9]+]] = { nounwind memory(read) }
-; CGSCC: attributes #[[ATTR12]] = { nosync }
-; CGSCC: attributes #[[ATTR13]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
-; CGSCC: attributes #[[ATTR14]] = { mustprogress nofree nosync nounwind willreturn memory(none) }
-; CGSCC: attributes #[[ATTR15]] = { nofree nounwind willreturn memory(write) }
-; CGSCC: attributes #[[ATTR16]] = { nosync memory(read) }
+; CHECK-DL: attributes #[[ATTR0]] = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable }
+; CHECK-DL: attributes #[[ATTR1]] = { mustprogress nofree noreturn nosync nounwind willreturn memory(none) }
+; CHECK-DL: attributes #[[ATTR2]] = { noinline nounwind uwtable }
 ;.
diff --git a/llvm/test/Transforms/Attributor/nofree-dl-sentinel.ll b/llvm/test/Transforms/Attributor/nofree-dl-sentinel.ll
index de752340cc16d..d26b64cb9cfcc 100755
--- a/llvm/test/Transforms/Attributor/nofree-dl-sentinel.ll
+++ b/llvm/test/Transforms/Attributor/nofree-dl-sentinel.ll
@@ -1,8 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
-; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal  -attributor-annotate-decl-cs  -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
-; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal  -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
-
-target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-z0:1-z2:neg1-z3:neg1-z5:neg1-S128"
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal  -attributor-annotate-decl-cs  -S < %s | FileCheck %s --check-prefixes=CHECK
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal  -attributor-annotate-decl-cs -data-layout=z0:1-z2:neg1-z3:neg1-z5:neg1 -S < %s | FileCheck %s --check-prefixes=CHECK-DL
 
 ; Test cases specifically designed for the "nofree" function attribute.
 ; We use FIXME's to indicate problems and missing attributes.
@@ -12,36 +10,6 @@ declare void @free(ptr nocapture) local_unnamed_addr #1
 declare noalias ptr @realloc(ptr nocapture, i64) local_unnamed_addr #0
 declare void @_ZdaPv(ptr) local_unnamed_addr #2
 
-
-; TEST 1 (positive case)
-define void @only_return() #0 {
-; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
-; CHECK-LABEL: define {{[^@]+}}@only_return
-; CHECK-SAME: () #[[ATTR3:[0-9]+]] {
-; CHECK-NEXT:    ret void
-;
-  ret void
-}
-
-
-; TEST 2 (negative case)
-; Only free
-; void only_free(char* p) {
-;    free(p);
-; }
-
-define void @only_free(ptr nocapture %0) local_unnamed_addr #0 {
-; CHECK: Function Attrs: noinline nounwind uwtable
-; CHECK-LABEL: define {{[^@]+}}@only_free
-; CHECK-SAME: (ptr nocapture nonnull [[TMP0:%.*]]) local_unnamed_addr #[[ATTR1:[0-9]+]] {
-; CHECK-NEXT:    tail call void @free(ptr nocapture nonnull [[TMP0]]) #[[ATTR0:[0-9]+]]
-; CHECK-NEXT:    ret void
-;
-  tail call void @free(ptr %0) #1
-  ret void
-}
-
-
 ; TEST 3 (negative case)
 ; Free occurs in same scc.
 ; void free_in_scc1(char*p){
@@ -56,27 +24,45 @@ define void @only_free(ptr nocapture %0) local_unnamed_addr #0 {
 define void @free_in_scc1(ptr nocapture %0) local_unnamed_addr #0 {
 ; CHECK: Function Attrs: noinline nounwind uwtable
 ; CHECK-LABEL: define {{[^@]+}}@free_in_scc1
-; CHECK-SAME: (ptr nocapture nonnull [[TMP0:%.*]]) local_unnamed_addr #[[ATTR1]] {
-; CHECK-NEXT:    tail call void @free_in_scc2(ptr nocapture nonnull [[TMP0]]) #[[ATTR0]]
+; CHECK-SAME: (ptr nocapture [[TMP0:%.*]]) local_unnamed_addr #[[ATTR1:[0-9]+]] {
+; CHECK-NEXT:    tail call void @free_in_scc2(ptr nocapture [[TMP0]]) #[[ATTR0:[0-9]+]]
 ; CHECK-NEXT:    ret void
+;
+; CHECK-DL: Function Attrs: noinline nounwind uwtable
+; CHECK-DL-LABEL: define {{[^@]+}}@free_in_scc1
+; CHECK-DL-SAME: (ptr nocapture nonnull [[TMP0:%.*]]) local_unnamed_addr #[[ATTR1:[0-9]+]] {
+; CHECK-DL-NEXT:    tail call void @free_in_scc2(ptr nocapture nonnull [[TMP0]]) #[[ATTR0:[0-9]+]]
+; CHECK-DL-NEXT:    ret void
 ;
   tail call void @free_in_scc2(ptr %0) #1
   ret void
 }
-
-
 define void @free_in_scc2(ptr nocapture %0) local_unnamed_addr #0 {
 ; CHECK: Function Attrs: noinline nounwind uwtable
 ; CHECK-LABEL: define {{[^@]+}}@free_in_scc2
-; CHECK-SAME: (ptr nocapture nonnull [[TMP0:%.*]]) local_unnamed_addr #[[ATTR1]] {
-; CHECK-NEXT:    br label [[CALL:%.*]]
+; CHECK-SAME: (ptr nocapture [[TMP0:%.*]]) local_unnamed_addr #[[ATTR1]] {
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[TMP0]], null
+; CHECK-NEXT:    br i1 [[CMP]], label [[REC:%.*]], label [[CALL:%.*]]
 ; CHECK:       call:
 ; CHECK-NEXT:    tail call void @free(ptr nocapture nonnull [[TMP0]]) #[[ATTR0]]
 ; CHECK-NEXT:    br label [[END:%.*]]
 ; CHECK:       rec:
-; CHECK-NEXT:    unreachable
+; CHECK-NEXT:    tail call void @free_in_scc1(ptr nocapture [[TMP0]]) #[[ATTR0]]
+; CHECK-NEXT:    br label [[END]]
 ; CHECK:       end:
 ; CHECK-NEXT:    ret void
+;
+; CHECK-DL: Function Attrs: noinline nounwind uwtable
+; CHECK-DL-LABEL: define {{[^@]+}}@free_in_scc2
+; CHECK-DL-SAME: (ptr nocapture nonnull [[TMP0:%.*]]) local_unnamed_addr #[[ATTR1]] {
+; CHECK-DL-NEXT:    br label [[CALL:%.*]]
+; CHECK-DL:       call:
+; CHECK-DL-NEXT:    tail call void @free(ptr nocapture nonnull [[TMP0]]) #[[ATTR0]]
+; CHECK-DL-NEXT:    br label [[END:%.*]]
+; CHECK-DL:       rec:
+; CHECK-DL-NEXT:    unreachable
+; CHECK-DL:       end:
+; CHECK-DL-NEXT:    ret void
 ;
   %cmp = icmp eq ptr %0, null
   br i1 %cmp, label %rec, label %call
@@ -90,48 +76,6 @@ end:
   ret void
 }
 
-
-; TEST 4 (positive case)
-; Free doesn't occur.
-; void mutual_recursion1(){
-;    mutual_recursion2();
-; }
-; void mutual_recursion2(){
-;     mutual_recursion1();
-; }
-
-
-define void @mutual_recursion1() #0 {
-; TUNIT: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable
-; TUNIT-LABEL: define {{[^@]+}}@mutual_recursion1
-; TUNIT-SAME: () #[[ATTR4:[0-9]+]] {
-; TUNIT-NEXT:    ret void
-;
-; CGSCC: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
-; CGSCC-LABEL: define {{[^@]+}}@mutual_recursion1
-; CGSCC-SAME: () #[[ATTR3]] {
-; CGSCC-NEXT:    ret void
-;
-  call void @mutual_recursion2()
-  ret void
-}
-
-define void @mutual_recursion2() #0 {
-; TUNIT: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable
-; TUNIT-LABEL: define {{[^@]+}}@mutual_recursion2
-; TUNIT-SAME: () #[[ATTR4]] {
-; TUNIT-NEXT:    ret void
-;
-; CGSCC: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
-; CGSCC-LABEL: define {{[^@]+}}@mutual_recursion2
-; CGSCC-SAME: () #[[ATTR3]] {
-; CGSCC-NEXT:    ret void
-;
-  call void @mutual_recursion1()
-  ret void
-}
-
-
 ; TEST 5
 ; C++ delete operation (negative case)
 ; void delete_op (char p[]){
@@ -141,13 +85,24 @@ define void @mutual_recursion2() #0 {
 define void @_Z9delete_opPc(ptr %0) local_unnamed_addr #0 {
 ; CHECK: Function Attrs: noinline nounwind uwtable
 ; CHECK-LABEL: define {{[^@]+}}@_Z9delete_opPc
-; CHECK-SAME: (ptr nonnull [[TMP0:%.*]]) local_unnamed_addr #[[ATTR1]] {
-; CHECK-NEXT:    br label [[TMP2:%.*]]
-; CHECK:       2:
-; CHECK-NEXT:    tail call void @_ZdaPv(ptr nonnull [[TMP0]]) #[[ATTR2:[0-9]+]]
-; CHECK-NEXT:    br label [[TMP3:%.*]]
+; CHECK-SAME: (ptr [[TMP0:%.*]]) local_unnamed_addr #[[ATTR1]] {
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq ptr [[TMP0]], null
+; CHECK-NEXT:    br i1 [[TMP2]], label [[TMP4:%.*]], label [[TMP3:%.*]]
 ; CHECK:       3:
+; CHECK-NEXT:    tail call void @_ZdaPv(ptr nonnull [[TMP0]]) #[[ATTR2:[0-9]+]]
+; CHECK-NEXT:    br label [[TMP4]]
+; CHECK:       4:
 ; CHECK-NEXT:    ret void
+;
+; CHECK-DL: Function Attrs: noinline nounwind uwtable
+; CHECK-DL-LABEL: define {{[^@]+}}@_Z9delete_opPc
+; CHECK-DL-SAME: (ptr nonnull [[TMP0:%.*]]) local_unnamed_addr #[[ATTR1]] {
+; CHECK-DL-NEXT:    br label [[TMP2:%.*]]
+; CHECK-DL:       2:
+; CHECK-DL-NEXT:    tail call void @_ZdaPv(ptr nonnull [[TMP0]]) #[[ATTR2:[0-9]+]]
+; CHECK-DL-NEXT:    br label [[TMP3:%.*]]
+; CHECK-DL:       3:
+; CHECK-DL-NEXT:    ret void
 ;
   %2 = icmp eq ptr %0, null
   br i1 %2, label %4, label %3
@@ -160,315 +115,6 @@ define void @_Z9delete_opPc(ptr %0) local_unnamed_addr #0 {
   ret void
 }
 
-
-; TEST 6 (negative case)
-; Call realloc
-define noalias ptr @call_realloc(ptr nocapture %0, i64 %1) local_unnamed_addr #0 {
-; CHECK: Function Attrs: noinline nounwind uwtable
-; CHECK-LABEL: define {{[^@]+}}@call_realloc
-; CHECK-SAME: (ptr nocapture nonnull [[TMP0:%.*]], i64 [[TMP1:%.*]]) local_unnamed_addr #[[ATTR1]] {
-; CHECK-NEXT:    [[RET:%.*]] = tail call nonnull ptr @realloc(ptr nocapture nonnull [[TMP0]], i64 [[TMP1]]) #[[ATTR2]]
-; CHECK-NEXT:    ret ptr [[RET]]
-;
-  %ret = tail call ptr @realloc(ptr %0, i64 %1) #2
-  ret ptr %ret
-}
-
-
-; TEST 7 (positive case)
-; Call function declaration with "nofree"
-
-
-; CHECK: Function Attrs:  nofree noinline nounwind memory(none) uwtable
-declare void @nofree_function() nofree readnone #0
-
-define void @call_nofree_function() #0 {
-; TUNIT: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable
-; TUNIT-LABEL: define {{[^@]+}}@call_nofree_function
-; TUNIT-SAME: () #[[ATTR4]] {
-; TUNIT-NEXT:    ret void
-;
-; CGSCC: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable
-; CGSCC-LABEL: define {{[^@]+}}@call_nofree_function
-; CGSCC-SAME: () #[[ATTR5:[0-9]+]] {
-; CGSCC-NEXT:    ret void
-;
-  tail call void @nofree_function()
-  ret void
-}
-
-; TEST 8 (negative case)
-; Call function declaration without "nofree"
-
-
-; CHECK: Function Attrs: noinline nounwind uwtable
-declare void @maybe_free() #0
-
-
-define void @call_maybe_free() #0 {
-; CHECK: Function Attrs: noinline nounwind uwtable
-; CHECK-LABEL: define {{[^@]+}}@call_maybe_free
-; CHECK-SAME: () #[[ATTR1]] {
-; CHECK-NEXT:    tail call void @maybe_free() #[[ATTR0]]
-; CHECK-NEXT:    ret void
-;
-  tail call void @maybe_free()
-  ret void
-}
-
-
-; TEST 9 (negative case)
-; Call both of above functions
-
-define void @call_both() #0 {
-; CHECK: Function Attrs: noinline nounwind uwtable
-; CHECK-LABEL: define {{[^@]+}}@call_both
-; CHECK-SAME: () #[[ATTR1]] {
-; CHECK-NEXT:    tail call void @maybe_free() #[[ATTR0]]
-; CHECK-NEXT:    ret void
-;
-  tail call void @maybe_free()
-  tail call void @nofree_function()
-  ret void
-}
-
-
-; TEST 10 (positive case)
-; Call intrinsic function
-; CHECK: Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
-declare float @llvm.floor.f32(float)
-
-define void @call_floor(float %a) #0 {
-; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
-; CHECK-LABEL: define {{[^@]+}}@call_floor
-; CHECK-SAME: (float [[A:%.*]]) #[[ATTR3]] {
-; CHECK-NEXT:    ret void
-;
-  tail call float @llvm.floor.f32(float %a)
-  ret void
-}
-
-define float @call_floor2(float %a) #0 {
-; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
-; CHECK-LABEL: define {{[^@]+}}@call_floor2
-; CHECK-SAME: (float nofpclass(sub) [[A:%.*]]) #[[ATTR3]] {
-; CHECK-NEXT:    [[C:%.*]] = tail call nofpclass(sub) float @llvm.floor.f32(float nofpclass(sub) [[A]]) #[[ATTR14:[0-9]+]]
-; CHECK-NEXT:    ret float [[C]]
-;
-  %c = tail call float @llvm.floor.f32(float %a)
-  ret float %c
-}
-
-; TEST 11 (positive case)
-; Check propagation.
-
-define void @f1() #0 {
-; TUNIT: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable
-; TUNIT-LABEL: define {{[^@]+}}@f1
-; TUNIT-SAME: () #[[ATTR4]] {
-; TUNIT-NEXT:    ret void
-;
-; CGSCC: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable
-; CGSCC-LABEL: define {{[^@]+}}@f1
-; CGSCC-SAME: () #[[ATTR5]] {
-; CGSCC-NEXT:    ret void
-;
-  tail call void @nofree_function()
-  ret void
-}
-
-define void @f2() #0 {
-; TUNIT: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable
-; TUNIT-LABEL: define {{[^@]+}}@f2
-; TUNIT-SAME: () #[[ATTR4]] {
-; TUNIT-NEXT:    ret void
-;
-; CGSCC: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable
-; CGSCC-LABEL: define {{[^@]+}}@f2
-; CGSCC-SAME: () #[[ATTR5]] {
-; CGSCC-NEXT:    ret void
-;
-  tail call void @f1()
-  ret void
-}
-
-; TEST 12 NoFree argument - positive.
-define double @test12(ptr nocapture readonly %a) {
-; CHECK: Function Attrs: nofree nounwind
-; CHECK-LABEL: define {{[^@]+}}@test12
-; CHECK-SAME: (ptr nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) [[A:%.*]]) #[[ATTR7:[0-9]+]] {
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[TMP0:%.*]] = load double, ptr [[A]], align 8
-; CHECK-NEXT:    [[CALL:%.*]] = tail call double @cos(double [[TMP0]]) #[[ATTR8:[0-9]+]]
-; CHECK-NEXT:    ret double [[CALL]]
-;
-entry:
-  %0 = load double, ptr %a, align 8
-  %call = tail call double @cos(double %0) #2
-  ret double %call
-}
-
-declare double @cos(double) nobuiltin nounwind nofree
-
-; FIXME: %a should be nofree.
-; TEST 13 NoFree argument - positive.
-define noalias ptr @test13(ptr nocapture readonly %a) {
-; CHECK: Function Attrs: nounwind
-; CHECK-LABEL: define {{[^@]+}}@test13
-; CHECK-SAME: (ptr nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) [[A:%.*]]) #[[ATTR0]] {
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[TMP0:%.*]] = load i64, ptr [[A]], align 8
-; CHECK-NEXT:    [[CALL:%.*]] = tail call noalias nonnull ptr @malloc(i64 [[TMP0]]) #[[ATTR2]]
-; CHECK-NEXT:    ret ptr [[CALL]]
-;
-entry:
-  %0 = load i64, ptr %a, align 8
-  %call = tail call noalias ptr @malloc(i64 %0) #2
-  ret ptr %call
-}
-
-define void @test14(ptr nocapture %0, ptr nocapture %1) {
-; CHECK: Function Attrs: nounwind
-; CHECK-LABEL: define {{[^@]+}}@test14
-; CHECK-SAME: (ptr nocapture nonnull [[TMP0:%.*]], ptr nocapture nofree nonnull readnone [[TMP1:%.*]]) #[[ATTR0]] {
-; CHECK-NEXT:    tail call void @free(ptr nocapture nonnull [[TMP0]]) #[[ATTR0]]
-; CHECK-NEXT:    ret void
-;
-  tail call void @free(ptr %0) #1
-  ret void
-}
-
-; UTC_ARGS: --enable
-
-define void @nonnull_assume_pos(ptr %arg1, ptr %arg2, ptr %arg3, ptr %arg4) {
-; ATTRIBUTOR-LABEL: define {{[^@]+}}@nonnull_assume_pos
-; ATTRIBUTOR-SAME: (ptr nofree [[ARG1:%.*]], ptr [[ARG2:%.*]], ptr nofree [[ARG3:%.*]], ptr [[ARG4:%.*]])
-; ATTRIBUTOR-NEXT:    call void @llvm.assume(i1 true) #11 [ "nofree"(ptr [[ARG1]]), "nofree"(ptr [[ARG3]]) ]
-; ATTRIBUTOR-NEXT:    call void @unknown(ptr nofree [[ARG1]], ptr [[ARG2]], ptr nofree [[ARG3]], ptr [[ARG4]])
-; ATTRIBUTOR-NEXT:    ret void
-;
-; CHECK-LABEL: define {{[^@]+}}@nonnull_assume_pos
-; CHECK-SAME: (ptr nofree nonnull [[ARG1:%.*]], ptr nonnull [[ARG2:%.*]], ptr nofree nonnull [[ARG3:%.*]], ptr nonnull [[ARG4:%.*]]) {
-; CHECK-NEXT:    call void @llvm.assume(i1 noundef true) #[[ATTR15:[0-9]+]] [ "nofree"(ptr [[ARG1]]), "nofree"(ptr [[ARG3]]) ]
-; CHECK-NEXT:    call void @unknown(ptr nofree nonnull [[ARG1]], ptr nonnull [[ARG2]], ptr nofree nonnull [[ARG3]], ptr nonnull [[ARG4]])
-; CHECK-NEXT:    ret void
-;
-  call void @llvm.assume(i1 true) ["nofree"(ptr %arg1), "nofree"(ptr %arg3)]
-  call void @unknown(ptr %arg1, ptr %arg2, ptr %arg3, ptr %arg4)
-  ret void
-}
-define void @nonnull_assume_neg(ptr %arg1, ptr %arg2, ptr %arg3, ptr %arg4) {
-; ATTRIBUTOR-LABEL: define {{[^@]+}}@nonnull_assume_neg
-; ATTRIBUTOR-SAME: (ptr [[ARG1:%.*]], ptr [[ARG2:%.*]], ptr [[ARG3:%.*]], ptr [[ARG4:%.*]])
-; ATTRIBUTOR-NEXT:    call void @unknown(ptr [[ARG1]], ptr [[ARG2]], ptr [[ARG3]], ptr [[ARG4]])
-; ATTRIBUTOR-NEXT:    call void @llvm.assume(i1 true) [ "nofree"(ptr [[ARG1]]), "nofree"(ptr [[ARG3]]) ]
-; ATTRIBUTOR-NEXT:    ret void
-;
-; CHECK-LABEL: define {{[^@]+}}@nonnull_assume_neg
-; CHECK-SAME: (ptr nonnull [[ARG1:%.*]], ptr nonnull [[ARG2:%.*]], ptr nonnull [[ARG3:%.*]], ptr nonnull [[ARG4:%.*]]) {
-; CHECK-NEXT:    call void @unknown(ptr nonnull [[ARG1]], ptr nonnull [[ARG2]], ptr nonnull [[ARG3]], ptr nonnull [[ARG4]])
-; CHECK-NEXT:    call void @llvm.assume(i1 noundef true) [ "nofree"(ptr [[ARG1]]), "nofree"(ptr [[ARG3]]) ]
-; CHECK-NEXT:    ret void
-;
-  call void @unknown(ptr %arg1, ptr %arg2, ptr %arg3, ptr %arg4)
-  call void @llvm.assume(i1 true) ["nofree"(ptr %arg1), "nofree"(ptr %arg3)]
-  ret void
-}
-define void @nonnull_assume_call(ptr %arg1, ptr %arg2, ptr %arg3, ptr %arg4) {
-; ATTRIBUTOR-LABEL: define {{[^@]+}}@nonnull_assume_call
-; ATTRIBUTOR-SAME: (ptr [[ARG1:%.*]], ptr [[ARG2:%.*]], ptr [[ARG3:%.*]], ptr [[ARG4:%.*]])
-; ATTRIBUTOR-NEXT:    call void @unknown(ptr [[ARG1]], ptr [[ARG2]], ptr [[ARG3]], ptr [[ARG4]])
-; ATTRIBUTOR-NEXT:    call void @use_i8_ptr(ptr noalias readnone [[ARG1]])
-; ATTRIBUTOR-NEXT:    call void @use_i8_ptr(ptr noalias readnone [[ARG2]])
-; ATTRIBUTOR-NEXT:    call void @llvm.assume(i1 true) [ "nofree"(ptr [[ARG1]]), "nofree"(ptr [[ARG3]]) ]
-; ATTRIBUTOR-NEXT:    call void @use_i8_ptr(ptr noalias nofree readnone [[ARG3]])
-; ATTRIBUTOR-NEXT:    call void @use_i8_ptr(ptr noalias readnone [[ARG4]])
-; ATTRIBUTOR-NEXT:    call void @use_i8_ptr_ret(ptr noalias nofree readnone [[ARG1]])
-; ATTRIBUTOR-NEXT:    call void @use_i8_ptr_ret(ptr noalias readnone [[ARG2]])
-; ATTRIBUTOR-NEXT:    call void @llvm.assume(i1 true) [ "nofree"(ptr [[ARG1]]), "nofree"(ptr [[ARG4]]) ]
-; ATTRIBUTOR-NEXT:    call void @use_i8_ptr_ret(ptr noalias nofree readnone [[ARG3]])
-; ATTRIBUTOR-NEXT:    call void @use_i8_ptr_ret(ptr noalias nofree readnone [[ARG4]])
-; ATTRIBUTOR-NEXT:    ret void
-;
-; CHECK-LABEL: define {{[^@]+}}@nonnull_assume_call
-; CHECK-SAME: (ptr nonnull [[ARG1:%.*]], ptr nonnull [[ARG2:%.*]], ptr nonnull [[ARG3:%.*]], ptr nonnull [[ARG4:%.*]]) {
-; CHECK-NEXT:    call void @unknown(ptr nonnull [[ARG1]], ptr nonnull [[ARG2]], ptr nonnull [[ARG3]], ptr nonnull [[ARG4]])
-; CHECK-NEXT:    call void @use_i8_ptr(ptr noalias nocapture nofree nonnull readnone [[ARG1]]) #[[ATTR0]]
-; CHECK-NEXT:    call void @use_i8_ptr(ptr noalias nocapture nofree nonnull readnone [[ARG2]]) #[[ATTR0]]
-; CHECK-NEXT:    call void @llvm.assume(i1 noundef true) [ "nofree"(ptr [[ARG1]]), "nofree"(ptr [[ARG3]]) ]
-; CHECK-NEXT:    call void @use_i8_ptr(ptr noalias nocapture nofree nonnull readnone [[ARG3]]) #[[ATTR0]]
-; CHECK-NEXT:    call void @use_i8_ptr(ptr noalias nocapture nofree nonnull readnone [[ARG4]]) #[[ATTR0]]
-; CHECK-NEXT:    call void @use_i8_ptr_ret(ptr noalias nocapture nofree nonnull readnone [[ARG1]]) #[[ATTR0]]
-; CHECK-NEXT:    call void @use_i8_ptr_ret(ptr noalias nocapture nofree nonnull readnone [[ARG2]]) #[[ATTR0]]
-; CHECK-NEXT:    call void @llvm.assume(i1 noundef true) [ "nofree"(ptr [[ARG1]]), "nofree"(ptr [[ARG4]]) ]
-; CHECK-NEXT:    call void @use_i8_ptr_ret(ptr noalias nocapture nofree nonnull readnone [[ARG3]]) #[[ATTR0]]
-; CHECK-NEXT:    call void @use_i8_ptr_ret(ptr noalias nocapture nofree nonnull readnone [[ARG4]]) #[[ATTR0]]
-; CHECK-NEXT:    ret void
-;
-  call void @unknown(ptr %arg1, ptr %arg2, ptr %arg3, ptr %arg4)
-  call void @use_i8_ptr(ptr %arg1)
-  call void @use_i8_ptr(ptr %arg2)
-  call void @llvm.assume(i1 true) ["nofree"(ptr %arg1), "nofree"(ptr %arg3)]
-  call void @use_i8_ptr(ptr %arg3)
-  call void @use_i8_ptr(ptr %arg4)
-  call void @use_i8_ptr_ret(ptr %arg1)
-  call void @use_i8_ptr_ret(ptr %arg2)
-  call void @llvm.assume(i1 true) ["nofree"(ptr %arg1), "nofree"(ptr %arg4)]
-  call void @use_i8_ptr_ret(ptr %arg3)
-  call void @use_i8_ptr_ret(ptr %arg4)
-  ret void
-}
-
-; FIXME: function is nofree
-define weak void @implied_nofree1() readnone {
-; CHECK: Function Attrs: nosync memory(none)
-; CHECK-LABEL: define {{[^@]+}}@implied_nofree1
-; CHECK-SAME: () #[[ATTR9:[0-9]+]] {
-; CHECK-NEXT:    ret void
-;
-  ret void
-}
-; FIXME: function is nofree
-define weak void @implied_nofree2() readonly {
-; CHECK: Function Attrs: nosync memory(read)
-; CHECK-LABEL: define {{[^@]+}}@implied_nofree2
-; CHECK-SAME: () #[[ATTR10:[0-9]+]] {
-; CHECK-NEXT:    ret void
-;
-  ret void
-}
-define weak void @implied_nofree3(ptr readnone %a) {
-; CHECK-LABEL: define {{[^@]+}}@implied_nofree3
-; CHECK-SAME: (ptr nofree readnone [[A:%.*]]) {
-; CHECK-NEXT:    ret void
-;
-  ret void
-}
-define weak void @implied_nofree4(ptr readonly %a) {
-; CHECK-LABEL: define {{[^@]+}}@implied_nofree4
-; CHECK-SAME: (ptr nofree readonly [[A:%.*]]) {
-; CHECK-NEXT:    ret void
-;
-  ret void
-}
-; FIXME: %a is nofree
-define weak void @implied_nofree5(ptr %a) readonly {
-; CHECK: Function Attrs: nosync memory(read)
-; CHECK-LABEL: define {{[^@]+}}@implied_nofree5
-; CHECK-SAME: (ptr [[A:%.*]]) #[[ATTR10]] {
-; CHECK-NEXT:    ret void
-;
-  ret void
-}
-define weak void @implied_nofree6(ptr %a) nofree {
-; CHECK: Function Attrs: nofree
-; CHECK-LABEL: define {{[^@]+}}@implied_nofree6
-; CHECK-SAME: (ptr nofree [[A:%.*]]) #[[ATTR11:[0-9]+]] {
-; CHECK-NEXT:    ret void
-;
-  ret void
-}
-
 declare void @llvm.assume(i1)
 declare void @unknown(ptr, ptr, ptr, ptr)
 declare void @use_i8_ptr(ptr nocapture readnone) nounwind
@@ -480,37 +126,15 @@ attributes #0 = { nounwind uwtable noinline }
 attributes #1 = { nounwind }
 attributes #2 = { nobuiltin nounwind }
 ;.
-; TUNIT: attributes #[[ATTR0]] = { nounwind }
-; TUNIT: attributes #[[ATTR1]] = { noinline nounwind uwtable }
-; TUNIT: attributes #[[ATTR2]] = { nobuiltin nounwind }
-; TUNIT: attributes #[[ATTR3]] = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable }
-; TUNIT: attributes #[[ATTR4]] = { mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable }
-; TUNIT: attributes #[[ATTR5:[0-9]+]] = { nofree noinline nounwind memory(none) uwtable }
-; TUNIT: attributes #[[ATTR6:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
-; TUNIT: attributes #[[ATTR7]] = { nofree nounwind }
-; TUNIT: attributes #[[ATTR8]] = { nobuiltin nofree nounwind }
-; TUNIT: attributes #[[ATTR9]] = { nosync memory(none) }
-; TUNIT: attributes #[[ATTR10]] = { nosync memory(read) }
-; TUNIT: attributes #[[ATTR11]] = { nofree }
-; TUNIT: attributes #[[ATTR12:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: write) }
-; TUNIT: attributes #[[ATTR13:[0-9]+]] = { nounwind willreturn }
-; TUNIT: attributes #[[ATTR14]] = { nofree nosync willreturn }
-; TUNIT: attributes #[[ATTR15]] = { nofree willreturn memory(write) }
+; CHECK: attributes #[[ATTR0]] = { nounwind }
+; CHECK: attributes #[[ATTR1]] = { noinline nounwind uwtable }
+; CHECK: attributes #[[ATTR2]] = { nobuiltin nounwind }
+; CHECK: attributes #[[ATTR3:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: write) }
+; CHECK: attributes #[[ATTR4:[0-9]+]] = { nounwind willreturn }
 ;.
-; CGSCC: attributes #[[ATTR0]] = { nounwind }
-; CGSCC: attributes #[[ATTR1]] = { noinline nounwind uwtable }
-; CGSCC: attributes #[[ATTR2]] = { nobuiltin nounwind }
-; CGSCC: attributes #[[ATTR3]] = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable }
-; CGSCC: attributes #[[ATTR4:[0-9]+]] = { nofree noinline nounwind memory(none) uwtable }
-; CGSCC: attributes #[[ATTR5]] = { mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable }
-; CGSCC: attributes #[[ATTR6:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
-; CGSCC: attributes #[[ATTR7]] = { nofree nounwind }
-; CGSCC: attributes #[[ATTR8]] = { nobuiltin nofree nounwind }
-; CGSCC: attributes #[[ATTR9]] = { nosync memory(none) }
-; CGSCC: attributes #[[ATTR10]] = { nosync memory(read) }
-; CGSCC: attributes #[[ATTR11]] = { nofree }
-; CGSCC: attributes #[[ATTR12:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: write) }
-; CGSCC: attributes #[[ATTR13:[0-9]+]] = { nounwind willreturn }
-; CGSCC: attributes #[[ATTR14]] = { nofree nosync willreturn }
-; CGSCC: attributes #[[ATTR15]] = { nofree willreturn memory(write) }
+; CHECK-DL: attributes #[[ATTR0]] = { nounwind }
+; CHECK-DL: attributes #[[ATTR1]] = { noinline nounwind uwtable }
+; CHECK-DL: attributes #[[ATTR2]] = { nobuiltin nounwind }
+; CHECK-DL: attributes #[[ATTR3:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: write) }
+; CHECK-DL: attributes #[[ATTR4:[0-9]+]] = { nounwind willreturn }
 ;.
diff --git a/llvm/test/Transforms/Attributor/read_write_returned_arguments_scc-dl-sentinel.ll b/llvm/test/Transforms/Attributor/read_write_returned_arguments_scc-dl-sentinel.ll
index 5c0378ebaa356..16792716e8d63 100755
--- a/llvm/test/Transforms/Attributor/read_write_returned_arguments_scc-dl-sentinel.ll
+++ b/llvm/test/Transforms/Attributor/read_write_returned_arguments_scc-dl-sentinel.ll
@@ -1,7 +1,8 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
 ; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal  -attributor-annotate-decl-cs  -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal  -attributor-annotate-decl-cs  -data-layout=z0:1-z2:neg1-z3:neg1-z5:neg1 -S < %s | FileCheck %s --check-prefixes=CHECK-DL,TUNIT-DL
 ; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal  -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
-
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal  -attributor-annotate-decl-cs  -data-layout=z0:1-z2:neg1-z3:neg1-z5:neg1 -S < %s | FileCheck %s --check-prefixes=CHECK-DL,CGSCC-DL
 ;
 ; This is an evolved example to stress test SCC parameter attribute propagation.
 ; The SCC in this test is made up of the following six function, three of which
@@ -30,22 +31,41 @@
 ;   6 - Number of arguments marked readonly
 ;   6 - Number of arguments marked returned
 ;
-target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-z0:1-z2:neg1-z3:neg1-z5:neg1-S128"
 
 define ptr @external_ret2_nrw(ptr %n0, ptr %r0, ptr %w0) {
 ; TUNIT: Function Attrs: nofree nosync nounwind memory(argmem: readwrite)
 ; TUNIT-LABEL: define {{[^@]+}}@external_ret2_nrw
-; TUNIT-SAME: (ptr nocapture nofree nonnull readnone [[N0:%.*]], ptr nocapture nofree nonnull readonly [[R0:%.*]], ptr nofree nonnull returned writeonly "no-capture-maybe-returned" [[W0:%.*]]) #[[ATTR0:[0-9]+]] {
+; TUNIT-SAME: (ptr nofree [[N0:%.*]], ptr nofree [[R0:%.*]], ptr nofree returned [[W0:%.*]]) #[[ATTR0:[0-9]+]] {
 ; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    [[CALL:%.*]] = call ptr @internal_ret0_nw(ptr nocapture nofree nonnull writeonly [[W0]]) #[[ATTR4:[0-9]+]]
-; TUNIT-NEXT:    unreachable
+; TUNIT-NEXT:    [[CALL:%.*]] = call ptr @internal_ret0_nw(ptr nofree [[N0]], ptr nofree [[W0]]) #[[ATTR3:[0-9]+]]
+; TUNIT-NEXT:    [[CALL1:%.*]] = call ptr @internal_ret1_rrw(ptr nofree noundef align 4 [[R0]], ptr nofree align 4 [[R0]], ptr nofree [[W0]]) #[[ATTR3]]
+; TUNIT-NEXT:    [[CALL2:%.*]] = call ptr @external_sink_ret2_nrw(ptr nofree [[N0]], ptr nocapture nofree readonly align 4 [[R0]], ptr nofree writeonly "no-capture-maybe-returned" [[W0]]) #[[ATTR3]]
+; TUNIT-NEXT:    [[CALL3:%.*]] = call ptr @internal_ret1_rw(ptr nofree noundef align 4 [[R0]], ptr nofree [[W0]]) #[[ATTR3]]
+; TUNIT-NEXT:    ret ptr [[W0]]
+;
+; TUNIT-DL: Function Attrs: nofree nosync nounwind memory(argmem: readwrite)
+; TUNIT-DL-LABEL: define {{[^@]+}}@external_ret2_nrw
+; TUNIT-DL-SAME: (ptr nocapture nofree nonnull readnone [[N0:%.*]], ptr nocapture nofree nonnull readonly [[R0:%.*]], ptr nofree nonnull returned writeonly "no-capture-maybe-returned" [[W0:%.*]]) #[[ATTR0:[0-9]+]] {
+; TUNIT-DL-NEXT:  entry:
+; TUNIT-DL-NEXT:    [[CALL:%.*]] = call ptr @internal_ret0_nw(ptr nocapture nofree nonnull writeonly [[W0]]) #[[ATTR4:[0-9]+]]
+; TUNIT-DL-NEXT:    unreachable
 ;
 ; CGSCC: Function Attrs: nofree nosync nounwind memory(argmem: readwrite)
 ; CGSCC-LABEL: define {{[^@]+}}@external_ret2_nrw
-; CGSCC-SAME: (ptr nocapture nofree nonnull readnone [[N0:%.*]], ptr nocapture nofree nonnull readonly [[R0:%.*]], ptr nofree nonnull returned [[W0:%.*]]) #[[ATTR0:[0-9]+]] {
+; CGSCC-SAME: (ptr nofree [[N0:%.*]], ptr nofree [[R0:%.*]], ptr nofree returned [[W0:%.*]]) #[[ATTR0:[0-9]+]] {
 ; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    [[CALL:%.*]] = call ptr @internal_ret0_nw(ptr noalias nocapture nofree nonnull readnone [[N0]], ptr nofree nonnull [[W0]]) #[[ATTR3:[0-9]+]]
-; CGSCC-NEXT:    unreachable
+; CGSCC-NEXT:    [[CALL:%.*]] = call ptr @internal_ret0_nw(ptr nofree [[N0]], ptr nofree [[W0]]) #[[ATTR2:[0-9]+]]
+; CGSCC-NEXT:    [[CALL1:%.*]] = call ptr @internal_ret1_rrw(ptr nofree noundef align 4 [[R0]], ptr nofree align 4 [[R0]], ptr nofree [[W0]]) #[[ATTR2]]
+; CGSCC-NEXT:    [[CALL2:%.*]] = call ptr @external_sink_ret2_nrw(ptr nofree [[N0]], ptr nocapture nofree readonly align 4 [[R0]], ptr nofree writeonly [[W0]]) #[[ATTR3:[0-9]+]]
+; CGSCC-NEXT:    [[CALL3:%.*]] = call ptr @internal_ret1_rw(ptr nofree noundef align 4 [[R0]], ptr nofree [[W0]]) #[[ATTR2]]
+; CGSCC-NEXT:    ret ptr [[W0]]
+;
+; CGSCC-DL: Function Attrs: nofree nosync nounwind memory(argmem: readwrite)
+; CGSCC-DL-LABEL: define {{[^@]+}}@external_ret2_nrw
+; CGSCC-DL-SAME: (ptr nocapture nofree nonnull readnone [[N0:%.*]], ptr nocapture nofree nonnull readonly [[R0:%.*]], ptr nofree nonnull returned [[W0:%.*]]) #[[ATTR0:[0-9]+]] {
+; CGSCC-DL-NEXT:  entry:
+; CGSCC-DL-NEXT:    [[CALL:%.*]] = call ptr @internal_ret0_nw(ptr noalias nocapture nofree nonnull readnone [[N0]], ptr nofree nonnull [[W0]]) #[[ATTR3:[0-9]+]]
+; CGSCC-DL-NEXT:    unreachable
 ;
 entry:
   %call = call ptr @internal_ret0_nw(ptr %n0, ptr %w0)
@@ -56,51 +76,101 @@ entry:
 }
 
 define internal ptr @internal_ret0_nw(ptr %n0, ptr %w0) {
-; TUNIT: Function Attrs: nofree noreturn nosync nounwind memory(argmem: readwrite)
+; TUNIT: Function Attrs: nofree nosync nounwind memory(argmem: readwrite)
 ; TUNIT-LABEL: define {{[^@]+}}@internal_ret0_nw
-; TUNIT-SAME: (ptr nocapture nofree nonnull writeonly [[W0:%.*]]) #[[ATTR1:[0-9]+]] {
+; TUNIT-SAME: (ptr nofree [[N0:%.*]], ptr nofree [[W0:%.*]]) #[[ATTR0]] {
 ; TUNIT-NEXT:  entry:
 ; TUNIT-NEXT:    [[R0:%.*]] = alloca i32, align 4
 ; TUNIT-NEXT:    [[R1:%.*]] = alloca i32, align 4
-; TUNIT-NEXT:    br label [[IF_END:%.*]]
+; TUNIT-NEXT:    [[TOBOOL:%.*]] = icmp ne ptr [[N0]], null
+; TUNIT-NEXT:    br i1 [[TOBOOL]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]
 ; TUNIT:       if.then:
-; TUNIT-NEXT:    unreachable
+; TUNIT-NEXT:    br label [[RETURN:%.*]]
 ; TUNIT:       if.end:
 ; TUNIT-NEXT:    store i32 3, ptr [[R0]], align 4
 ; TUNIT-NEXT:    store i32 5, ptr [[R1]], align 4
 ; TUNIT-NEXT:    store i32 1, ptr [[W0]], align 4
-; TUNIT-NEXT:    [[CALL:%.*]] = call ptr @internal_ret1_rrw(ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0]], ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R1]], ptr nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[W0]]) #[[ATTR5:[0-9]+]]
-; TUNIT-NEXT:    [[CALL1:%.*]] = call ptr @external_ret2_nrw(ptr noalias nocapture nofree nonnull readnone undef, ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0]], ptr nofree nonnull writeonly align 4 dereferenceable(4) "no-capture-maybe-returned" [[W0]]) #[[ATTR5]]
-; TUNIT-NEXT:    [[CALL2:%.*]] = call ptr @external_ret2_nrw(ptr noalias nocapture nofree nonnull readnone undef, ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R1]], ptr nofree nonnull writeonly align 4 dereferenceable(4) "no-capture-maybe-returned" [[W0]]) #[[ATTR5]]
-; TUNIT-NEXT:    [[CALL3:%.*]] = call ptr @external_sink_ret2_nrw(ptr noalias nocapture nofree nonnull readnone undef, ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0]], ptr nofree nonnull writeonly align 4 dereferenceable(4) "no-capture-maybe-returned" [[W0]]) #[[ATTR5]]
-; TUNIT-NEXT:    [[CALL4:%.*]] = call ptr @external_sink_ret2_nrw(ptr noalias nocapture nofree nonnull readnone undef, ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R1]], ptr nofree nonnull writeonly align 4 dereferenceable(4) "no-capture-maybe-returned" [[W0]]) #[[ATTR5]]
-; TUNIT-NEXT:    [[CALL5:%.*]] = call ptr @internal_ret0_nw(ptr nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[W0]]) #[[ATTR4]]
-; TUNIT-NEXT:    unreachable
+; TUNIT-NEXT:    [[CALL:%.*]] = call ptr @internal_ret1_rrw(ptr nofree noundef nonnull align 4 dereferenceable(4) [[R0]], ptr nofree noundef nonnull align 4 dereferenceable(4) [[R1]], ptr nofree nonnull align 4 dereferenceable(4) [[W0]]) #[[ATTR3]]
+; TUNIT-NEXT:    [[CALL1:%.*]] = call ptr @external_ret2_nrw(ptr nofree nonnull [[N0]], ptr nofree noundef nonnull align 4 dereferenceable(4) [[R0]], ptr nofree nonnull align 4 dereferenceable(4) [[W0]]) #[[ATTR3]]
+; TUNIT-NEXT:    [[CALL2:%.*]] = call ptr @external_ret2_nrw(ptr nofree nonnull [[N0]], ptr nofree noundef nonnull align 4 dereferenceable(4) [[R1]], ptr nofree nonnull align 4 dereferenceable(4) [[W0]]) #[[ATTR3]]
+; TUNIT-NEXT:    [[CALL3:%.*]] = call ptr @external_sink_ret2_nrw(ptr nofree nonnull [[N0]], ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0]], ptr nofree nonnull writeonly align 4 dereferenceable(4) "no-capture-maybe-returned" [[W0]]) #[[ATTR3]]
+; TUNIT-NEXT:    [[CALL4:%.*]] = call ptr @external_sink_ret2_nrw(ptr nofree nonnull [[N0]], ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R1]], ptr nofree nonnull writeonly align 4 dereferenceable(4) "no-capture-maybe-returned" [[W0]]) #[[ATTR3]]
+; TUNIT-NEXT:    [[CALL5:%.*]] = call ptr @internal_ret0_nw(ptr nofree nonnull [[N0]], ptr nofree nonnull align 4 dereferenceable(4) [[W0]]) #[[ATTR3]]
+; TUNIT-NEXT:    br label [[RETURN]]
 ; TUNIT:       return:
-; TUNIT-NEXT:    unreachable
+; TUNIT-NEXT:    [[RETVAL_0:%.*]] = phi ptr [ [[CALL5]], [[IF_END]] ], [ [[N0]], [[IF_THEN]] ]
+; TUNIT-NEXT:    ret ptr [[RETVAL_0]]
+;
+; TUNIT-DL: Function Attrs: nofree noreturn nosync nounwind memory(argmem: readwrite)
+; TUNIT-DL-LABEL: define {{[^@]+}}@internal_ret0_nw
+; TUNIT-DL-SAME: (ptr nocapture nofree nonnull writeonly [[W0:%.*]]) #[[ATTR1:[0-9]+]] {
+; TUNIT-DL-NEXT:  entry:
+; TUNIT-DL-NEXT:    [[R0:%.*]] = alloca i32, align 4
+; TUNIT-DL-NEXT:    [[R1:%.*]] = alloca i32, align 4
+; TUNIT-DL-NEXT:    br label [[IF_END:%.*]]
+; TUNIT-DL:       if.then:
+; TUNIT-DL-NEXT:    unreachable
+; TUNIT-DL:       if.end:
+; TUNIT-DL-NEXT:    store i32 3, ptr [[R0]], align 4
+; TUNIT-DL-NEXT:    store i32 5, ptr [[R1]], align 4
+; TUNIT-DL-NEXT:    store i32 1, ptr [[W0]], align 4
+; TUNIT-DL-NEXT:    [[CALL:%.*]] = call ptr @internal_ret1_rrw(ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0]], ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R1]], ptr nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[W0]]) #[[ATTR5:[0-9]+]]
+; TUNIT-DL-NEXT:    [[CALL1:%.*]] = call ptr @external_ret2_nrw(ptr noalias nocapture nofree nonnull readnone undef, ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0]], ptr nofree nonnull writeonly align 4 dereferenceable(4) "no-capture-maybe-returned" [[W0]]) #[[ATTR5]]
+; TUNIT-DL-NEXT:    [[CALL2:%.*]] = call ptr @external_ret2_nrw(ptr noalias nocapture nofree nonnull readnone undef, ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R1]], ptr nofree nonnull writeonly align 4 dereferenceable(4) "no-capture-maybe-returned" [[W0]]) #[[ATTR5]]
+; TUNIT-DL-NEXT:    [[CALL3:%.*]] = call ptr @external_sink_ret2_nrw(ptr noalias nocapture nofree nonnull readnone undef, ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0]], ptr nofree nonnull writeonly align 4 dereferenceable(4) "no-capture-maybe-returned" [[W0]]) #[[ATTR5]]
+; TUNIT-DL-NEXT:    [[CALL4:%.*]] = call ptr @external_sink_ret2_nrw(ptr noalias nocapture nofree nonnull readnone undef, ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R1]], ptr nofree nonnull writeonly align 4 dereferenceable(4) "no-capture-maybe-returned" [[W0]]) #[[ATTR5]]
+; TUNIT-DL-NEXT:    [[CALL5:%.*]] = call ptr @internal_ret0_nw(ptr nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[W0]]) #[[ATTR4]]
+; TUNIT-DL-NEXT:    unreachable
+; TUNIT-DL:       return:
+; TUNIT-DL-NEXT:    unreachable
 ;
-; CGSCC: Function Attrs: nofree noreturn nosync nounwind memory(argmem: readwrite)
+; CGSCC: Function Attrs: nofree nosync nounwind memory(argmem: readwrite)
 ; CGSCC-LABEL: define {{[^@]+}}@internal_ret0_nw
-; CGSCC-SAME: (ptr noalias nocapture nofree nonnull readnone [[N0:%.*]], ptr nofree nonnull [[W0:%.*]]) #[[ATTR1:[0-9]+]] {
+; CGSCC-SAME: (ptr nofree [[N0:%.*]], ptr nofree [[W0:%.*]]) #[[ATTR0]] {
 ; CGSCC-NEXT:  entry:
 ; CGSCC-NEXT:    [[R0:%.*]] = alloca i32, align 4
 ; CGSCC-NEXT:    [[R1:%.*]] = alloca i32, align 4
-; CGSCC-NEXT:    br label [[IF_END:%.*]]
+; CGSCC-NEXT:    [[TOBOOL:%.*]] = icmp ne ptr [[N0]], null
+; CGSCC-NEXT:    br i1 [[TOBOOL]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]
 ; CGSCC:       if.then:
-; CGSCC-NEXT:    unreachable
+; CGSCC-NEXT:    br label [[RETURN:%.*]]
 ; CGSCC:       if.end:
 ; CGSCC-NEXT:    store i32 3, ptr [[R0]], align 4
 ; CGSCC-NEXT:    store i32 5, ptr [[R1]], align 4
 ; CGSCC-NEXT:    store i32 1, ptr [[W0]], align 4
-; CGSCC-NEXT:    [[CALL:%.*]] = call ptr @internal_ret1_rrw(ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0]], ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R1]], ptr nofree nonnull align 4 dereferenceable(4) [[W0]]) #[[ATTR4:[0-9]+]]
-; CGSCC-NEXT:    [[CALL1:%.*]] = call ptr @external_ret2_nrw(ptr noalias nocapture nofree nonnull readnone [[N0]], ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0]], ptr nofree nonnull align 4 dereferenceable(4) [[W0]]) #[[ATTR4]]
-; CGSCC-NEXT:    [[CALL2:%.*]] = call ptr @external_ret2_nrw(ptr noalias nocapture nofree nonnull readnone [[N0]], ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R1]], ptr nofree nonnull align 4 dereferenceable(4) [[W0]]) #[[ATTR4]]
-; CGSCC-NEXT:    [[CALL3:%.*]] = call ptr @external_sink_ret2_nrw(ptr noalias nocapture nofree nonnull readnone [[N0]], ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0]], ptr nofree nonnull writeonly align 4 dereferenceable(4) [[W0]]) #[[ATTR5:[0-9]+]]
-; CGSCC-NEXT:    [[CALL4:%.*]] = call ptr @external_sink_ret2_nrw(ptr noalias nocapture nofree nonnull readnone [[N0]], ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R1]], ptr nofree nonnull writeonly align 4 dereferenceable(4) [[W0]]) #[[ATTR5]]
-; CGSCC-NEXT:    [[CALL5:%.*]] = call ptr @internal_ret0_nw(ptr noalias nocapture nofree nonnull readnone [[N0]], ptr nofree nonnull align 4 dereferenceable(4) [[W0]]) #[[ATTR3]]
-; CGSCC-NEXT:    unreachable
+; CGSCC-NEXT:    [[CALL:%.*]] = call ptr @internal_ret1_rrw(ptr nofree noundef nonnull align 4 dereferenceable(4) [[R0]], ptr nofree noundef nonnull align 4 dereferenceable(4) [[R1]], ptr nofree nonnull align 4 dereferenceable(4) [[W0]]) #[[ATTR2]]
+; CGSCC-NEXT:    [[CALL1:%.*]] = call ptr @external_ret2_nrw(ptr nofree nonnull [[N0]], ptr nofree noundef nonnull align 4 dereferenceable(4) [[R0]], ptr nofree nonnull align 4 dereferenceable(4) [[W0]]) #[[ATTR2]]
+; CGSCC-NEXT:    [[CALL2:%.*]] = call ptr @external_ret2_nrw(ptr nofree nonnull [[N0]], ptr nofree noundef nonnull align 4 dereferenceable(4) [[R1]], ptr nofree nonnull align 4 dereferenceable(4) [[W0]]) #[[ATTR2]]
+; CGSCC-NEXT:    [[CALL3:%.*]] = call ptr @external_sink_ret2_nrw(ptr nofree nonnull [[N0]], ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0]], ptr nofree nonnull writeonly align 4 dereferenceable(4) [[W0]]) #[[ATTR4:[0-9]+]]
+; CGSCC-NEXT:    [[CALL4:%.*]] = call ptr @external_sink_ret2_nrw(ptr nofree nonnull [[N0]], ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R1]], ptr nofree nonnull writeonly align 4 dereferenceable(4) [[W0]]) #[[ATTR4]]
+; CGSCC-NEXT:    [[CALL5:%.*]] = call ptr @internal_ret0_nw(ptr nofree nonnull [[N0]], ptr nofree nonnull align 4 dereferenceable(4) [[W0]]) #[[ATTR2]]
+; CGSCC-NEXT:    br label [[RETURN]]
 ; CGSCC:       return:
-; CGSCC-NEXT:    unreachable
+; CGSCC-NEXT:    [[RETVAL_0:%.*]] = phi ptr [ [[CALL5]], [[IF_END]] ], [ [[N0]], [[IF_THEN]] ]
+; CGSCC-NEXT:    ret ptr [[RETVAL_0]]
+;
+; CGSCC-DL: Function Attrs: nofree noreturn nosync nounwind memory(argmem: readwrite)
+; CGSCC-DL-LABEL: define {{[^@]+}}@internal_ret0_nw
+; CGSCC-DL-SAME: (ptr noalias nocapture nofree nonnull readnone [[N0:%.*]], ptr nofree nonnull [[W0:%.*]]) #[[ATTR1:[0-9]+]] {
+; CGSCC-DL-NEXT:  entry:
+; CGSCC-DL-NEXT:    [[R0:%.*]] = alloca i32, align 4
+; CGSCC-DL-NEXT:    [[R1:%.*]] = alloca i32, align 4
+; CGSCC-DL-NEXT:    br label [[IF_END:%.*]]
+; CGSCC-DL:       if.then:
+; CGSCC-DL-NEXT:    unreachable
+; CGSCC-DL:       if.end:
+; CGSCC-DL-NEXT:    store i32 3, ptr [[R0]], align 4
+; CGSCC-DL-NEXT:    store i32 5, ptr [[R1]], align 4
+; CGSCC-DL-NEXT:    store i32 1, ptr [[W0]], align 4
+; CGSCC-DL-NEXT:    [[CALL:%.*]] = call ptr @internal_ret1_rrw(ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0]], ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R1]], ptr nofree nonnull align 4 dereferenceable(4) [[W0]]) #[[ATTR4:[0-9]+]]
+; CGSCC-DL-NEXT:    [[CALL1:%.*]] = call ptr @external_ret2_nrw(ptr noalias nocapture nofree nonnull readnone [[N0]], ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0]], ptr nofree nonnull align 4 dereferenceable(4) [[W0]]) #[[ATTR4]]
+; CGSCC-DL-NEXT:    [[CALL2:%.*]] = call ptr @external_ret2_nrw(ptr noalias nocapture nofree nonnull readnone [[N0]], ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R1]], ptr nofree nonnull align 4 dereferenceable(4) [[W0]]) #[[ATTR4]]
+; CGSCC-DL-NEXT:    [[CALL3:%.*]] = call ptr @external_sink_ret2_nrw(ptr noalias nocapture nofree nonnull readnone [[N0]], ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0]], ptr nofree nonnull writeonly align 4 dereferenceable(4) [[W0]]) #[[ATTR5:[0-9]+]]
+; CGSCC-DL-NEXT:    [[CALL4:%.*]] = call ptr @external_sink_ret2_nrw(ptr noalias nocapture nofree nonnull readnone [[N0]], ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R1]], ptr nofree nonnull writeonly align 4 dereferenceable(4) [[W0]]) #[[ATTR5]]
+; CGSCC-DL-NEXT:    [[CALL5:%.*]] = call ptr @internal_ret0_nw(ptr noalias nocapture nofree nonnull readnone [[N0]], ptr nofree nonnull align 4 dereferenceable(4) [[W0]]) #[[ATTR3]]
+; CGSCC-DL-NEXT:    unreachable
+; CGSCC-DL:       return:
+; CGSCC-DL-NEXT:    unreachable
 ;
 entry:
   %r0 = alloca i32, align 4
@@ -131,7 +201,7 @@ return:                                           ; preds = %if.end, %if.then
 define internal ptr @internal_ret1_rrw(ptr %r0, ptr %r1, ptr %w0) {
 ; TUNIT: Function Attrs: nofree nosync nounwind memory(argmem: readwrite)
 ; TUNIT-LABEL: define {{[^@]+}}@internal_ret1_rrw
-; TUNIT-SAME: (ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0:%.*]], ptr nocapture nofree nonnull readonly align 4 [[R1:%.*]], ptr nocapture nofree nonnull writeonly [[W0:%.*]]) #[[ATTR0]] {
+; TUNIT-SAME: (ptr nofree noundef nonnull align 4 dereferenceable(4) [[R0:%.*]], ptr nofree align 4 [[R1:%.*]], ptr nofree [[W0:%.*]]) #[[ATTR0]] {
 ; TUNIT-NEXT:  entry:
 ; TUNIT-NEXT:    [[TMP0:%.*]] = load i32, ptr [[R0]], align 4
 ; TUNIT-NEXT:    [[TOBOOL:%.*]] = icmp ne i32 [[TMP0]], 0
@@ -139,20 +209,48 @@ define internal ptr @internal_ret1_rrw(ptr %r0, ptr %r1, ptr %w0) {
 ; TUNIT:       if.then:
 ; TUNIT-NEXT:    br label [[RETURN:%.*]]
 ; TUNIT:       if.end:
-; TUNIT-NEXT:    [[CALL:%.*]] = call ptr @internal_ret1_rw(ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0]], ptr nofree nonnull writeonly "no-capture-maybe-returned" [[W0]]) #[[ATTR5]]
+; TUNIT-NEXT:    [[CALL:%.*]] = call ptr @internal_ret1_rw(ptr nofree noundef nonnull align 4 dereferenceable(4) [[R0]], ptr nofree [[W0]]) #[[ATTR3]]
 ; TUNIT-NEXT:    [[TMP1:%.*]] = load i32, ptr [[R0]], align 4
 ; TUNIT-NEXT:    [[TMP2:%.*]] = load i32, ptr [[R1]], align 4
 ; TUNIT-NEXT:    [[ADD:%.*]] = add nsw i32 [[TMP1]], [[TMP2]]
 ; TUNIT-NEXT:    store i32 [[ADD]], ptr [[W0]], align 4
-; TUNIT-NEXT:    [[CALL1:%.*]] = call ptr @internal_ret1_rw(ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R1]], ptr nofree nonnull writeonly align 4 dereferenceable(4) "no-capture-maybe-returned" [[W0]]) #[[ATTR5]]
-; TUNIT-NEXT:    [[CALL2:%.*]] = call ptr @internal_ret0_nw(ptr nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[W0]]) #[[ATTR4]]
-; TUNIT-NEXT:    unreachable
+; TUNIT-NEXT:    [[CALL1:%.*]] = call ptr @internal_ret1_rw(ptr nofree noundef nonnull align 4 dereferenceable(4) [[R1]], ptr nofree nonnull align 4 dereferenceable(4) [[W0]]) #[[ATTR3]]
+; TUNIT-NEXT:    [[CALL2:%.*]] = call ptr @internal_ret0_nw(ptr nofree noundef nonnull align 4 dereferenceable(4) [[R0]], ptr nofree nonnull align 4 dereferenceable(4) [[W0]]) #[[ATTR3]]
+; TUNIT-NEXT:    [[CALL3:%.*]] = call ptr @internal_ret0_nw(ptr nofree nonnull align 4 dereferenceable(4) [[W0]], ptr nofree nonnull align 4 dereferenceable(4) [[W0]]) #[[ATTR3]]
+; TUNIT-NEXT:    [[CALL4:%.*]] = call ptr @external_ret2_nrw(ptr nofree noundef nonnull align 4 dereferenceable(4) [[R0]], ptr nofree nonnull align 4 dereferenceable(4) [[R1]], ptr nofree nonnull align 4 dereferenceable(4) [[W0]]) #[[ATTR3]]
+; TUNIT-NEXT:    [[CALL5:%.*]] = call ptr @external_ret2_nrw(ptr nofree nonnull align 4 dereferenceable(4) [[R1]], ptr nofree noundef nonnull align 4 dereferenceable(4) [[R0]], ptr nofree nonnull align 4 dereferenceable(4) [[W0]]) #[[ATTR3]]
+; TUNIT-NEXT:    [[CALL6:%.*]] = call ptr @external_sink_ret2_nrw(ptr nofree noundef nonnull align 4 dereferenceable(4) [[R0]], ptr nocapture nofree nonnull readonly align 4 dereferenceable(4) [[R1]], ptr nofree nonnull writeonly align 4 dereferenceable(4) "no-capture-maybe-returned" [[W0]]) #[[ATTR3]]
+; TUNIT-NEXT:    [[CALL7:%.*]] = call ptr @external_sink_ret2_nrw(ptr nofree nonnull align 4 dereferenceable(4) [[R1]], ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0]], ptr nofree nonnull writeonly align 4 dereferenceable(4) "no-capture-maybe-returned" [[W0]]) #[[ATTR3]]
+; TUNIT-NEXT:    [[CALL8:%.*]] = call ptr @internal_ret0_nw(ptr nofree nonnull align 4 dereferenceable(4) [[R1]], ptr nofree nonnull align 4 dereferenceable(4) [[W0]]) #[[ATTR3]]
+; TUNIT-NEXT:    br label [[RETURN]]
 ; TUNIT:       return:
+; TUNIT-NEXT:    [[RETVAL_0:%.*]] = phi ptr [ [[CALL8]], [[IF_END]] ], [ [[R1]], [[IF_THEN]] ]
 ; TUNIT-NEXT:    ret ptr undef
 ;
+; TUNIT-DL: Function Attrs: nofree nosync nounwind memory(argmem: readwrite)
+; TUNIT-DL-LABEL: define {{[^@]+}}@internal_ret1_rrw
+; TUNIT-DL-SAME: (ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0:%.*]], ptr nocapture nofree nonnull readonly align 4 [[R1:%.*]], ptr nocapture nofree nonnull writeonly [[W0:%.*]]) #[[ATTR0]] {
+; TUNIT-DL-NEXT:  entry:
+; TUNIT-DL-NEXT:    [[TMP0:%.*]] = load i32, ptr [[R0]], align 4
+; TUNIT-DL-NEXT:    [[TOBOOL:%.*]] = icmp ne i32 [[TMP0]], 0
+; TUNIT-DL-NEXT:    br i1 [[TOBOOL]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]
+; TUNIT-DL:       if.then:
+; TUNIT-DL-NEXT:    br label [[RETURN:%.*]]
+; TUNIT-DL:       if.end:
+; TUNIT-DL-NEXT:    [[CALL:%.*]] = call ptr @internal_ret1_rw(ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0]], ptr nofree nonnull writeonly "no-capture-maybe-returned" [[W0]]) #[[ATTR5]]
+; TUNIT-DL-NEXT:    [[TMP1:%.*]] = load i32, ptr [[R0]], align 4
+; TUNIT-DL-NEXT:    [[TMP2:%.*]] = load i32, ptr [[R1]], align 4
+; TUNIT-DL-NEXT:    [[ADD:%.*]] = add nsw i32 [[TMP1]], [[TMP2]]
+; TUNIT-DL-NEXT:    store i32 [[ADD]], ptr [[W0]], align 4
+; TUNIT-DL-NEXT:    [[CALL1:%.*]] = call ptr @internal_ret1_rw(ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R1]], ptr nofree nonnull writeonly align 4 dereferenceable(4) "no-capture-maybe-returned" [[W0]]) #[[ATTR5]]
+; TUNIT-DL-NEXT:    [[CALL2:%.*]] = call ptr @internal_ret0_nw(ptr nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[W0]]) #[[ATTR4]]
+; TUNIT-DL-NEXT:    unreachable
+; TUNIT-DL:       return:
+; TUNIT-DL-NEXT:    ret ptr undef
+;
 ; CGSCC: Function Attrs: nofree nosync nounwind memory(argmem: readwrite)
 ; CGSCC-LABEL: define {{[^@]+}}@internal_ret1_rrw
-; CGSCC-SAME: (ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0:%.*]], ptr nocapture nofree nonnull readonly align 4 [[R1:%.*]], ptr nofree nonnull [[W0:%.*]]) #[[ATTR0]] {
+; CGSCC-SAME: (ptr nofree noundef nonnull align 4 dereferenceable(4) [[R0:%.*]], ptr nofree align 4 [[R1:%.*]], ptr nofree [[W0:%.*]]) #[[ATTR0]] {
 ; CGSCC-NEXT:  entry:
 ; CGSCC-NEXT:    [[TMP0:%.*]] = load i32, ptr [[R0]], align 4
 ; CGSCC-NEXT:    [[TOBOOL:%.*]] = icmp ne i32 [[TMP0]], 0
@@ -160,17 +258,45 @@ define internal ptr @internal_ret1_rrw(ptr %r0, ptr %r1, ptr %w0) {
 ; CGSCC:       if.then:
 ; CGSCC-NEXT:    br label [[RETURN:%.*]]
 ; CGSCC:       if.end:
-; CGSCC-NEXT:    [[CALL:%.*]] = call ptr @internal_ret1_rw(ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0]], ptr nofree nonnull [[W0]]) #[[ATTR4]]
+; CGSCC-NEXT:    [[CALL:%.*]] = call ptr @internal_ret1_rw(ptr nofree noundef nonnull align 4 dereferenceable(4) [[R0]], ptr nofree [[W0]]) #[[ATTR2]]
 ; CGSCC-NEXT:    [[TMP1:%.*]] = load i32, ptr [[R0]], align 4
 ; CGSCC-NEXT:    [[TMP2:%.*]] = load i32, ptr [[R1]], align 4
 ; CGSCC-NEXT:    [[ADD:%.*]] = add nsw i32 [[TMP1]], [[TMP2]]
 ; CGSCC-NEXT:    store i32 [[ADD]], ptr [[W0]], align 4
-; CGSCC-NEXT:    [[CALL1:%.*]] = call ptr @internal_ret1_rw(ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R1]], ptr nofree nonnull align 4 dereferenceable(4) [[W0]]) #[[ATTR4]]
-; CGSCC-NEXT:    [[CALL2:%.*]] = call ptr @internal_ret0_nw(ptr noalias nocapture nofree noundef nonnull readnone align 4 dereferenceable(4) [[R0]], ptr nofree nonnull align 4 dereferenceable(4) [[W0]]) #[[ATTR3]]
-; CGSCC-NEXT:    unreachable
+; CGSCC-NEXT:    [[CALL1:%.*]] = call ptr @internal_ret1_rw(ptr nofree noundef nonnull align 4 dereferenceable(4) [[R1]], ptr nofree nonnull align 4 dereferenceable(4) [[W0]]) #[[ATTR2]]
+; CGSCC-NEXT:    [[CALL2:%.*]] = call ptr @internal_ret0_nw(ptr nofree noundef nonnull align 4 dereferenceable(4) [[R0]], ptr nofree nonnull align 4 dereferenceable(4) [[W0]]) #[[ATTR2]]
+; CGSCC-NEXT:    [[CALL3:%.*]] = call ptr @internal_ret0_nw(ptr nofree nonnull align 4 dereferenceable(4) [[W0]], ptr nofree nonnull align 4 dereferenceable(4) [[W0]]) #[[ATTR2]]
+; CGSCC-NEXT:    [[CALL4:%.*]] = call ptr @external_ret2_nrw(ptr nofree noundef nonnull align 4 dereferenceable(4) [[R0]], ptr nofree nonnull align 4 dereferenceable(4) [[R1]], ptr nofree nonnull align 4 dereferenceable(4) [[W0]]) #[[ATTR2]]
+; CGSCC-NEXT:    [[CALL5:%.*]] = call ptr @external_ret2_nrw(ptr nofree nonnull align 4 dereferenceable(4) [[R1]], ptr nofree noundef nonnull align 4 dereferenceable(4) [[R0]], ptr nofree nonnull align 4 dereferenceable(4) [[W0]]) #[[ATTR2]]
+; CGSCC-NEXT:    [[CALL6:%.*]] = call ptr @external_sink_ret2_nrw(ptr nofree noundef nonnull align 4 dereferenceable(4) [[R0]], ptr nocapture nofree nonnull readonly align 4 dereferenceable(4) [[R1]], ptr nofree nonnull writeonly align 4 dereferenceable(4) [[W0]]) #[[ATTR4]]
+; CGSCC-NEXT:    [[CALL7:%.*]] = call ptr @external_sink_ret2_nrw(ptr nofree nonnull align 4 dereferenceable(4) [[R1]], ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0]], ptr nofree nonnull writeonly align 4 dereferenceable(4) [[W0]]) #[[ATTR4]]
+; CGSCC-NEXT:    [[CALL8:%.*]] = call ptr @internal_ret0_nw(ptr nofree nonnull align 4 dereferenceable(4) [[R1]], ptr nofree nonnull align 4 dereferenceable(4) [[W0]]) #[[ATTR2]]
+; CGSCC-NEXT:    br label [[RETURN]]
 ; CGSCC:       return:
+; CGSCC-NEXT:    [[RETVAL_0:%.*]] = phi ptr [ [[CALL8]], [[IF_END]] ], [ [[R1]], [[IF_THEN]] ]
 ; CGSCC-NEXT:    ret ptr undef
 ;
+; CGSCC-DL: Function Attrs: nofree nosync nounwind memory(argmem: readwrite)
+; CGSCC-DL-LABEL: define {{[^@]+}}@internal_ret1_rrw
+; CGSCC-DL-SAME: (ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0:%.*]], ptr nocapture nofree nonnull readonly align 4 [[R1:%.*]], ptr nofree nonnull [[W0:%.*]]) #[[ATTR0]] {
+; CGSCC-DL-NEXT:  entry:
+; CGSCC-DL-NEXT:    [[TMP0:%.*]] = load i32, ptr [[R0]], align 4
+; CGSCC-DL-NEXT:    [[TOBOOL:%.*]] = icmp ne i32 [[TMP0]], 0
+; CGSCC-DL-NEXT:    br i1 [[TOBOOL]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]
+; CGSCC-DL:       if.then:
+; CGSCC-DL-NEXT:    br label [[RETURN:%.*]]
+; CGSCC-DL:       if.end:
+; CGSCC-DL-NEXT:    [[CALL:%.*]] = call ptr @internal_ret1_rw(ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0]], ptr nofree nonnull [[W0]]) #[[ATTR4]]
+; CGSCC-DL-NEXT:    [[TMP1:%.*]] = load i32, ptr [[R0]], align 4
+; CGSCC-DL-NEXT:    [[TMP2:%.*]] = load i32, ptr [[R1]], align 4
+; CGSCC-DL-NEXT:    [[ADD:%.*]] = add nsw i32 [[TMP1]], [[TMP2]]
+; CGSCC-DL-NEXT:    store i32 [[ADD]], ptr [[W0]], align 4
+; CGSCC-DL-NEXT:    [[CALL1:%.*]] = call ptr @internal_ret1_rw(ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R1]], ptr nofree nonnull align 4 dereferenceable(4) [[W0]]) #[[ATTR4]]
+; CGSCC-DL-NEXT:    [[CALL2:%.*]] = call ptr @internal_ret0_nw(ptr noalias nocapture nofree noundef nonnull readnone align 4 dereferenceable(4) [[R0]], ptr nofree nonnull align 4 dereferenceable(4) [[W0]]) #[[ATTR3]]
+; CGSCC-DL-NEXT:    unreachable
+; CGSCC-DL:       return:
+; CGSCC-DL-NEXT:    ret ptr undef
+;
 entry:
   %0 = load i32, ptr %r0, align 4
   %tobool = icmp ne i32 %0, 0
@@ -203,18 +329,33 @@ return:                                           ; preds = %if.end, %if.then
 define ptr @external_sink_ret2_nrw(ptr %n0, ptr %r0, ptr %w0) {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite)
 ; CHECK-LABEL: define {{[^@]+}}@external_sink_ret2_nrw
-; CHECK-SAME: (ptr nocapture nofree nonnull readnone [[N0:%.*]], ptr nocapture nofree nonnull readonly [[R0:%.*]], ptr nofree nonnull returned writeonly "no-capture-maybe-returned" [[W0:%.*]]) #[[ATTR2:[0-9]+]] {
+; CHECK-SAME: (ptr nofree [[N0:%.*]], ptr nocapture nofree readonly [[R0:%.*]], ptr nofree returned writeonly "no-capture-maybe-returned" [[W0:%.*]]) #[[ATTR1:[0-9]+]] {
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    br label [[IF_END:%.*]]
+; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp ne ptr [[N0]], null
+; CHECK-NEXT:    br i1 [[TOBOOL]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]
 ; CHECK:       if.then:
-; CHECK-NEXT:    unreachable
+; CHECK-NEXT:    br label [[RETURN:%.*]]
 ; CHECK:       if.end:
 ; CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr [[R0]], align 4
 ; CHECK-NEXT:    store i32 [[TMP0]], ptr [[W0]], align 4
-; CHECK-NEXT:    br label [[RETURN:%.*]]
+; CHECK-NEXT:    br label [[RETURN]]
 ; CHECK:       return:
 ; CHECK-NEXT:    ret ptr [[W0]]
 ;
+; CHECK-DL: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite)
+; CHECK-DL-LABEL: define {{[^@]+}}@external_sink_ret2_nrw
+; CHECK-DL-SAME: (ptr nocapture nofree nonnull readnone [[N0:%.*]], ptr nocapture nofree nonnull readonly [[R0:%.*]], ptr nofree nonnull returned writeonly "no-capture-maybe-returned" [[W0:%.*]]) #[[ATTR2:[0-9]+]] {
+; CHECK-DL-NEXT:  entry:
+; CHECK-DL-NEXT:    br label [[IF_END:%.*]]
+; CHECK-DL:       if.then:
+; CHECK-DL-NEXT:    unreachable
+; CHECK-DL:       if.end:
+; CHECK-DL-NEXT:    [[TMP0:%.*]] = load i32, ptr [[R0]], align 4
+; CHECK-DL-NEXT:    store i32 [[TMP0]], ptr [[W0]], align 4
+; CHECK-DL-NEXT:    br label [[RETURN:%.*]]
+; CHECK-DL:       return:
+; CHECK-DL-NEXT:    ret ptr [[W0]]
+;
 entry:
   %tobool = icmp ne ptr %n0, null
   br i1 %tobool, label %if.end, label %if.then
@@ -234,7 +375,7 @@ return:                                           ; preds = %if.end, %if.then
 define internal ptr @internal_ret1_rw(ptr %r0, ptr %w0) {
 ; TUNIT: Function Attrs: nofree nosync nounwind memory(argmem: readwrite)
 ; TUNIT-LABEL: define {{[^@]+}}@internal_ret1_rw
-; TUNIT-SAME: (ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0:%.*]], ptr nofree nonnull returned writeonly "no-capture-maybe-returned" [[W0:%.*]]) #[[ATTR0]] {
+; TUNIT-SAME: (ptr nofree noundef nonnull align 4 dereferenceable(4) [[R0:%.*]], ptr nofree [[W0:%.*]]) #[[ATTR0]] {
 ; TUNIT-NEXT:  entry:
 ; TUNIT-NEXT:    [[TMP0:%.*]] = load i32, ptr [[R0]], align 4
 ; TUNIT-NEXT:    [[TOBOOL:%.*]] = icmp ne i32 [[TMP0]], 0
@@ -242,17 +383,39 @@ define internal ptr @internal_ret1_rw(ptr %r0, ptr %w0) {
 ; TUNIT:       if.then:
 ; TUNIT-NEXT:    br label [[RETURN:%.*]]
 ; TUNIT:       if.end:
-; TUNIT-NEXT:    [[CALL:%.*]] = call ptr @internal_ret1_rrw(ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0]], ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0]], ptr nocapture nofree nonnull writeonly [[W0]]) #[[ATTR5]]
+; TUNIT-NEXT:    [[CALL:%.*]] = call ptr @internal_ret1_rrw(ptr nofree noundef nonnull align 4 dereferenceable(4) [[R0]], ptr nofree noundef nonnull align 4 dereferenceable(4) [[R0]], ptr nofree [[W0]]) #[[ATTR3]]
 ; TUNIT-NEXT:    [[TMP1:%.*]] = load i32, ptr [[R0]], align 4
 ; TUNIT-NEXT:    store i32 [[TMP1]], ptr [[W0]], align 4
-; TUNIT-NEXT:    [[CALL1:%.*]] = call ptr @internal_ret0_nw(ptr nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[W0]]) #[[ATTR4]]
-; TUNIT-NEXT:    unreachable
+; TUNIT-NEXT:    [[CALL1:%.*]] = call ptr @internal_ret0_nw(ptr nofree noundef nonnull align 4 dereferenceable(4) [[R0]], ptr nofree nonnull align 4 dereferenceable(4) [[W0]]) #[[ATTR3]]
+; TUNIT-NEXT:    [[CALL2:%.*]] = call ptr @internal_ret0_nw(ptr nofree nonnull align 4 dereferenceable(4) [[W0]], ptr nofree nonnull align 4 dereferenceable(4) [[W0]]) #[[ATTR3]]
+; TUNIT-NEXT:    [[CALL3:%.*]] = call ptr @external_sink_ret2_nrw(ptr nofree noundef nonnull align 4 dereferenceable(4) [[R0]], ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0]], ptr nofree nonnull writeonly align 4 dereferenceable(4) "no-capture-maybe-returned" [[W0]]) #[[ATTR3]]
+; TUNIT-NEXT:    [[CALL4:%.*]] = call ptr @external_ret2_nrw(ptr nofree noundef nonnull align 4 dereferenceable(4) [[R0]], ptr nofree noundef nonnull align 4 dereferenceable(4) [[R0]], ptr nofree nonnull align 4 dereferenceable(4) [[W0]]) #[[ATTR3]]
+; TUNIT-NEXT:    br label [[RETURN]]
 ; TUNIT:       return:
-; TUNIT-NEXT:    ret ptr [[W0]]
+; TUNIT-NEXT:    [[RETVAL_0:%.*]] = phi ptr [ [[CALL4]], [[IF_END]] ], [ [[W0]], [[IF_THEN]] ]
+; TUNIT-NEXT:    ret ptr [[RETVAL_0]]
+;
+; TUNIT-DL: Function Attrs: nofree nosync nounwind memory(argmem: readwrite)
+; TUNIT-DL-LABEL: define {{[^@]+}}@internal_ret1_rw
+; TUNIT-DL-SAME: (ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0:%.*]], ptr nofree nonnull returned writeonly "no-capture-maybe-returned" [[W0:%.*]]) #[[ATTR0]] {
+; TUNIT-DL-NEXT:  entry:
+; TUNIT-DL-NEXT:    [[TMP0:%.*]] = load i32, ptr [[R0]], align 4
+; TUNIT-DL-NEXT:    [[TOBOOL:%.*]] = icmp ne i32 [[TMP0]], 0
+; TUNIT-DL-NEXT:    br i1 [[TOBOOL]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]
+; TUNIT-DL:       if.then:
+; TUNIT-DL-NEXT:    br label [[RETURN:%.*]]
+; TUNIT-DL:       if.end:
+; TUNIT-DL-NEXT:    [[CALL:%.*]] = call ptr @internal_ret1_rrw(ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0]], ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0]], ptr nocapture nofree nonnull writeonly [[W0]]) #[[ATTR5]]
+; TUNIT-DL-NEXT:    [[TMP1:%.*]] = load i32, ptr [[R0]], align 4
+; TUNIT-DL-NEXT:    store i32 [[TMP1]], ptr [[W0]], align 4
+; TUNIT-DL-NEXT:    [[CALL1:%.*]] = call ptr @internal_ret0_nw(ptr nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[W0]]) #[[ATTR4]]
+; TUNIT-DL-NEXT:    unreachable
+; TUNIT-DL:       return:
+; TUNIT-DL-NEXT:    ret ptr [[W0]]
 ;
 ; CGSCC: Function Attrs: nofree nosync nounwind memory(argmem: readwrite)
 ; CGSCC-LABEL: define {{[^@]+}}@internal_ret1_rw
-; CGSCC-SAME: (ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0:%.*]], ptr nofree nonnull returned [[W0:%.*]]) #[[ATTR0]] {
+; CGSCC-SAME: (ptr nofree noundef nonnull align 4 dereferenceable(4) [[R0:%.*]], ptr nofree [[W0:%.*]]) #[[ATTR0]] {
 ; CGSCC-NEXT:  entry:
 ; CGSCC-NEXT:    [[TMP0:%.*]] = load i32, ptr [[R0]], align 4
 ; CGSCC-NEXT:    [[TOBOOL:%.*]] = icmp ne i32 [[TMP0]], 0
@@ -260,13 +423,35 @@ define internal ptr @internal_ret1_rw(ptr %r0, ptr %w0) {
 ; CGSCC:       if.then:
 ; CGSCC-NEXT:    br label [[RETURN:%.*]]
 ; CGSCC:       if.end:
-; CGSCC-NEXT:    [[CALL:%.*]] = call ptr @internal_ret1_rrw(ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0]], ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0]], ptr nofree nonnull [[W0]]) #[[ATTR4]]
+; CGSCC-NEXT:    [[CALL:%.*]] = call ptr @internal_ret1_rrw(ptr nofree noundef nonnull align 4 dereferenceable(4) [[R0]], ptr nofree noundef nonnull align 4 dereferenceable(4) [[R0]], ptr nofree [[W0]]) #[[ATTR2]]
 ; CGSCC-NEXT:    [[TMP1:%.*]] = load i32, ptr [[R0]], align 4
 ; CGSCC-NEXT:    store i32 [[TMP1]], ptr [[W0]], align 4
-; CGSCC-NEXT:    [[CALL1:%.*]] = call ptr @internal_ret0_nw(ptr noalias nocapture nofree noundef nonnull readnone align 4 dereferenceable(4) [[R0]], ptr nofree nonnull align 4 dereferenceable(4) [[W0]]) #[[ATTR3]]
-; CGSCC-NEXT:    unreachable
+; CGSCC-NEXT:    [[CALL1:%.*]] = call ptr @internal_ret0_nw(ptr nofree noundef nonnull align 4 dereferenceable(4) [[R0]], ptr nofree nonnull align 4 dereferenceable(4) [[W0]]) #[[ATTR2]]
+; CGSCC-NEXT:    [[CALL2:%.*]] = call ptr @internal_ret0_nw(ptr nofree nonnull align 4 dereferenceable(4) [[W0]], ptr nofree nonnull align 4 dereferenceable(4) [[W0]]) #[[ATTR2]]
+; CGSCC-NEXT:    [[CALL3:%.*]] = call ptr @external_sink_ret2_nrw(ptr nofree noundef nonnull align 4 dereferenceable(4) [[R0]], ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0]], ptr nofree nonnull writeonly align 4 dereferenceable(4) [[W0]]) #[[ATTR4]]
+; CGSCC-NEXT:    [[CALL4:%.*]] = call ptr @external_ret2_nrw(ptr nofree noundef nonnull align 4 dereferenceable(4) [[R0]], ptr nofree noundef nonnull align 4 dereferenceable(4) [[R0]], ptr nofree nonnull align 4 dereferenceable(4) [[W0]]) #[[ATTR2]]
+; CGSCC-NEXT:    br label [[RETURN]]
 ; CGSCC:       return:
-; CGSCC-NEXT:    ret ptr [[W0]]
+; CGSCC-NEXT:    [[RETVAL_0:%.*]] = phi ptr [ [[CALL4]], [[IF_END]] ], [ [[W0]], [[IF_THEN]] ]
+; CGSCC-NEXT:    ret ptr [[RETVAL_0]]
+;
+; CGSCC-DL: Function Attrs: nofree nosync nounwind memory(argmem: readwrite)
+; CGSCC-DL-LABEL: define {{[^@]+}}@internal_ret1_rw
+; CGSCC-DL-SAME: (ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0:%.*]], ptr nofree nonnull returned [[W0:%.*]]) #[[ATTR0]] {
+; CGSCC-DL-NEXT:  entry:
+; CGSCC-DL-NEXT:    [[TMP0:%.*]] = load i32, ptr [[R0]], align 4
+; CGSCC-DL-NEXT:    [[TOBOOL:%.*]] = icmp ne i32 [[TMP0]], 0
+; CGSCC-DL-NEXT:    br i1 [[TOBOOL]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]
+; CGSCC-DL:       if.then:
+; CGSCC-DL-NEXT:    br label [[RETURN:%.*]]
+; CGSCC-DL:       if.end:
+; CGSCC-DL-NEXT:    [[CALL:%.*]] = call ptr @internal_ret1_rrw(ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0]], ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[R0]], ptr nofree nonnull [[W0]]) #[[ATTR4]]
+; CGSCC-DL-NEXT:    [[TMP1:%.*]] = load i32, ptr [[R0]], align 4
+; CGSCC-DL-NEXT:    store i32 [[TMP1]], ptr [[W0]], align 4
+; CGSCC-DL-NEXT:    [[CALL1:%.*]] = call ptr @internal_ret0_nw(ptr noalias nocapture nofree noundef nonnull readnone align 4 dereferenceable(4) [[R0]], ptr nofree nonnull align 4 dereferenceable(4) [[W0]]) #[[ATTR3]]
+; CGSCC-DL-NEXT:    unreachable
+; CGSCC-DL:       return:
+; CGSCC-DL-NEXT:    ret ptr [[W0]]
 ;
 entry:
   %0 = load i32, ptr %r0, align 4
@@ -294,20 +479,36 @@ return:                                           ; preds = %if.end, %if.then
 define ptr @external_source_ret2_nrw(ptr %n0, ptr %r0, ptr %w0) {
 ; TUNIT: Function Attrs: nofree norecurse nosync nounwind memory(argmem: readwrite)
 ; TUNIT-LABEL: define {{[^@]+}}@external_source_ret2_nrw
-; TUNIT-SAME: (ptr nocapture nofree nonnull readnone [[N0:%.*]], ptr nocapture nofree nonnull readonly [[R0:%.*]], ptr nofree nonnull returned writeonly "no-capture-maybe-returned" [[W0:%.*]]) #[[ATTR3:[0-9]+]] {
+; TUNIT-SAME: (ptr nofree [[N0:%.*]], ptr nofree [[R0:%.*]], ptr nofree returned [[W0:%.*]]) #[[ATTR2:[0-9]+]] {
 ; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    [[CALL:%.*]] = call ptr @external_sink_ret2_nrw(ptr noalias nocapture nofree nonnull readnone undef, ptr nocapture nofree nonnull readonly [[R0]], ptr nofree nonnull writeonly "no-capture-maybe-returned" [[W0]]) #[[ATTR6:[0-9]+]]
-; TUNIT-NEXT:    [[CALL1:%.*]] = call ptr @external_ret2_nrw(ptr noalias nocapture nofree nonnull readnone undef, ptr nocapture nofree nonnull readonly [[R0]], ptr nofree nonnull writeonly "no-capture-maybe-returned" [[W0]]) #[[ATTR5]]
+; TUNIT-NEXT:    [[CALL:%.*]] = call ptr @external_sink_ret2_nrw(ptr nofree [[N0]], ptr nocapture nofree readonly [[R0]], ptr nofree writeonly "no-capture-maybe-returned" [[W0]]) #[[ATTR4:[0-9]+]]
+; TUNIT-NEXT:    [[CALL1:%.*]] = call ptr @external_ret2_nrw(ptr nofree [[N0]], ptr nofree [[R0]], ptr nofree [[W0]]) #[[ATTR3]]
 ; TUNIT-NEXT:    ret ptr [[W0]]
 ;
+; TUNIT-DL: Function Attrs: nofree norecurse nosync nounwind memory(argmem: readwrite)
+; TUNIT-DL-LABEL: define {{[^@]+}}@external_source_ret2_nrw
+; TUNIT-DL-SAME: (ptr nocapture nofree nonnull readnone [[N0:%.*]], ptr nocapture nofree nonnull readonly [[R0:%.*]], ptr nofree nonnull returned writeonly "no-capture-maybe-returned" [[W0:%.*]]) #[[ATTR3:[0-9]+]] {
+; TUNIT-DL-NEXT:  entry:
+; TUNIT-DL-NEXT:    [[CALL:%.*]] = call ptr @external_sink_ret2_nrw(ptr noalias nocapture nofree nonnull readnone undef, ptr nocapture nofree nonnull readonly [[R0]], ptr nofree nonnull writeonly "no-capture-maybe-returned" [[W0]]) #[[ATTR6:[0-9]+]]
+; TUNIT-DL-NEXT:    [[CALL1:%.*]] = call ptr @external_ret2_nrw(ptr noalias nocapture nofree nonnull readnone undef, ptr nocapture nofree nonnull readonly [[R0]], ptr nofree nonnull writeonly "no-capture-maybe-returned" [[W0]]) #[[ATTR5]]
+; TUNIT-DL-NEXT:    ret ptr [[W0]]
+;
 ; CGSCC: Function Attrs: nofree nosync nounwind memory(argmem: readwrite)
 ; CGSCC-LABEL: define {{[^@]+}}@external_source_ret2_nrw
-; CGSCC-SAME: (ptr nocapture nofree nonnull readnone [[N0:%.*]], ptr nocapture nofree nonnull readonly align 4 [[R0:%.*]], ptr nofree nonnull align 4 [[W0:%.*]]) #[[ATTR0]] {
+; CGSCC-SAME: (ptr nofree [[N0:%.*]], ptr nofree [[R0:%.*]], ptr nofree [[W0:%.*]]) #[[ATTR0]] {
 ; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    [[CALL:%.*]] = call ptr @external_sink_ret2_nrw(ptr noalias nocapture nofree nonnull readnone [[N0]], ptr nocapture nofree nonnull readonly align 4 [[R0]], ptr nofree nonnull writeonly align 4 [[W0]]) #[[ATTR6:[0-9]+]]
-; CGSCC-NEXT:    [[CALL1:%.*]] = call nonnull ptr @external_ret2_nrw(ptr noalias nocapture nofree nonnull readnone [[N0]], ptr nocapture nofree nonnull readonly align 4 [[R0]], ptr nofree nonnull align 4 [[W0]]) #[[ATTR7:[0-9]+]]
+; CGSCC-NEXT:    [[CALL:%.*]] = call ptr @external_sink_ret2_nrw(ptr nofree [[N0]], ptr nocapture nofree readonly [[R0]], ptr nofree writeonly [[W0]]) #[[ATTR5:[0-9]+]]
+; CGSCC-NEXT:    [[CALL1:%.*]] = call ptr @external_ret2_nrw(ptr nofree [[N0]], ptr nofree [[R0]], ptr nofree [[W0]]) #[[ATTR3]]
 ; CGSCC-NEXT:    ret ptr [[CALL1]]
 ;
+; CGSCC-DL: Function Attrs: nofree nosync nounwind memory(argmem: readwrite)
+; CGSCC-DL-LABEL: define {{[^@]+}}@external_source_ret2_nrw
+; CGSCC-DL-SAME: (ptr nocapture nofree nonnull readnone [[N0:%.*]], ptr nocapture nofree nonnull readonly align 4 [[R0:%.*]], ptr nofree nonnull align 4 [[W0:%.*]]) #[[ATTR0]] {
+; CGSCC-DL-NEXT:  entry:
+; CGSCC-DL-NEXT:    [[CALL:%.*]] = call ptr @external_sink_ret2_nrw(ptr noalias nocapture nofree nonnull readnone [[N0]], ptr nocapture nofree nonnull readonly align 4 [[R0]], ptr nofree nonnull writeonly align 4 [[W0]]) #[[ATTR6:[0-9]+]]
+; CGSCC-DL-NEXT:    [[CALL1:%.*]] = call nonnull ptr @external_ret2_nrw(ptr noalias nocapture nofree nonnull readnone [[N0]], ptr nocapture nofree nonnull readonly align 4 [[R0]], ptr nofree nonnull align 4 [[W0]]) #[[ATTR7:[0-9]+]]
+; CGSCC-DL-NEXT:    ret ptr [[CALL1]]
+;
 entry:
   %call = call ptr @external_sink_ret2_nrw(ptr %n0, ptr %r0, ptr %w0)
   %call1 = call ptr @external_ret2_nrw(ptr %n0, ptr %r0, ptr %w0)
@@ -318,19 +519,32 @@ entry:
 ; for a subset relation.
 ;.
 ; TUNIT: attributes #[[ATTR0]] = { nofree nosync nounwind memory(argmem: readwrite) }
-; TUNIT: attributes #[[ATTR1]] = { nofree noreturn nosync nounwind memory(argmem: readwrite) }
-; TUNIT: attributes #[[ATTR2]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) }
-; TUNIT: attributes #[[ATTR3]] = { nofree norecurse nosync nounwind memory(argmem: readwrite) }
-; TUNIT: attributes #[[ATTR4]] = { nofree noreturn nosync nounwind }
-; TUNIT: attributes #[[ATTR5]] = { nofree nosync nounwind }
-; TUNIT: attributes #[[ATTR6]] = { nofree nosync nounwind willreturn }
+; TUNIT: attributes #[[ATTR1]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) }
+; TUNIT: attributes #[[ATTR2]] = { nofree norecurse nosync nounwind memory(argmem: readwrite) }
+; TUNIT: attributes #[[ATTR3]] = { nofree nosync nounwind }
+; TUNIT: attributes #[[ATTR4]] = { nofree nosync nounwind willreturn }
+;.
+; TUNIT-DL: attributes #[[ATTR0]] = { nofree nosync nounwind memory(argmem: readwrite) }
+; TUNIT-DL: attributes #[[ATTR1]] = { nofree noreturn nosync nounwind memory(argmem: readwrite) }
+; TUNIT-DL: attributes #[[ATTR2]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) }
+; TUNIT-DL: attributes #[[ATTR3]] = { nofree norecurse nosync nounwind memory(argmem: readwrite) }
+; TUNIT-DL: attributes #[[ATTR4]] = { nofree noreturn nosync nounwind }
+; TUNIT-DL: attributes #[[ATTR5]] = { nofree nosync nounwind }
+; TUNIT-DL: attributes #[[ATTR6]] = { nofree nosync nounwind willreturn }
 ;.
 ; CGSCC: attributes #[[ATTR0]] = { nofree nosync nounwind memory(argmem: readwrite) }
-; CGSCC: attributes #[[ATTR1]] = { nofree noreturn nosync nounwind memory(argmem: readwrite) }
-; CGSCC: attributes #[[ATTR2]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) }
-; CGSCC: attributes #[[ATTR3]] = { nofree noreturn nosync nounwind }
-; CGSCC: attributes #[[ATTR4]] = { nofree nosync nounwind }
-; CGSCC: attributes #[[ATTR5]] = { nofree nounwind memory(readwrite) }
-; CGSCC: attributes #[[ATTR6]] = { nofree nounwind willreturn }
-; CGSCC: attributes #[[ATTR7]] = { nofree nounwind }
+; CGSCC: attributes #[[ATTR1]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) }
+; CGSCC: attributes #[[ATTR2]] = { nofree nosync nounwind }
+; CGSCC: attributes #[[ATTR3]] = { nofree nounwind }
+; CGSCC: attributes #[[ATTR4]] = { nofree nounwind memory(readwrite) }
+; CGSCC: attributes #[[ATTR5]] = { nofree nounwind willreturn }
+;.
+; CGSCC-DL: attributes #[[ATTR0]] = { nofree nosync nounwind memory(argmem: readwrite) }
+; CGSCC-DL: attributes #[[ATTR1]] = { nofree noreturn nosync nounwind memory(argmem: readwrite) }
+; CGSCC-DL: attributes #[[ATTR2]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) }
+; CGSCC-DL: attributes #[[ATTR3]] = { nofree noreturn nosync nounwind }
+; CGSCC-DL: attributes #[[ATTR4]] = { nofree nosync nounwind }
+; CGSCC-DL: attributes #[[ATTR5]] = { nofree nounwind memory(readwrite) }
+; CGSCC-DL: attributes #[[ATTR6]] = { nofree nounwind willreturn }
+; CGSCC-DL: attributes #[[ATTR7]] = { nofree nounwind }
 ;.
diff --git a/llvm/test/Transforms/Attributor/returned-dl-sentinel.ll b/llvm/test/Transforms/Attributor/returned-dl-sentinel.ll
index 70e203f83542b..32e0aa180913f 100755
--- a/llvm/test/Transforms/Attributor/returned-dl-sentinel.ll
+++ b/llvm/test/Transforms/Attributor/returned-dl-sentinel.ll
@@ -1,336 +1,26 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
 ; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal  -attributor-annotate-decl-cs  -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal  -attributor-annotate-decl-cs  -data-layout=z0:1-z2:neg1-z3:neg1-z5:neg1 -S < %s | FileCheck %s --check-prefixes=CHECK-DL,TUNIT-DL
 ; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal  -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal  -attributor-annotate-decl-cs  -data-layout=z0:1-z2:neg1-z3:neg1-z5:neg1 -S < %s | FileCheck %s --check-prefixes=CHECK-DL,CGSCC-DL
 ;
 ; Test cases specifically designed for the "returned" argument attribute.
 ; We use FIXME's to indicate problems and missing attributes.
 ;
 
-; TEST SCC test returning an integer value argument
-;
-; int scc_r1(int a, int b, int r);
-; int scc_r2(int a, int b, int r);
-;
-; __attribute__((noinline)) int sink_r0(int r) {
-;   return r;
-; }
-;
-; __attribute__((noinline)) int scc_r1(int a, int r, int b) {
-;   return scc_r2(r, a, sink_r0(r));
-; }
-;
-; __attribute__((noinline)) int scc_r2(int a, int b, int r) {
-;   if (a > b)
-;     return scc_r2(b, a, sink_r0(r));
-;   if (a < b)
-;     return scc_r1(sink_r0(b), scc_r2(scc_r1(a, b, r), scc_r1(a, scc_r2(r, r, r), r), scc_r2(a, b, r)), scc_r1(a, b, r));
-;   return a == b ? r : scc_r2(a, b, r);
-; }
-; __attribute__((noinline)) int scc_rX(int a, int b, int r) {
-;   if (a > b)
-;     return scc_r2(b, a, sink_r0(r));
-;   if (a < b)                                                                         // V Diff to scc_r2
-;     return scc_r1(sink_r0(b), scc_r2(scc_r1(a, b, r), scc_r1(a, scc_r2(r, r, r), r), scc_r1(a, b, r)), scc_r1(a, b, r));
-;   return a == b ? r : scc_r2(a, b, r);
-; }
-target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-z0:1-z2:neg1-z3:neg1-z5:neg1-S128"
-
-;.
-; CHECK: @G = external global i8
-; CHECK: @_ZTI1X = external dso_local constant { ptr, ptr }, align 8
-; CHECK: @_ZTI1Y = external dso_local constant { ptr, ptr, ptr }, align 8
-;.
-define i32 @sink_r0(i32 %r) #0 {
-; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
-; CHECK-LABEL: define {{[^@]+}}@sink_r0
-; CHECK-SAME: (i32 returned [[R:%.*]]) #[[ATTR0:[0-9]+]] {
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    ret i32 [[R]]
-;
-entry:
-  ret i32 %r
-}
-
-define i32 @scc_r1(i32 %a, i32 %r, i32 %b) #0 {
-; TUNIT: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
-; TUNIT-LABEL: define {{[^@]+}}@scc_r1
-; TUNIT-SAME: (i32 [[A:%.*]], i32 returned [[R:%.*]], i32 [[B:%.*]]) #[[ATTR1:[0-9]+]] {
-; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    [[CALL1:%.*]] = call i32 @scc_r2(i32 [[R]], i32 [[A]], i32 [[R]]) #[[ATTR8:[0-9]+]]
-; TUNIT-NEXT:    ret i32 [[R]]
-;
-; CGSCC: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
-; CGSCC-LABEL: define {{[^@]+}}@scc_r1
-; CGSCC-SAME: (i32 [[A:%.*]], i32 returned [[R:%.*]], i32 [[B:%.*]]) #[[ATTR1:[0-9]+]] {
-; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    [[CALL1:%.*]] = call i32 @scc_r2(i32 [[R]], i32 [[A]], i32 [[R]]) #[[ATTR7:[0-9]+]]
-; CGSCC-NEXT:    ret i32 [[R]]
-;
-entry:
-  %call = call i32 @sink_r0(i32 %r)
-  %call1 = call i32 @scc_r2(i32 %r, i32 %a, i32 %call)
-  ret i32 %call1
-}
-
-define i32 @scc_r2(i32 %a, i32 %b, i32 %r) #0 {
-; TUNIT: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
-; TUNIT-LABEL: define {{[^@]+}}@scc_r2
-; TUNIT-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 returned [[R:%.*]]) #[[ATTR1]] {
-; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[A]], [[B]]
-; TUNIT-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
-; TUNIT:       if.then:
-; TUNIT-NEXT:    [[CALL1:%.*]] = call i32 @scc_r2(i32 [[B]], i32 [[A]], i32 [[R]]) #[[ATTR8]]
-; TUNIT-NEXT:    br label [[RETURN:%.*]]
-; TUNIT:       if.end:
-; TUNIT-NEXT:    [[CMP2:%.*]] = icmp slt i32 [[A]], [[B]]
-; TUNIT-NEXT:    br i1 [[CMP2]], label [[IF_THEN3:%.*]], label [[IF_END12:%.*]]
-; TUNIT:       if.then3:
-; TUNIT-NEXT:    [[CALL5:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[B]], i32 undef) #[[ATTR8]]
-; TUNIT-NEXT:    [[CALL6:%.*]] = call i32 @scc_r2(i32 [[R]], i32 [[R]], i32 [[R]]) #[[ATTR8]]
-; TUNIT-NEXT:    [[CALL7:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[R]], i32 undef) #[[ATTR8]]
-; TUNIT-NEXT:    [[CALL8:%.*]] = call i32 @scc_r2(i32 [[A]], i32 [[B]], i32 [[R]]) #[[ATTR8]]
-; TUNIT-NEXT:    [[CALL9:%.*]] = call i32 @scc_r2(i32 [[B]], i32 [[R]], i32 [[R]]) #[[ATTR8]]
-; TUNIT-NEXT:    [[CALL11:%.*]] = call i32 @scc_r1(i32 [[B]], i32 [[R]], i32 undef) #[[ATTR8]]
-; TUNIT-NEXT:    br label [[RETURN]]
-; TUNIT:       if.end12:
-; TUNIT-NEXT:    [[CMP13:%.*]] = icmp eq i32 [[A]], [[B]]
-; TUNIT-NEXT:    br i1 [[CMP13]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-; TUNIT:       cond.true:
-; TUNIT-NEXT:    br label [[COND_END:%.*]]
-; TUNIT:       cond.false:
-; TUNIT-NEXT:    [[CALL14:%.*]] = call i32 @scc_r2(i32 [[A]], i32 [[B]], i32 [[R]]) #[[ATTR8]]
-; TUNIT-NEXT:    br label [[COND_END]]
-; TUNIT:       cond.end:
-; TUNIT-NEXT:    [[COND:%.*]] = phi i32 [ [[R]], [[COND_TRUE]] ], [ [[R]], [[COND_FALSE]] ]
-; TUNIT-NEXT:    br label [[RETURN]]
-; TUNIT:       return:
-; TUNIT-NEXT:    [[RETVAL_0:%.*]] = phi i32 [ [[R]], [[IF_THEN]] ], [ [[R]], [[IF_THEN3]] ], [ [[R]], [[COND_END]] ]
-; TUNIT-NEXT:    ret i32 [[R]]
-;
-; CGSCC: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
-; CGSCC-LABEL: define {{[^@]+}}@scc_r2
-; CGSCC-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 returned [[R:%.*]]) #[[ATTR1]] {
-; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[A]], [[B]]
-; CGSCC-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
-; CGSCC:       if.then:
-; CGSCC-NEXT:    [[CALL1:%.*]] = call i32 @scc_r2(i32 [[B]], i32 [[A]], i32 [[R]]) #[[ATTR7]]
-; CGSCC-NEXT:    br label [[RETURN:%.*]]
-; CGSCC:       if.end:
-; CGSCC-NEXT:    [[CMP2:%.*]] = icmp slt i32 [[A]], [[B]]
-; CGSCC-NEXT:    br i1 [[CMP2]], label [[IF_THEN3:%.*]], label [[IF_END12:%.*]]
-; CGSCC:       if.then3:
-; CGSCC-NEXT:    [[CALL5:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[B]], i32 undef) #[[ATTR7]]
-; CGSCC-NEXT:    [[CALL6:%.*]] = call i32 @scc_r2(i32 [[R]], i32 [[R]], i32 [[R]]) #[[ATTR7]]
-; CGSCC-NEXT:    [[CALL7:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[R]], i32 undef) #[[ATTR7]]
-; CGSCC-NEXT:    [[CALL8:%.*]] = call i32 @scc_r2(i32 [[A]], i32 [[B]], i32 [[R]]) #[[ATTR7]]
-; CGSCC-NEXT:    [[CALL9:%.*]] = call i32 @scc_r2(i32 [[B]], i32 [[R]], i32 [[R]]) #[[ATTR7]]
-; CGSCC-NEXT:    [[CALL11:%.*]] = call i32 @scc_r1(i32 [[B]], i32 [[R]], i32 undef) #[[ATTR7]]
-; CGSCC-NEXT:    br label [[RETURN]]
-; CGSCC:       if.end12:
-; CGSCC-NEXT:    [[CMP13:%.*]] = icmp eq i32 [[A]], [[B]]
-; CGSCC-NEXT:    br i1 [[CMP13]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-; CGSCC:       cond.true:
-; CGSCC-NEXT:    br label [[COND_END:%.*]]
-; CGSCC:       cond.false:
-; CGSCC-NEXT:    [[CALL14:%.*]] = call i32 @scc_r2(i32 [[A]], i32 [[B]], i32 [[R]]) #[[ATTR7]]
-; CGSCC-NEXT:    br label [[COND_END]]
-; CGSCC:       cond.end:
-; CGSCC-NEXT:    [[COND:%.*]] = phi i32 [ [[R]], [[COND_TRUE]] ], [ [[R]], [[COND_FALSE]] ]
-; CGSCC-NEXT:    br label [[RETURN]]
-; CGSCC:       return:
-; CGSCC-NEXT:    [[RETVAL_0:%.*]] = phi i32 [ [[R]], [[IF_THEN]] ], [ [[R]], [[IF_THEN3]] ], [ [[R]], [[COND_END]] ]
-; CGSCC-NEXT:    ret i32 [[R]]
-;
-entry:
-  %cmp = icmp sgt i32 %a, %b
-  br i1 %cmp, label %if.then, label %if.end
-
-if.then:                                          ; preds = %entry
-  %call = call i32 @sink_r0(i32 %r)
-  %call1 = call i32 @scc_r2(i32 %b, i32 %a, i32 %call)
-  br label %return
-
-if.end:                                           ; preds = %entry
-  %cmp2 = icmp slt i32 %a, %b
-  br i1 %cmp2, label %if.then3, label %if.end12
-
-if.then3:                                         ; preds = %if.end
-  %call4 = call i32 @sink_r0(i32 %b)
-  %call5 = call i32 @scc_r1(i32 %a, i32 %b, i32 %r)
-  %call6 = call i32 @scc_r2(i32 %r, i32 %r, i32 %r)
-  %call7 = call i32 @scc_r1(i32 %a, i32 %call6, i32 %r)
-  %call8 = call i32 @scc_r2(i32 %a, i32 %b, i32 %r)
-  %call9 = call i32 @scc_r2(i32 %call5, i32 %call7, i32 %call8)
-  %call10 = call i32 @scc_r1(i32 %a, i32 %b, i32 %r)
-  %call11 = call i32 @scc_r1(i32 %call4, i32 %call9, i32 %call10)
-  br label %return
-
-if.end12:                                         ; preds = %if.end
-  %cmp13 = icmp eq i32 %a, %b
-  br i1 %cmp13, label %cond.true, label %cond.false
-
-cond.true:                                        ; preds = %if.end12
-  br label %cond.end
-
-cond.false:                                       ; preds = %if.end12
-  %call14 = call i32 @scc_r2(i32 %a, i32 %b, i32 %r)
-  br label %cond.end
-
-cond.end:                                         ; preds = %cond.false, %cond.true
-  %cond = phi i32 [ %r, %cond.true ], [ %call14, %cond.false ]
-  br label %return
-
-return:                                           ; preds = %cond.end, %if.then3, %if.then
-  %retval.0 = phi i32 [ %call1, %if.then ], [ %call11, %if.then3 ], [ %cond, %cond.end ]
-  ret i32 %retval.0
-}
-
-define i32 @scc_rX(i32 %a, i32 %b, i32 %r) #0 {
-; TUNIT: Function Attrs: nofree noinline norecurse nosync nounwind memory(none) uwtable
-; TUNIT-LABEL: define {{[^@]+}}@scc_rX
-; TUNIT-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[R:%.*]]) #[[ATTR2:[0-9]+]] {
-; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[A]], [[B]]
-; TUNIT-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
-; TUNIT:       if.then:
-; TUNIT-NEXT:    [[CALL1:%.*]] = call i32 @scc_r2(i32 [[B]], i32 [[A]], i32 [[R]]) #[[ATTR8]]
-; TUNIT-NEXT:    br label [[RETURN:%.*]]
-; TUNIT:       if.end:
-; TUNIT-NEXT:    [[CMP2:%.*]] = icmp slt i32 [[A]], [[B]]
-; TUNIT-NEXT:    br i1 [[CMP2]], label [[IF_THEN3:%.*]], label [[IF_END12:%.*]]
-; TUNIT:       if.then3:
-; TUNIT-NEXT:    [[CALL5:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[B]], i32 undef) #[[ATTR8]]
-; TUNIT-NEXT:    [[CALL6:%.*]] = call i32 @scc_r2(i32 [[R]], i32 [[R]], i32 [[R]]) #[[ATTR8]]
-; TUNIT-NEXT:    [[CALL7:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[R]], i32 undef) #[[ATTR8]]
-; TUNIT-NEXT:    [[CALL8:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[B]], i32 undef) #[[ATTR8]]
-; TUNIT-NEXT:    [[CALL9:%.*]] = call i32 @scc_r2(i32 [[B]], i32 [[R]], i32 [[B]]) #[[ATTR8]]
-; TUNIT-NEXT:    [[CALL11:%.*]] = call i32 @scc_r1(i32 [[B]], i32 [[B]], i32 undef) #[[ATTR8]]
-; TUNIT-NEXT:    br label [[RETURN]]
-; TUNIT:       if.end12:
-; TUNIT-NEXT:    [[CMP13:%.*]] = icmp eq i32 [[A]], [[B]]
-; TUNIT-NEXT:    br i1 [[CMP13]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-; TUNIT:       cond.true:
-; TUNIT-NEXT:    br label [[COND_END:%.*]]
-; TUNIT:       cond.false:
-; TUNIT-NEXT:    [[CALL14:%.*]] = call i32 @scc_r2(i32 [[A]], i32 [[B]], i32 [[R]]) #[[ATTR8]]
-; TUNIT-NEXT:    br label [[COND_END]]
-; TUNIT:       cond.end:
-; TUNIT-NEXT:    [[COND:%.*]] = phi i32 [ [[R]], [[COND_TRUE]] ], [ [[R]], [[COND_FALSE]] ]
-; TUNIT-NEXT:    br label [[RETURN]]
-; TUNIT:       return:
-; TUNIT-NEXT:    [[RETVAL_0:%.*]] = phi i32 [ [[R]], [[IF_THEN]] ], [ [[B]], [[IF_THEN3]] ], [ [[R]], [[COND_END]] ]
-; TUNIT-NEXT:    ret i32 [[RETVAL_0]]
-;
-; CGSCC: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
-; CGSCC-LABEL: define {{[^@]+}}@scc_rX
-; CGSCC-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[R:%.*]]) #[[ATTR1]] {
-; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[A]], [[B]]
-; CGSCC-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
-; CGSCC:       if.then:
-; CGSCC-NEXT:    [[CALL1:%.*]] = call i32 @scc_r2(i32 [[B]], i32 [[A]], i32 [[R]]) #[[ATTR7]]
-; CGSCC-NEXT:    br label [[RETURN:%.*]]
-; CGSCC:       if.end:
-; CGSCC-NEXT:    [[CMP2:%.*]] = icmp slt i32 [[A]], [[B]]
-; CGSCC-NEXT:    br i1 [[CMP2]], label [[IF_THEN3:%.*]], label [[IF_END12:%.*]]
-; CGSCC:       if.then3:
-; CGSCC-NEXT:    [[CALL5:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[B]], i32 [[R]]) #[[ATTR7]]
-; CGSCC-NEXT:    [[CALL6:%.*]] = call i32 @scc_r2(i32 [[R]], i32 [[R]], i32 [[R]]) #[[ATTR7]]
-; CGSCC-NEXT:    [[CALL7:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[R]], i32 [[R]]) #[[ATTR7]]
-; CGSCC-NEXT:    [[CALL8:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[B]], i32 [[R]]) #[[ATTR7]]
-; CGSCC-NEXT:    [[CALL9:%.*]] = call i32 @scc_r2(i32 [[B]], i32 [[R]], i32 [[B]]) #[[ATTR7]]
-; CGSCC-NEXT:    [[CALL10:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[B]], i32 [[R]]) #[[ATTR7]]
-; CGSCC-NEXT:    [[CALL11:%.*]] = call i32 @scc_r1(i32 [[B]], i32 [[B]], i32 [[B]]) #[[ATTR7]]
-; CGSCC-NEXT:    br label [[RETURN]]
-; CGSCC:       if.end12:
-; CGSCC-NEXT:    [[CMP13:%.*]] = icmp eq i32 [[A]], [[B]]
-; CGSCC-NEXT:    br i1 [[CMP13]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-; CGSCC:       cond.true:
-; CGSCC-NEXT:    br label [[COND_END:%.*]]
-; CGSCC:       cond.false:
-; CGSCC-NEXT:    [[CALL14:%.*]] = call i32 @scc_r2(i32 [[A]], i32 [[B]], i32 [[R]]) #[[ATTR7]]
-; CGSCC-NEXT:    br label [[COND_END]]
-; CGSCC:       cond.end:
-; CGSCC-NEXT:    [[COND:%.*]] = phi i32 [ [[R]], [[COND_TRUE]] ], [ [[CALL14]], [[COND_FALSE]] ]
-; CGSCC-NEXT:    br label [[RETURN]]
-; CGSCC:       return:
-; CGSCC-NEXT:    [[RETVAL_0:%.*]] = phi i32 [ [[CALL1]], [[IF_THEN]] ], [ [[CALL11]], [[IF_THEN3]] ], [ [[R]], [[COND_END]] ]
-; CGSCC-NEXT:    ret i32 [[RETVAL_0]]
-;
-entry:
-  %cmp = icmp sgt i32 %a, %b
-  br i1 %cmp, label %if.then, label %if.end
-
-if.then:                                          ; preds = %entry
-  %call = call i32 @sink_r0(i32 %r)
-  %call1 = call i32 @scc_r2(i32 %b, i32 %a, i32 %call)
-  br label %return
-
-if.end:                                           ; preds = %entry
-  %cmp2 = icmp slt i32 %a, %b
-  br i1 %cmp2, label %if.then3, label %if.end12
-
-if.then3:                                         ; preds = %if.end
-  %call4 = call i32 @sink_r0(i32 %b)
-  %call5 = call i32 @scc_r1(i32 %a, i32 %b, i32 %r)
-  %call6 = call i32 @scc_r2(i32 %r, i32 %r, i32 %r)
-  %call7 = call i32 @scc_r1(i32 %a, i32 %call6, i32 %r)
-  %call8 = call i32 @scc_r1(i32 %a, i32 %b, i32 %r)
-  %call9 = call i32 @scc_r2(i32 %call5, i32 %call7, i32 %call8)
-  %call10 = call i32 @scc_r1(i32 %a, i32 %b, i32 %r)
-  %call11 = call i32 @scc_r1(i32 %call4, i32 %call9, i32 %call10)
-  br label %return
-
-if.end12:                                         ; preds = %if.end
-  %cmp13 = icmp eq i32 %a, %b
-  br i1 %cmp13, label %cond.true, label %cond.false
-
-cond.true:                                        ; preds = %if.end12
-  br label %cond.end
-
-cond.false:                                       ; preds = %if.end12
-  %call14 = call i32 @scc_r2(i32 %a, i32 %b, i32 %r)
-  br label %cond.end
-
-cond.end:                                         ; preds = %cond.false, %cond.true
-  %cond = phi i32 [ %r, %cond.true ], [ %call14, %cond.false ]
-  br label %return
-
-return:                                           ; preds = %cond.end, %if.then3, %if.then
-  %retval.0 = phi i32 [ %call1, %if.then ], [ %call11, %if.then3 ], [ %cond, %cond.end ]
-  ret i32 %retval.0
-}
-
-
-; TEST SCC test returning a pointer value argument
-;
-; double* ptr_scc_r1(double* a, double* b, double* r);
-; double* ptr_scc_r2(double* a, double* b, double* r);
-;
-; __attribute__((noinline)) double* ptr_sink_r0(double* r) {
-;   return r;
-; }
-;
-; __attribute__((noinline)) double* ptr_scc_r1(double* a, double* r, double* b) {
-;   return ptr_scc_r2(r, a, ptr_sink_r0(r));
-; }
-;
-; __attribute__((noinline)) double* ptr_scc_r2(double* a, double* b, double* r) {
-;   if (a > b)
-;     return ptr_scc_r2(b, a, ptr_sink_r0(r));
-;   if (a < b)
-;     return ptr_scc_r1(ptr_sink_r0(b), ptr_scc_r2(ptr_scc_r1(a, b, r), ptr_scc_r1(a, ptr_scc_r2(r, r, r), r), ptr_scc_r2(a, b, r)), ptr_scc_r1(a, b, r));
-;   return a == b ? r : ptr_scc_r2(a, b, r);
-; }
 define ptr @ptr_sink_r0(ptr %r) #0 {
 ; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
 ; CHECK-LABEL: define {{[^@]+}}@ptr_sink_r0
-; CHECK-SAME: (ptr nofree nonnull readnone returned "no-capture-maybe-returned" [[R:%.*]]) #[[ATTR0]] {
+; CHECK-SAME: (ptr nofree readnone returned "no-capture-maybe-returned" [[R:%.*]]) #[[ATTR0:[0-9]+]] {
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    ret ptr [[R]]
 ;
+; CHECK-DL: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
+; CHECK-DL-LABEL: define {{[^@]+}}@ptr_sink_r0
+; CHECK-DL-SAME: (ptr nofree nonnull readnone returned "no-capture-maybe-returned" [[R:%.*]]) #[[ATTR0:[0-9]+]] {
+; CHECK-DL-NEXT:  entry:
+; CHECK-DL-NEXT:    ret ptr [[R]]
+;
 entry:
   ret ptr %r
 }
@@ -338,18 +28,32 @@ entry:
 define ptr @ptr_scc_r1(ptr %a, ptr %r, ptr %b) #0 {
 ; TUNIT: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
 ; TUNIT-LABEL: define {{[^@]+}}@ptr_scc_r1
-; TUNIT-SAME: (ptr nocapture nofree nonnull readnone [[A:%.*]], ptr nofree nonnull readnone returned "no-capture-maybe-returned" [[R:%.*]], ptr nocapture nofree nonnull readnone [[B:%.*]]) #[[ATTR1]] {
+; TUNIT-SAME: (ptr nocapture nofree readnone [[A:%.*]], ptr nofree readnone returned "no-capture-maybe-returned" [[R:%.*]], ptr nocapture nofree readnone [[B:%.*]]) #[[ATTR1:[0-9]+]] {
 ; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    [[CALL1:%.*]] = call ptr @ptr_scc_r2(ptr noalias nocapture nofree nonnull readnone [[R]], ptr noalias nocapture nofree nonnull readnone [[A]], ptr noalias nofree nonnull readnone "no-capture-maybe-returned" [[R]]) #[[ATTR8]]
+; TUNIT-NEXT:    [[CALL1:%.*]] = call ptr @ptr_scc_r2(ptr noalias nocapture nofree readnone [[R]], ptr noalias nocapture nofree readnone [[A]], ptr noalias nofree readnone "no-capture-maybe-returned" [[R]]) #[[ATTR5:[0-9]+]]
 ; TUNIT-NEXT:    ret ptr [[R]]
 ;
+; TUNIT-DL: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
+; TUNIT-DL-LABEL: define {{[^@]+}}@ptr_scc_r1
+; TUNIT-DL-SAME: (ptr nocapture nofree nonnull readnone [[A:%.*]], ptr nofree nonnull readnone returned "no-capture-maybe-returned" [[R:%.*]], ptr nocapture nofree nonnull readnone [[B:%.*]]) #[[ATTR1:[0-9]+]] {
+; TUNIT-DL-NEXT:  entry:
+; TUNIT-DL-NEXT:    [[CALL1:%.*]] = call ptr @ptr_scc_r2(ptr noalias nocapture nofree nonnull readnone [[R]], ptr noalias nocapture nofree nonnull readnone [[A]], ptr noalias nofree nonnull readnone "no-capture-maybe-returned" [[R]]) #[[ATTR5:[0-9]+]]
+; TUNIT-DL-NEXT:    ret ptr [[R]]
+;
 ; CGSCC: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
 ; CGSCC-LABEL: define {{[^@]+}}@ptr_scc_r1
-; CGSCC-SAME: (ptr nocapture nofree nonnull readnone [[A:%.*]], ptr nofree nonnull readnone returned [[R:%.*]], ptr nocapture nofree nonnull readnone [[B:%.*]]) #[[ATTR1]] {
+; CGSCC-SAME: (ptr nocapture nofree readnone [[A:%.*]], ptr nofree readnone returned [[R:%.*]], ptr nocapture nofree readnone [[B:%.*]]) #[[ATTR1:[0-9]+]] {
 ; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    [[CALL1:%.*]] = call ptr @ptr_scc_r2(ptr noalias nocapture nofree nonnull readnone [[R]], ptr noalias nocapture nofree nonnull readnone [[A]], ptr noalias nofree nonnull readnone [[R]]) #[[ATTR7]]
+; CGSCC-NEXT:    [[CALL1:%.*]] = call ptr @ptr_scc_r2(ptr noalias nocapture nofree readnone [[R]], ptr noalias nocapture nofree readnone [[A]], ptr noalias nofree readnone [[R]]) #[[ATTR5:[0-9]+]]
 ; CGSCC-NEXT:    ret ptr [[R]]
 ;
+; CGSCC-DL: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
+; CGSCC-DL-LABEL: define {{[^@]+}}@ptr_scc_r1
+; CGSCC-DL-SAME: (ptr nocapture nofree nonnull readnone [[A:%.*]], ptr nofree nonnull readnone returned [[R:%.*]], ptr nocapture nofree nonnull readnone [[B:%.*]]) #[[ATTR1:[0-9]+]] {
+; CGSCC-DL-NEXT:  entry:
+; CGSCC-DL-NEXT:    [[CALL1:%.*]] = call ptr @ptr_scc_r2(ptr noalias nocapture nofree nonnull readnone [[R]], ptr noalias nocapture nofree nonnull readnone [[A]], ptr noalias nofree nonnull readnone [[R]]) #[[ATTR5:[0-9]+]]
+; CGSCC-DL-NEXT:    ret ptr [[R]]
+;
 entry:
   %call = call ptr @ptr_sink_r0(ptr %r)
   %call1 = call ptr @ptr_scc_r2(ptr %r, ptr %a, ptr %call)
@@ -359,23 +63,23 @@ entry:
 define ptr @ptr_scc_r2(ptr %a, ptr %b, ptr %r) #0 {
 ; TUNIT: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
 ; TUNIT-LABEL: define {{[^@]+}}@ptr_scc_r2
-; TUNIT-SAME: (ptr nocapture nofree nonnull readnone [[A:%.*]], ptr nocapture nofree nonnull readnone [[B:%.*]], ptr nofree nonnull readnone returned "no-capture-maybe-returned" [[R:%.*]]) #[[ATTR1]] {
+; TUNIT-SAME: (ptr nocapture nofree readnone [[A:%.*]], ptr nocapture nofree readnone [[B:%.*]], ptr nofree readnone returned "no-capture-maybe-returned" [[R:%.*]]) #[[ATTR1]] {
 ; TUNIT-NEXT:  entry:
 ; TUNIT-NEXT:    [[CMP:%.*]] = icmp ugt ptr [[A]], [[B]]
 ; TUNIT-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
 ; TUNIT:       if.then:
-; TUNIT-NEXT:    [[CALL1:%.*]] = call ptr @ptr_scc_r2(ptr noalias nocapture nofree nonnull readnone [[B]], ptr noalias nocapture nofree nonnull readnone [[A]], ptr noalias nofree nonnull readnone "no-capture-maybe-returned" [[R]]) #[[ATTR8]]
+; TUNIT-NEXT:    [[CALL1:%.*]] = call ptr @ptr_scc_r2(ptr noalias nocapture nofree readnone [[B]], ptr noalias nocapture nofree nonnull readnone [[A]], ptr noalias nofree readnone "no-capture-maybe-returned" [[R]]) #[[ATTR5]]
 ; TUNIT-NEXT:    br label [[RETURN:%.*]]
 ; TUNIT:       if.end:
 ; TUNIT-NEXT:    [[CMP2:%.*]] = icmp ult ptr [[A]], [[B]]
 ; TUNIT-NEXT:    br i1 [[CMP2]], label [[IF_THEN3:%.*]], label [[IF_END12:%.*]]
 ; TUNIT:       if.then3:
-; TUNIT-NEXT:    [[CALL5:%.*]] = call nonnull ptr @ptr_scc_r1(ptr noalias nocapture nofree nonnull readnone [[A]], ptr noalias nofree nonnull readnone "no-capture-maybe-returned" [[B]], ptr noalias nocapture nofree nonnull readnone undef) #[[ATTR8]]
-; TUNIT-NEXT:    [[CALL6:%.*]] = call nonnull ptr @ptr_scc_r2(ptr noalias nocapture nofree nonnull readnone [[R]], ptr noalias nocapture nofree nonnull readnone [[R]], ptr noalias nofree nonnull readnone "no-capture-maybe-returned" [[R]]) #[[ATTR8]]
-; TUNIT-NEXT:    [[CALL7:%.*]] = call nonnull ptr @ptr_scc_r1(ptr noalias nocapture nofree nonnull readnone [[A]], ptr noalias nofree nonnull readnone "no-capture-maybe-returned" [[R]], ptr noalias nocapture nofree nonnull readnone undef) #[[ATTR8]]
-; TUNIT-NEXT:    [[CALL8:%.*]] = call nonnull ptr @ptr_scc_r2(ptr noalias nocapture nofree nonnull readnone [[A]], ptr noalias nocapture nofree nonnull readnone [[B]], ptr noalias nofree nonnull readnone "no-capture-maybe-returned" [[R]]) #[[ATTR8]]
-; TUNIT-NEXT:    [[CALL9:%.*]] = call nonnull ptr @ptr_scc_r2(ptr noalias nocapture nofree nonnull readnone [[B]], ptr noalias nocapture nofree nonnull readnone [[R]], ptr noalias nofree nonnull readnone "no-capture-maybe-returned" [[R]]) #[[ATTR8]]
-; TUNIT-NEXT:    [[CALL11:%.*]] = call ptr @ptr_scc_r1(ptr noalias nocapture nofree nonnull readnone [[B]], ptr noalias nofree nonnull readnone "no-capture-maybe-returned" [[R]], ptr noalias nocapture nofree nonnull readnone undef) #[[ATTR8]]
+; TUNIT-NEXT:    [[CALL5:%.*]] = call ptr @ptr_scc_r1(ptr noalias nocapture nofree readnone [[A]], ptr noalias nofree nonnull readnone "no-capture-maybe-returned" [[B]], ptr noalias nocapture nofree readnone undef) #[[ATTR5]]
+; TUNIT-NEXT:    [[CALL6:%.*]] = call ptr @ptr_scc_r2(ptr noalias nocapture nofree readnone [[R]], ptr noalias nocapture nofree readnone [[R]], ptr noalias nofree readnone "no-capture-maybe-returned" [[R]]) #[[ATTR5]]
+; TUNIT-NEXT:    [[CALL7:%.*]] = call ptr @ptr_scc_r1(ptr noalias nocapture nofree readnone [[A]], ptr noalias nofree readnone "no-capture-maybe-returned" [[R]], ptr noalias nocapture nofree readnone undef) #[[ATTR5]]
+; TUNIT-NEXT:    [[CALL8:%.*]] = call ptr @ptr_scc_r2(ptr noalias nocapture nofree readnone [[A]], ptr noalias nocapture nofree nonnull readnone [[B]], ptr noalias nofree readnone "no-capture-maybe-returned" [[R]]) #[[ATTR5]]
+; TUNIT-NEXT:    [[CALL9:%.*]] = call ptr @ptr_scc_r2(ptr noalias nocapture nofree readnone [[B]], ptr noalias nocapture nofree readnone [[R]], ptr noalias nofree readnone "no-capture-maybe-returned" [[R]]) #[[ATTR5]]
+; TUNIT-NEXT:    [[CALL11:%.*]] = call ptr @ptr_scc_r1(ptr noalias nocapture nofree readnone [[B]], ptr noalias nofree readnone "no-capture-maybe-returned" [[R]], ptr noalias nocapture nofree readnone undef) #[[ATTR5]]
 ; TUNIT-NEXT:    br label [[RETURN]]
 ; TUNIT:       if.end12:
 ; TUNIT-NEXT:    [[CMP13:%.*]] = icmp eq ptr [[A]], [[B]]
@@ -383,7 +87,7 @@ define ptr @ptr_scc_r2(ptr %a, ptr %b, ptr %r) #0 {
 ; TUNIT:       cond.true:
 ; TUNIT-NEXT:    br label [[COND_END:%.*]]
 ; TUNIT:       cond.false:
-; TUNIT-NEXT:    [[CALL14:%.*]] = call ptr @ptr_scc_r2(ptr noalias nocapture nofree nonnull readnone [[A]], ptr noalias nocapture nofree nonnull readnone [[B]], ptr noalias nofree nonnull readnone "no-capture-maybe-returned" [[R]]) #[[ATTR8]]
+; TUNIT-NEXT:    [[CALL14:%.*]] = call ptr @ptr_scc_r2(ptr noalias nocapture nofree readnone [[A]], ptr noalias nocapture nofree readnone [[B]], ptr noalias nofree readnone "no-capture-maybe-returned" [[R]]) #[[ATTR5]]
 ; TUNIT-NEXT:    br label [[COND_END]]
 ; TUNIT:       cond.end:
 ; TUNIT-NEXT:    [[COND:%.*]] = phi ptr [ [[R]], [[COND_TRUE]] ], [ [[R]], [[COND_FALSE]] ]
@@ -392,25 +96,60 @@ define ptr @ptr_scc_r2(ptr %a, ptr %b, ptr %r) #0 {
 ; TUNIT-NEXT:    [[RETVAL_0:%.*]] = phi ptr [ [[R]], [[IF_THEN]] ], [ [[R]], [[IF_THEN3]] ], [ [[R]], [[COND_END]] ]
 ; TUNIT-NEXT:    ret ptr [[R]]
 ;
+; TUNIT-DL: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
+; TUNIT-DL-LABEL: define {{[^@]+}}@ptr_scc_r2
+; TUNIT-DL-SAME: (ptr nocapture nofree nonnull readnone [[A:%.*]], ptr nocapture nofree nonnull readnone [[B:%.*]], ptr nofree nonnull readnone returned "no-capture-maybe-returned" [[R:%.*]]) #[[ATTR1]] {
+; TUNIT-DL-NEXT:  entry:
+; TUNIT-DL-NEXT:    [[CMP:%.*]] = icmp ugt ptr [[A]], [[B]]
+; TUNIT-DL-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
+; TUNIT-DL:       if.then:
+; TUNIT-DL-NEXT:    [[CALL1:%.*]] = call ptr @ptr_scc_r2(ptr noalias nocapture nofree nonnull readnone [[B]], ptr noalias nocapture nofree nonnull readnone [[A]], ptr noalias nofree nonnull readnone "no-capture-maybe-returned" [[R]]) #[[ATTR5]]
+; TUNIT-DL-NEXT:    br label [[RETURN:%.*]]
+; TUNIT-DL:       if.end:
+; TUNIT-DL-NEXT:    [[CMP2:%.*]] = icmp ult ptr [[A]], [[B]]
+; TUNIT-DL-NEXT:    br i1 [[CMP2]], label [[IF_THEN3:%.*]], label [[IF_END12:%.*]]
+; TUNIT-DL:       if.then3:
+; TUNIT-DL-NEXT:    [[CALL5:%.*]] = call nonnull ptr @ptr_scc_r1(ptr noalias nocapture nofree nonnull readnone [[A]], ptr noalias nofree nonnull readnone "no-capture-maybe-returned" [[B]], ptr noalias nocapture nofree nonnull readnone undef) #[[ATTR5]]
+; TUNIT-DL-NEXT:    [[CALL6:%.*]] = call nonnull ptr @ptr_scc_r2(ptr noalias nocapture nofree nonnull readnone [[R]], ptr noalias nocapture nofree nonnull readnone [[R]], ptr noalias nofree nonnull readnone "no-capture-maybe-returned" [[R]]) #[[ATTR5]]
+; TUNIT-DL-NEXT:    [[CALL7:%.*]] = call nonnull ptr @ptr_scc_r1(ptr noalias nocapture nofree nonnull readnone [[A]], ptr noalias nofree nonnull readnone "no-capture-maybe-returned" [[R]], ptr noalias nocapture nofree nonnull readnone undef) #[[ATTR5]]
+; TUNIT-DL-NEXT:    [[CALL8:%.*]] = call nonnull ptr @ptr_scc_r2(ptr noalias nocapture nofree nonnull readnone [[A]], ptr noalias nocapture nofree nonnull readnone [[B]], ptr noalias nofree nonnull readnone "no-capture-maybe-returned" [[R]]) #[[ATTR5]]
+; TUNIT-DL-NEXT:    [[CALL9:%.*]] = call nonnull ptr @ptr_scc_r2(ptr noalias nocapture nofree nonnull readnone [[B]], ptr noalias nocapture nofree nonnull readnone [[R]], ptr noalias nofree nonnull readnone "no-capture-maybe-returned" [[R]]) #[[ATTR5]]
+; TUNIT-DL-NEXT:    [[CALL11:%.*]] = call ptr @ptr_scc_r1(ptr noalias nocapture nofree nonnull readnone [[B]], ptr noalias nofree nonnull readnone "no-capture-maybe-returned" [[R]], ptr noalias nocapture nofree nonnull readnone undef) #[[ATTR5]]
+; TUNIT-DL-NEXT:    br label [[RETURN]]
+; TUNIT-DL:       if.end12:
+; TUNIT-DL-NEXT:    [[CMP13:%.*]] = icmp eq ptr [[A]], [[B]]
+; TUNIT-DL-NEXT:    br i1 [[CMP13]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
+; TUNIT-DL:       cond.true:
+; TUNIT-DL-NEXT:    br label [[COND_END:%.*]]
+; TUNIT-DL:       cond.false:
+; TUNIT-DL-NEXT:    [[CALL14:%.*]] = call ptr @ptr_scc_r2(ptr noalias nocapture nofree nonnull readnone [[A]], ptr noalias nocapture nofree nonnull readnone [[B]], ptr noalias nofree nonnull readnone "no-capture-maybe-returned" [[R]]) #[[ATTR5]]
+; TUNIT-DL-NEXT:    br label [[COND_END]]
+; TUNIT-DL:       cond.end:
+; TUNIT-DL-NEXT:    [[COND:%.*]] = phi ptr [ [[R]], [[COND_TRUE]] ], [ [[R]], [[COND_FALSE]] ]
+; TUNIT-DL-NEXT:    br label [[RETURN]]
+; TUNIT-DL:       return:
+; TUNIT-DL-NEXT:    [[RETVAL_0:%.*]] = phi ptr [ [[R]], [[IF_THEN]] ], [ [[R]], [[IF_THEN3]] ], [ [[R]], [[COND_END]] ]
+; TUNIT-DL-NEXT:    ret ptr [[R]]
+;
 ; CGSCC: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
 ; CGSCC-LABEL: define {{[^@]+}}@ptr_scc_r2
-; CGSCC-SAME: (ptr nocapture nofree nonnull readnone [[A:%.*]], ptr nocapture nofree nonnull readnone [[B:%.*]], ptr nofree nonnull readnone returned [[R:%.*]]) #[[ATTR1]] {
+; CGSCC-SAME: (ptr nocapture nofree readnone [[A:%.*]], ptr nocapture nofree readnone [[B:%.*]], ptr nofree readnone returned [[R:%.*]]) #[[ATTR1]] {
 ; CGSCC-NEXT:  entry:
 ; CGSCC-NEXT:    [[CMP:%.*]] = icmp ugt ptr [[A]], [[B]]
 ; CGSCC-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
 ; CGSCC:       if.then:
-; CGSCC-NEXT:    [[CALL1:%.*]] = call ptr @ptr_scc_r2(ptr noalias nocapture nofree nonnull readnone [[B]], ptr noalias nocapture nofree nonnull readnone [[A]], ptr noalias nofree nonnull readnone [[R]]) #[[ATTR7]]
+; CGSCC-NEXT:    [[CALL1:%.*]] = call ptr @ptr_scc_r2(ptr noalias nocapture nofree readnone [[B]], ptr noalias nocapture nofree nonnull readnone [[A]], ptr noalias nofree readnone [[R]]) #[[ATTR5]]
 ; CGSCC-NEXT:    br label [[RETURN:%.*]]
 ; CGSCC:       if.end:
 ; CGSCC-NEXT:    [[CMP2:%.*]] = icmp ult ptr [[A]], [[B]]
 ; CGSCC-NEXT:    br i1 [[CMP2]], label [[IF_THEN3:%.*]], label [[IF_END12:%.*]]
 ; CGSCC:       if.then3:
-; CGSCC-NEXT:    [[CALL5:%.*]] = call nonnull ptr @ptr_scc_r1(ptr noalias nocapture nofree nonnull readnone [[A]], ptr noalias nofree nonnull readnone [[B]], ptr noalias nocapture nofree nonnull readnone undef) #[[ATTR7]]
-; CGSCC-NEXT:    [[CALL6:%.*]] = call nonnull ptr @ptr_scc_r2(ptr noalias nocapture nofree nonnull readnone [[R]], ptr noalias nocapture nofree nonnull readnone [[R]], ptr noalias nofree nonnull readnone [[R]]) #[[ATTR7]]
-; CGSCC-NEXT:    [[CALL7:%.*]] = call nonnull ptr @ptr_scc_r1(ptr noalias nocapture nofree nonnull readnone [[A]], ptr noalias nofree nonnull readnone [[R]], ptr noalias nocapture nofree nonnull readnone undef) #[[ATTR7]]
-; CGSCC-NEXT:    [[CALL8:%.*]] = call nonnull ptr @ptr_scc_r2(ptr noalias nocapture nofree nonnull readnone [[A]], ptr noalias nocapture nofree nonnull readnone [[B]], ptr noalias nofree nonnull readnone [[R]]) #[[ATTR7]]
-; CGSCC-NEXT:    [[CALL9:%.*]] = call nonnull ptr @ptr_scc_r2(ptr noalias nocapture nofree nonnull readnone [[B]], ptr noalias nocapture nofree nonnull readnone [[R]], ptr noalias nofree nonnull readnone [[R]]) #[[ATTR7]]
-; CGSCC-NEXT:    [[CALL11:%.*]] = call ptr @ptr_scc_r1(ptr noalias nocapture nofree nonnull readnone [[B]], ptr noalias nofree nonnull readnone [[R]], ptr noalias nocapture nofree nonnull readnone undef) #[[ATTR7]]
+; CGSCC-NEXT:    [[CALL5:%.*]] = call ptr @ptr_scc_r1(ptr noalias nocapture nofree readnone [[A]], ptr noalias nofree nonnull readnone [[B]], ptr noalias nocapture nofree readnone undef) #[[ATTR5]]
+; CGSCC-NEXT:    [[CALL6:%.*]] = call ptr @ptr_scc_r2(ptr noalias nocapture nofree readnone [[R]], ptr noalias nocapture nofree readnone [[R]], ptr noalias nofree readnone [[R]]) #[[ATTR5]]
+; CGSCC-NEXT:    [[CALL7:%.*]] = call ptr @ptr_scc_r1(ptr noalias nocapture nofree readnone [[A]], ptr noalias nofree readnone [[R]], ptr noalias nocapture nofree readnone undef) #[[ATTR5]]
+; CGSCC-NEXT:    [[CALL8:%.*]] = call ptr @ptr_scc_r2(ptr noalias nocapture nofree readnone [[A]], ptr noalias nocapture nofree nonnull readnone [[B]], ptr noalias nofree readnone [[R]]) #[[ATTR5]]
+; CGSCC-NEXT:    [[CALL9:%.*]] = call ptr @ptr_scc_r2(ptr noalias nocapture nofree readnone [[B]], ptr noalias nocapture nofree readnone [[R]], ptr noalias nofree readnone [[R]]) #[[ATTR5]]
+; CGSCC-NEXT:    [[CALL11:%.*]] = call ptr @ptr_scc_r1(ptr noalias nocapture nofree nonnull readnone [[B]], ptr noalias nofree readnone [[R]], ptr noalias nocapture nofree readnone undef) #[[ATTR5]]
 ; CGSCC-NEXT:    br label [[RETURN]]
 ; CGSCC:       if.end12:
 ; CGSCC-NEXT:    [[CMP13:%.*]] = icmp eq ptr [[A]], [[B]]
@@ -418,7 +157,7 @@ define ptr @ptr_scc_r2(ptr %a, ptr %b, ptr %r) #0 {
 ; CGSCC:       cond.true:
 ; CGSCC-NEXT:    br label [[COND_END:%.*]]
 ; CGSCC:       cond.false:
-; CGSCC-NEXT:    [[CALL14:%.*]] = call ptr @ptr_scc_r2(ptr noalias nocapture nofree nonnull readnone [[A]], ptr noalias nocapture nofree nonnull readnone [[B]], ptr noalias nofree nonnull readnone [[R]]) #[[ATTR7]]
+; CGSCC-NEXT:    [[CALL14:%.*]] = call ptr @ptr_scc_r2(ptr noalias nocapture nofree readnone [[A]], ptr noalias nocapture nofree readnone [[B]], ptr noalias nofree readnone [[R]]) #[[ATTR5]]
 ; CGSCC-NEXT:    br label [[COND_END]]
 ; CGSCC:       cond.end:
 ; CGSCC-NEXT:    [[COND:%.*]] = phi ptr [ [[R]], [[COND_TRUE]] ], [ [[R]], [[COND_FALSE]] ]
@@ -427,6 +166,41 @@ define ptr @ptr_scc_r2(ptr %a, ptr %b, ptr %r) #0 {
 ; CGSCC-NEXT:    [[RETVAL_0:%.*]] = phi ptr [ [[R]], [[IF_THEN]] ], [ [[R]], [[IF_THEN3]] ], [ [[R]], [[COND_END]] ]
 ; CGSCC-NEXT:    ret ptr [[R]]
 ;
+; CGSCC-DL: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
+; CGSCC-DL-LABEL: define {{[^@]+}}@ptr_scc_r2
+; CGSCC-DL-SAME: (ptr nocapture nofree nonnull readnone [[A:%.*]], ptr nocapture nofree nonnull readnone [[B:%.*]], ptr nofree nonnull readnone returned [[R:%.*]]) #[[ATTR1]] {
+; CGSCC-DL-NEXT:  entry:
+; CGSCC-DL-NEXT:    [[CMP:%.*]] = icmp ugt ptr [[A]], [[B]]
+; CGSCC-DL-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
+; CGSCC-DL:       if.then:
+; CGSCC-DL-NEXT:    [[CALL1:%.*]] = call ptr @ptr_scc_r2(ptr noalias nocapture nofree nonnull readnone [[B]], ptr noalias nocapture nofree nonnull readnone [[A]], ptr noalias nofree nonnull readnone [[R]]) #[[ATTR5]]
+; CGSCC-DL-NEXT:    br label [[RETURN:%.*]]
+; CGSCC-DL:       if.end:
+; CGSCC-DL-NEXT:    [[CMP2:%.*]] = icmp ult ptr [[A]], [[B]]
+; CGSCC-DL-NEXT:    br i1 [[CMP2]], label [[IF_THEN3:%.*]], label [[IF_END12:%.*]]
+; CGSCC-DL:       if.then3:
+; CGSCC-DL-NEXT:    [[CALL5:%.*]] = call nonnull ptr @ptr_scc_r1(ptr noalias nocapture nofree nonnull readnone [[A]], ptr noalias nofree nonnull readnone [[B]], ptr noalias nocapture nofree nonnull readnone undef) #[[ATTR5]]
+; CGSCC-DL-NEXT:    [[CALL6:%.*]] = call nonnull ptr @ptr_scc_r2(ptr noalias nocapture nofree nonnull readnone [[R]], ptr noalias nocapture nofree nonnull readnone [[R]], ptr noalias nofree nonnull readnone [[R]]) #[[ATTR5]]
+; CGSCC-DL-NEXT:    [[CALL7:%.*]] = call nonnull ptr @ptr_scc_r1(ptr noalias nocapture nofree nonnull readnone [[A]], ptr noalias nofree nonnull readnone [[R]], ptr noalias nocapture nofree nonnull readnone undef) #[[ATTR5]]
+; CGSCC-DL-NEXT:    [[CALL8:%.*]] = call nonnull ptr @ptr_scc_r2(ptr noalias nocapture nofree nonnull readnone [[A]], ptr noalias nocapture nofree nonnull readnone [[B]], ptr noalias nofree nonnull readnone [[R]]) #[[ATTR5]]
+; CGSCC-DL-NEXT:    [[CALL9:%.*]] = call nonnull ptr @ptr_scc_r2(ptr noalias nocapture nofree nonnull readnone [[B]], ptr noalias nocapture nofree nonnull readnone [[R]], ptr noalias nofree nonnull readnone [[R]]) #[[ATTR5]]
+; CGSCC-DL-NEXT:    [[CALL11:%.*]] = call ptr @ptr_scc_r1(ptr noalias nocapture nofree nonnull readnone [[B]], ptr noalias nofree nonnull readnone [[R]], ptr noalias nocapture nofree nonnull readnone undef) #[[ATTR5]]
+; CGSCC-DL-NEXT:    br label [[RETURN]]
+; CGSCC-DL:       if.end12:
+; CGSCC-DL-NEXT:    [[CMP13:%.*]] = icmp eq ptr [[A]], [[B]]
+; CGSCC-DL-NEXT:    br i1 [[CMP13]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
+; CGSCC-DL:       cond.true:
+; CGSCC-DL-NEXT:    br label [[COND_END:%.*]]
+; CGSCC-DL:       cond.false:
+; CGSCC-DL-NEXT:    [[CALL14:%.*]] = call ptr @ptr_scc_r2(ptr noalias nocapture nofree nonnull readnone [[A]], ptr noalias nocapture nofree nonnull readnone [[B]], ptr noalias nofree nonnull readnone [[R]]) #[[ATTR5]]
+; CGSCC-DL-NEXT:    br label [[COND_END]]
+; CGSCC-DL:       cond.end:
+; CGSCC-DL-NEXT:    [[COND:%.*]] = phi ptr [ [[R]], [[COND_TRUE]] ], [ [[R]], [[COND_FALSE]] ]
+; CGSCC-DL-NEXT:    br label [[RETURN]]
+; CGSCC-DL:       return:
+; CGSCC-DL-NEXT:    [[RETVAL_0:%.*]] = phi ptr [ [[R]], [[IF_THEN]] ], [ [[R]], [[IF_THEN3]] ], [ [[R]], [[COND_END]] ]
+; CGSCC-DL-NEXT:    ret ptr [[R]]
+;
 entry:
   %cmp = icmp ugt ptr %a, %b
   br i1 %cmp, label %if.then, label %if.end
@@ -479,19 +253,19 @@ return:                                           ; preds = %cond.end, %if.then3
 ; }
 ;
 define ptr @rt0(ptr %a) #0 {
-; TUNIT: Function Attrs: nofree noinline nosync nounwind memory(argmem: read) uwtable
-; TUNIT-LABEL: define {{[^@]+}}@rt0
-; TUNIT-SAME: (ptr nofree noundef nonnull readonly returned align 4 dereferenceable(4) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR3:[0-9]+]] {
-; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    [[CALL:%.*]] = call ptr @rt0(ptr nofree noundef nonnull readonly align 4 dereferenceable(4) "no-capture-maybe-returned" [[A]]) #[[ATTR9:[0-9]+]]
-; TUNIT-NEXT:    ret ptr [[A]]
+; CHECK: Function Attrs: nofree noinline nosync nounwind memory(argmem: read) uwtable
+; CHECK-LABEL: define {{[^@]+}}@rt0
+; CHECK-SAME: (ptr nofree noundef nonnull readonly returned align 4 dereferenceable(4) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR2:[0-9]+]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CALL:%.*]] = call ptr @rt0(ptr nofree noundef nonnull readonly align 4 dereferenceable(4) "no-capture-maybe-returned" [[A]]) #[[ATTR6:[0-9]+]]
+; CHECK-NEXT:    ret ptr [[A]]
 ;
-; CGSCC: Function Attrs: nofree noinline nosync nounwind memory(argmem: read) uwtable
-; CGSCC-LABEL: define {{[^@]+}}@rt0
-; CGSCC-SAME: (ptr nofree noundef nonnull readonly returned align 4 dereferenceable(4) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR2:[0-9]+]] {
-; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    [[CALL:%.*]] = call ptr @rt0(ptr nofree noundef nonnull readonly align 4 dereferenceable(4) "no-capture-maybe-returned" [[A]]) #[[ATTR8:[0-9]+]]
-; CGSCC-NEXT:    ret ptr [[A]]
+; CHECK-DL: Function Attrs: nofree noinline nosync nounwind memory(argmem: read) uwtable
+; CHECK-DL-LABEL: define {{[^@]+}}@rt0
+; CHECK-DL-SAME: (ptr nofree noundef nonnull readonly returned align 4 dereferenceable(4) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR2:[0-9]+]] {
+; CHECK-DL-NEXT:  entry:
+; CHECK-DL-NEXT:    [[CALL:%.*]] = call ptr @rt0(ptr nofree noundef nonnull readonly align 4 dereferenceable(4) "no-capture-maybe-returned" [[A]]) #[[ATTR6:[0-9]+]]
+; CHECK-DL-NEXT:    ret ptr [[A]]
 ;
 entry:
   %v = load i32, ptr %a, align 4
@@ -508,17 +282,17 @@ entry:
 ; }
 ;
 define ptr @rt1(ptr %a) #0 {
-; TUNIT: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable
-; TUNIT-LABEL: define {{[^@]+}}@rt1
-; TUNIT-SAME: (ptr nocapture nofree nonnull readnone align 4 dereferenceable(4) [[A:%.*]]) #[[ATTR4:[0-9]+]] {
-; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    ret ptr undef
+; CHECK: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable
+; CHECK-LABEL: define {{[^@]+}}@rt1
+; CHECK-SAME: (ptr nocapture nofree nonnull readnone align 4 dereferenceable(4) [[A:%.*]]) #[[ATTR3:[0-9]+]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    ret ptr undef
 ;
-; CGSCC: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable
-; CGSCC-LABEL: define {{[^@]+}}@rt1
-; CGSCC-SAME: (ptr nocapture nofree nonnull readnone align 4 dereferenceable(4) [[A:%.*]]) #[[ATTR3:[0-9]+]] {
-; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    ret ptr undef
+; CHECK-DL: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable
+; CHECK-DL-LABEL: define {{[^@]+}}@rt1
+; CHECK-DL-SAME: (ptr nocapture nofree nonnull readnone align 4 dereferenceable(4) [[A:%.*]]) #[[ATTR3:[0-9]+]] {
+; CHECK-DL-NEXT:  entry:
+; CHECK-DL-NEXT:    ret ptr undef
 ;
 entry:
   %v = load i32, ptr %a, align 4
@@ -531,27 +305,47 @@ entry:
 ; TEST another SCC test
 ;
 define ptr @rt2_helper(ptr %a) #0 {
-; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
+; CHECK: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
 ; CHECK-LABEL: define {{[^@]+}}@rt2_helper
-; CHECK-SAME: (ptr nofree nonnull readnone returned "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR0]] {
+; CHECK-SAME: (ptr nofree readnone returned [[A:%.*]]) #[[ATTR1:[0-9]+]] {
 ; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CALL:%.*]] = call ptr @rt2(ptr noalias nofree readnone [[A]], ptr noalias nofree readnone "no-capture-maybe-returned" [[A]]) #[[ATTR5:[0-9]+]]
 ; CHECK-NEXT:    ret ptr [[A]]
 ;
+; CHECK-DL: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
+; CHECK-DL-LABEL: define {{[^@]+}}@rt2_helper
+; CHECK-DL-SAME: (ptr nofree nonnull readnone returned "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR0]] {
+; CHECK-DL-NEXT:  entry:
+; CHECK-DL-NEXT:    ret ptr [[A]]
+;
 entry:
   %call = call ptr @rt2(ptr %a, ptr %a)
   ret ptr %call
 }
 
 define ptr @rt2(ptr %a, ptr %b) #0 {
-; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
+; CHECK: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
 ; CHECK-LABEL: define {{[^@]+}}@rt2
-; CHECK-SAME: (ptr nocapture nofree nonnull readnone [[A:%.*]], ptr nofree nonnull readnone returned "no-capture-maybe-returned" [[B:%.*]]) #[[ATTR0]] {
+; CHECK-SAME: (ptr nofree readnone [[A:%.*]], ptr nofree readnone "no-capture-maybe-returned" [[B:%.*]]) #[[ATTR1]] {
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    br label [[IF_END:%.*]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[A]], null
+; CHECK-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
 ; CHECK:       if.then:
-; CHECK-NEXT:    unreachable
+; CHECK-NEXT:    [[CALL:%.*]] = call ptr @rt2_helper(ptr noalias nofree readnone [[A]]) #[[ATTR5]]
+; CHECK-NEXT:    br label [[IF_END]]
 ; CHECK:       if.end:
-; CHECK-NEXT:    ret ptr [[B]]
+; CHECK-NEXT:    [[SEL:%.*]] = phi ptr [ [[B]], [[ENTRY:%.*]] ], [ [[A]], [[IF_THEN]] ]
+; CHECK-NEXT:    ret ptr [[SEL]]
+;
+; CHECK-DL: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
+; CHECK-DL-LABEL: define {{[^@]+}}@rt2
+; CHECK-DL-SAME: (ptr nocapture nofree nonnull readnone [[A:%.*]], ptr nofree nonnull readnone returned "no-capture-maybe-returned" [[B:%.*]]) #[[ATTR0]] {
+; CHECK-DL-NEXT:  entry:
+; CHECK-DL-NEXT:    br label [[IF_END:%.*]]
+; CHECK-DL:       if.then:
+; CHECK-DL-NEXT:    unreachable
+; CHECK-DL:       if.end:
+; CHECK-DL-NEXT:    ret ptr [[B]]
 ;
 entry:
   %cmp = icmp eq ptr %a, null
@@ -569,28 +363,48 @@ if.end:
 ; TEST another SCC test
 ;
 define ptr @rt3_helper(ptr %a, ptr %b) #0 {
-; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
+; CHECK: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
 ; CHECK-LABEL: define {{[^@]+}}@rt3_helper
-; CHECK-SAME: (ptr nocapture nofree nonnull readnone [[A:%.*]], ptr nofree nonnull readnone returned "no-capture-maybe-returned" [[B:%.*]]) #[[ATTR0]] {
+; CHECK-SAME: (ptr nocapture nofree readnone [[A:%.*]], ptr nofree readnone returned "no-capture-maybe-returned" [[B:%.*]]) #[[ATTR1]] {
 ; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CALL:%.*]] = call ptr @rt3(ptr noalias nocapture nofree readnone [[A]], ptr noalias nofree readnone "no-capture-maybe-returned" [[B]]) #[[ATTR5]]
 ; CHECK-NEXT:    ret ptr [[B]]
 ;
+; CHECK-DL: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
+; CHECK-DL-LABEL: define {{[^@]+}}@rt3_helper
+; CHECK-DL-SAME: (ptr nocapture nofree nonnull readnone [[A:%.*]], ptr nofree nonnull readnone returned "no-capture-maybe-returned" [[B:%.*]]) #[[ATTR0]] {
+; CHECK-DL-NEXT:  entry:
+; CHECK-DL-NEXT:    ret ptr [[B]]
+;
 entry:
   %call = call ptr @rt3(ptr %a, ptr %b)
   ret ptr %call
 }
 
 define ptr @rt3(ptr %a, ptr %b) #0 {
-; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
+; CHECK: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
 ; CHECK-LABEL: define {{[^@]+}}@rt3
-; CHECK-SAME: (ptr nocapture nofree nonnull readnone [[A:%.*]], ptr nofree nonnull readnone returned "no-capture-maybe-returned" [[B:%.*]]) #[[ATTR0]] {
+; CHECK-SAME: (ptr nocapture nofree readnone [[A:%.*]], ptr nofree readnone returned "no-capture-maybe-returned" [[B:%.*]]) #[[ATTR1]] {
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    br label [[IF_END:%.*]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[A]], null
+; CHECK-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
 ; CHECK:       if.then:
-; CHECK-NEXT:    unreachable
+; CHECK-NEXT:    [[CALL:%.*]] = call ptr @rt3_helper(ptr noalias nocapture nofree readnone [[A]], ptr noalias nofree readnone "no-capture-maybe-returned" [[B]]) #[[ATTR5]]
+; CHECK-NEXT:    br label [[IF_END]]
 ; CHECK:       if.end:
+; CHECK-NEXT:    [[SEL:%.*]] = phi ptr [ [[B]], [[ENTRY:%.*]] ], [ [[B]], [[IF_THEN]] ]
 ; CHECK-NEXT:    ret ptr [[B]]
 ;
+; CHECK-DL: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
+; CHECK-DL-LABEL: define {{[^@]+}}@rt3
+; CHECK-DL-SAME: (ptr nocapture nofree nonnull readnone [[A:%.*]], ptr nofree nonnull readnone returned "no-capture-maybe-returned" [[B:%.*]]) #[[ATTR0]] {
+; CHECK-DL-NEXT:  entry:
+; CHECK-DL-NEXT:    br label [[IF_END:%.*]]
+; CHECK-DL:       if.then:
+; CHECK-DL-NEXT:    unreachable
+; CHECK-DL:       if.end:
+; CHECK-DL-NEXT:    ret ptr [[B]]
+;
 entry:
   %cmp = icmp eq ptr %a, null
   br i1 %cmp, label %if.then, label %if.end
@@ -616,17 +430,17 @@ if.end:
 declare void @unknown_fn(ptr) #0
 
 define ptr @calls_unknown_fn(ptr %r) #0 {
-; TUNIT: Function Attrs: noinline nounwind uwtable
-; TUNIT-LABEL: define {{[^@]+}}@calls_unknown_fn
-; TUNIT-SAME: (ptr nofree nonnull readnone returned "no-capture-maybe-returned" [[R:%.*]]) #[[ATTR5:[0-9]+]] {
-; TUNIT-NEXT:    tail call void @unknown_fn(ptr noundef nonnull @calls_unknown_fn) #[[ATTR10:[0-9]+]]
-; TUNIT-NEXT:    ret ptr [[R]]
+; CHECK: Function Attrs: noinline nounwind uwtable
+; CHECK-LABEL: define {{[^@]+}}@calls_unknown_fn
+; CHECK-SAME: (ptr nofree readnone returned "no-capture-maybe-returned" [[R:%.*]]) #[[ATTR4:[0-9]+]] {
+; CHECK-NEXT:    tail call void @unknown_fn(ptr noundef nonnull @calls_unknown_fn) #[[ATTR7:[0-9]+]]
+; CHECK-NEXT:    ret ptr [[R]]
 ;
-; CGSCC: Function Attrs: noinline nounwind uwtable
-; CGSCC-LABEL: define {{[^@]+}}@calls_unknown_fn
-; CGSCC-SAME: (ptr nofree nonnull readnone returned "no-capture-maybe-returned" [[R:%.*]]) #[[ATTR4:[0-9]+]] {
-; CGSCC-NEXT:    tail call void @unknown_fn(ptr noundef nonnull @calls_unknown_fn) #[[ATTR9:[0-9]+]]
-; CGSCC-NEXT:    ret ptr [[R]]
+; CHECK-DL: Function Attrs: noinline nounwind uwtable
+; CHECK-DL-LABEL: define {{[^@]+}}@calls_unknown_fn
+; CHECK-DL-SAME: (ptr nofree nonnull readnone returned "no-capture-maybe-returned" [[R:%.*]]) #[[ATTR4:[0-9]+]] {
+; CHECK-DL-NEXT:    tail call void @unknown_fn(ptr noundef nonnull @calls_unknown_fn) #[[ATTR7:[0-9]+]]
+; CHECK-DL-NEXT:    ret ptr [[R]]
 ;
   tail call void @unknown_fn(ptr nonnull @calls_unknown_fn)
   ret ptr %r
@@ -647,36 +461,36 @@ define ptr @calls_unknown_fn(ptr %r) #0 {
 ; Verify the maybe-redefined function is not annotated:
 ;
 define linkonce_odr ptr @maybe_redefined_fn(ptr %r) #0 {
-; TUNIT: Function Attrs: noinline nounwind uwtable
-; TUNIT-LABEL: define {{[^@]+}}@maybe_redefined_fn
-; TUNIT-SAME: (ptr [[R:%.*]]) #[[ATTR5]] {
-; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    ret ptr [[R]]
+; CHECK: Function Attrs: noinline nounwind uwtable
+; CHECK-LABEL: define {{[^@]+}}@maybe_redefined_fn
+; CHECK-SAME: (ptr [[R:%.*]]) #[[ATTR4]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    ret ptr [[R]]
 ;
-; CGSCC: Function Attrs: noinline nounwind uwtable
-; CGSCC-LABEL: define {{[^@]+}}@maybe_redefined_fn
-; CGSCC-SAME: (ptr [[R:%.*]]) #[[ATTR4]] {
-; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    ret ptr [[R]]
+; CHECK-DL: Function Attrs: noinline nounwind uwtable
+; CHECK-DL-LABEL: define {{[^@]+}}@maybe_redefined_fn
+; CHECK-DL-SAME: (ptr [[R:%.*]]) #[[ATTR4]] {
+; CHECK-DL-NEXT:  entry:
+; CHECK-DL-NEXT:    ret ptr [[R]]
 ;
 entry:
   ret ptr %r
 }
 
 define ptr @calls_maybe_redefined_fn(ptr %r) #0 {
-; TUNIT: Function Attrs: noinline nounwind uwtable
-; TUNIT-LABEL: define {{[^@]+}}@calls_maybe_redefined_fn
-; TUNIT-SAME: (ptr nonnull returned [[R:%.*]]) #[[ATTR5]] {
-; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    [[CALL:%.*]] = call ptr @maybe_redefined_fn(ptr nonnull [[R]]) #[[ATTR10]]
-; TUNIT-NEXT:    ret ptr [[R]]
+; CHECK: Function Attrs: noinline nounwind uwtable
+; CHECK-LABEL: define {{[^@]+}}@calls_maybe_redefined_fn
+; CHECK-SAME: (ptr returned [[R:%.*]]) #[[ATTR4]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CALL:%.*]] = call ptr @maybe_redefined_fn(ptr [[R]]) #[[ATTR7]]
+; CHECK-NEXT:    ret ptr [[R]]
 ;
-; CGSCC: Function Attrs: noinline nounwind uwtable
-; CGSCC-LABEL: define {{[^@]+}}@calls_maybe_redefined_fn
-; CGSCC-SAME: (ptr nonnull returned [[R:%.*]]) #[[ATTR4]] {
-; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    [[CALL:%.*]] = call ptr @maybe_redefined_fn(ptr nonnull [[R]]) #[[ATTR9]]
-; CGSCC-NEXT:    ret ptr [[R]]
+; CHECK-DL: Function Attrs: noinline nounwind uwtable
+; CHECK-DL-LABEL: define {{[^@]+}}@calls_maybe_redefined_fn
+; CHECK-DL-SAME: (ptr nonnull returned [[R:%.*]]) #[[ATTR4]] {
+; CHECK-DL-NEXT:  entry:
+; CHECK-DL-NEXT:    [[CALL:%.*]] = call ptr @maybe_redefined_fn(ptr nonnull [[R]]) #[[ATTR7]]
+; CHECK-DL-NEXT:    ret ptr [[R]]
 ;
 entry:
   %call = call ptr @maybe_redefined_fn(ptr %r)
@@ -696,36 +510,36 @@ entry:
 ; Verify the maybe-redefined function is not annotated:
 ;
 define linkonce_odr ptr @maybe_redefined_fn2(ptr %r) #0 {
-; TUNIT: Function Attrs: noinline nounwind uwtable
-; TUNIT-LABEL: define {{[^@]+}}@maybe_redefined_fn2
-; TUNIT-SAME: (ptr [[R:%.*]]) #[[ATTR5]] {
-; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    ret ptr [[R]]
+; CHECK: Function Attrs: noinline nounwind uwtable
+; CHECK-LABEL: define {{[^@]+}}@maybe_redefined_fn2
+; CHECK-SAME: (ptr [[R:%.*]]) #[[ATTR4]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    ret ptr [[R]]
 ;
-; CGSCC: Function Attrs: noinline nounwind uwtable
-; CGSCC-LABEL: define {{[^@]+}}@maybe_redefined_fn2
-; CGSCC-SAME: (ptr [[R:%.*]]) #[[ATTR4]] {
-; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    ret ptr [[R]]
+; CHECK-DL: Function Attrs: noinline nounwind uwtable
+; CHECK-DL-LABEL: define {{[^@]+}}@maybe_redefined_fn2
+; CHECK-DL-SAME: (ptr [[R:%.*]]) #[[ATTR4]] {
+; CHECK-DL-NEXT:  entry:
+; CHECK-DL-NEXT:    ret ptr [[R]]
 ;
 entry:
   ret ptr %r
 }
 
 define ptr @calls_maybe_redefined_fn2(ptr %r) #0 {
-; TUNIT: Function Attrs: noinline nounwind uwtable
-; TUNIT-LABEL: define {{[^@]+}}@calls_maybe_redefined_fn2
-; TUNIT-SAME: (ptr nonnull [[R:%.*]]) #[[ATTR5]] {
-; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    [[CALL:%.*]] = call nonnull ptr @maybe_redefined_fn2(ptr nonnull [[R]]) #[[ATTR10]]
-; TUNIT-NEXT:    ret ptr [[CALL]]
+; CHECK: Function Attrs: noinline nounwind uwtable
+; CHECK-LABEL: define {{[^@]+}}@calls_maybe_redefined_fn2
+; CHECK-SAME: (ptr [[R:%.*]]) #[[ATTR4]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CALL:%.*]] = call ptr @maybe_redefined_fn2(ptr [[R]]) #[[ATTR7]]
+; CHECK-NEXT:    ret ptr [[CALL]]
 ;
-; CGSCC: Function Attrs: noinline nounwind uwtable
-; CGSCC-LABEL: define {{[^@]+}}@calls_maybe_redefined_fn2
-; CGSCC-SAME: (ptr nonnull [[R:%.*]]) #[[ATTR4]] {
-; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    [[CALL:%.*]] = call nonnull ptr @maybe_redefined_fn2(ptr nonnull [[R]]) #[[ATTR9]]
-; CGSCC-NEXT:    ret ptr [[CALL]]
+; CHECK-DL: Function Attrs: noinline nounwind uwtable
+; CHECK-DL-LABEL: define {{[^@]+}}@calls_maybe_redefined_fn2
+; CHECK-DL-SAME: (ptr nonnull [[R:%.*]]) #[[ATTR4]] {
+; CHECK-DL-NEXT:  entry:
+; CHECK-DL-NEXT:    [[CALL:%.*]] = call nonnull ptr @maybe_redefined_fn2(ptr nonnull [[R]]) #[[ATTR7]]
+; CHECK-DL-NEXT:    ret ptr [[CALL]]
 ;
 entry:
   %call = call ptr @maybe_redefined_fn2(ptr %r)
@@ -755,6 +569,18 @@ define double @select_and_phi(double %b) #0 {
 ; CHECK-NEXT:    [[PHI:%.*]] = phi double [ [[B]], [[IF_THEN]] ], [ [[B]], [[ENTRY:%.*]] ]
 ; CHECK-NEXT:    ret double [[B]]
 ;
+; CHECK-DL: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
+; CHECK-DL-LABEL: define {{[^@]+}}@select_and_phi
+; CHECK-DL-SAME: (double returned [[B:%.*]]) #[[ATTR0]] {
+; CHECK-DL-NEXT:  entry:
+; CHECK-DL-NEXT:    [[CMP:%.*]] = fcmp ogt double [[B]], 0.000000e+00
+; CHECK-DL-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
+; CHECK-DL:       if.then:
+; CHECK-DL-NEXT:    br label [[IF_END]]
+; CHECK-DL:       if.end:
+; CHECK-DL-NEXT:    [[PHI:%.*]] = phi double [ [[B]], [[IF_THEN]] ], [ [[B]], [[ENTRY:%.*]] ]
+; CHECK-DL-NEXT:    ret double [[B]]
+;
 entry:
   %cmp = fcmp ogt double %b, 0.000000e+00
   br i1 %cmp, label %if.then, label %if.end
@@ -780,33 +606,33 @@ if.end:                                           ; preds = %if.then, %entry
 ; }
 ;
 define double @recursion_select_and_phi(i32 %a, double %b) #0 {
-; TUNIT: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
-; TUNIT-LABEL: define {{[^@]+}}@recursion_select_and_phi
-; TUNIT-SAME: (i32 [[A:%.*]], double returned [[B:%.*]]) #[[ATTR1]] {
-; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    [[DEC:%.*]] = add nsw i32 [[A]], -1
-; TUNIT-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[A]], 0
-; TUNIT-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
-; TUNIT:       if.then:
-; TUNIT-NEXT:    [[CALL:%.*]] = call double @recursion_select_and_phi(i32 [[DEC]], double [[B]]) #[[ATTR8]]
-; TUNIT-NEXT:    br label [[IF_END]]
-; TUNIT:       if.end:
-; TUNIT-NEXT:    [[PHI:%.*]] = phi double [ [[B]], [[IF_THEN]] ], [ [[B]], [[ENTRY:%.*]] ]
-; TUNIT-NEXT:    ret double [[B]]
+; CHECK: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
+; CHECK-LABEL: define {{[^@]+}}@recursion_select_and_phi
+; CHECK-SAME: (i32 [[A:%.*]], double returned [[B:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[DEC:%.*]] = add nsw i32 [[A]], -1
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[A]], 0
+; CHECK-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
+; CHECK:       if.then:
+; CHECK-NEXT:    [[CALL:%.*]] = call double @recursion_select_and_phi(i32 [[DEC]], double [[B]]) #[[ATTR5]]
+; CHECK-NEXT:    br label [[IF_END]]
+; CHECK:       if.end:
+; CHECK-NEXT:    [[PHI:%.*]] = phi double [ [[B]], [[IF_THEN]] ], [ [[B]], [[ENTRY:%.*]] ]
+; CHECK-NEXT:    ret double [[B]]
 ;
-; CGSCC: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
-; CGSCC-LABEL: define {{[^@]+}}@recursion_select_and_phi
-; CGSCC-SAME: (i32 [[A:%.*]], double returned [[B:%.*]]) #[[ATTR1]] {
-; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    [[DEC:%.*]] = add nsw i32 [[A]], -1
-; CGSCC-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[A]], 0
-; CGSCC-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
-; CGSCC:       if.then:
-; CGSCC-NEXT:    [[CALL:%.*]] = call double @recursion_select_and_phi(i32 [[DEC]], double [[B]]) #[[ATTR7]]
-; CGSCC-NEXT:    br label [[IF_END]]
-; CGSCC:       if.end:
-; CGSCC-NEXT:    [[PHI:%.*]] = phi double [ [[B]], [[IF_THEN]] ], [ [[B]], [[ENTRY:%.*]] ]
-; CGSCC-NEXT:    ret double [[B]]
+; CHECK-DL: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
+; CHECK-DL-LABEL: define {{[^@]+}}@recursion_select_and_phi
+; CHECK-DL-SAME: (i32 [[A:%.*]], double returned [[B:%.*]]) #[[ATTR1:[0-9]+]] {
+; CHECK-DL-NEXT:  entry:
+; CHECK-DL-NEXT:    [[DEC:%.*]] = add nsw i32 [[A]], -1
+; CHECK-DL-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[A]], 0
+; CHECK-DL-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
+; CHECK-DL:       if.then:
+; CHECK-DL-NEXT:    [[CALL:%.*]] = call double @recursion_select_and_phi(i32 [[DEC]], double [[B]]) #[[ATTR5:[0-9]+]]
+; CHECK-DL-NEXT:    br label [[IF_END]]
+; CHECK-DL:       if.end:
+; CHECK-DL-NEXT:    [[PHI:%.*]] = phi double [ [[B]], [[IF_THEN]] ], [ [[B]], [[ENTRY:%.*]] ]
+; CHECK-DL-NEXT:    ret double [[B]]
 ;
 entry:
   %dec = add nsw i32 %a, -1
@@ -834,10 +660,16 @@ if.end:                                           ; preds = %if.then, %entry
 define ptr @bitcast(ptr %b) #0 {
 ; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
 ; CHECK-LABEL: define {{[^@]+}}@bitcast
-; CHECK-SAME: (ptr nofree nonnull readnone returned "no-capture-maybe-returned" [[B:%.*]]) #[[ATTR0]] {
+; CHECK-SAME: (ptr nofree readnone returned "no-capture-maybe-returned" [[B:%.*]]) #[[ATTR0]] {
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    ret ptr [[B]]
 ;
+; CHECK-DL: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
+; CHECK-DL-LABEL: define {{[^@]+}}@bitcast
+; CHECK-DL-SAME: (ptr nofree nonnull readnone returned "no-capture-maybe-returned" [[B:%.*]]) #[[ATTR0]] {
+; CHECK-DL-NEXT:  entry:
+; CHECK-DL-NEXT:    ret ptr [[B]]
+;
 entry:
   ret ptr %b
 }
@@ -855,14 +687,26 @@ entry:
 define ptr @bitcasts_select_and_phi(ptr %b) #0 {
 ; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
 ; CHECK-LABEL: define {{[^@]+}}@bitcasts_select_and_phi
-; CHECK-SAME: (ptr nofree nonnull readnone returned "no-capture-maybe-returned" [[B:%.*]]) #[[ATTR0]] {
+; CHECK-SAME: (ptr nofree readnone returned [[B:%.*]]) #[[ATTR0]] {
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    br label [[IF_END:%.*]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[B]], null
+; CHECK-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
 ; CHECK:       if.then:
-; CHECK-NEXT:    unreachable
+; CHECK-NEXT:    br label [[IF_END]]
 ; CHECK:       if.end:
+; CHECK-NEXT:    [[PHI:%.*]] = phi ptr [ [[B]], [[IF_THEN]] ], [ [[B]], [[ENTRY:%.*]] ]
 ; CHECK-NEXT:    ret ptr [[B]]
 ;
+; CHECK-DL: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
+; CHECK-DL-LABEL: define {{[^@]+}}@bitcasts_select_and_phi
+; CHECK-DL-SAME: (ptr nofree nonnull readnone returned "no-capture-maybe-returned" [[B:%.*]]) #[[ATTR0]] {
+; CHECK-DL-NEXT:  entry:
+; CHECK-DL-NEXT:    br label [[IF_END:%.*]]
+; CHECK-DL:       if.then:
+; CHECK-DL-NEXT:    unreachable
+; CHECK-DL:       if.end:
+; CHECK-DL-NEXT:    ret ptr [[B]]
+;
 entry:
   %cmp = icmp eq ptr %b, null
   br i1 %cmp, label %if.then, label %if.end
@@ -891,18 +735,33 @@ if.end:                                           ; preds = %if.then, %entry
 define ptr @ret_arg_arg_undef(ptr %b) #0 {
 ; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
 ; CHECK-LABEL: define {{[^@]+}}@ret_arg_arg_undef
-; CHECK-SAME: (ptr nocapture nofree nonnull readnone [[B:%.*]]) #[[ATTR0]] {
+; CHECK-SAME: (ptr nofree readnone returned [[B:%.*]]) #[[ATTR0]] {
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    br label [[IF_END:%.*]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[B]], null
+; CHECK-NEXT:    br i1 [[CMP]], label [[RET_ARG0:%.*]], label [[IF_END:%.*]]
 ; CHECK:       ret_arg0:
-; CHECK-NEXT:    unreachable
+; CHECK-NEXT:    ret ptr [[B]]
 ; CHECK:       if.end:
-; CHECK-NEXT:    br label [[RET_UNDEF:%.*]]
+; CHECK-NEXT:    br i1 [[CMP]], label [[RET_ARG1:%.*]], label [[RET_UNDEF:%.*]]
 ; CHECK:       ret_arg1:
-; CHECK-NEXT:    unreachable
+; CHECK-NEXT:    ret ptr [[B]]
 ; CHECK:       ret_undef:
 ; CHECK-NEXT:    ret ptr undef
 ;
+; CHECK-DL: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
+; CHECK-DL-LABEL: define {{[^@]+}}@ret_arg_arg_undef
+; CHECK-DL-SAME: (ptr nocapture nofree nonnull readnone [[B:%.*]]) #[[ATTR0]] {
+; CHECK-DL-NEXT:  entry:
+; CHECK-DL-NEXT:    br label [[IF_END:%.*]]
+; CHECK-DL:       ret_arg0:
+; CHECK-DL-NEXT:    unreachable
+; CHECK-DL:       if.end:
+; CHECK-DL-NEXT:    br label [[RET_UNDEF:%.*]]
+; CHECK-DL:       ret_arg1:
+; CHECK-DL-NEXT:    unreachable
+; CHECK-DL:       ret_undef:
+; CHECK-DL-NEXT:    ret ptr undef
+;
 entry:
   %cmp = icmp eq ptr %b, null
   br i1 %cmp, label %ret_arg0, label %if.end
@@ -934,18 +793,33 @@ ret_undef:
 define ptr @ret_undef_arg_arg(ptr %b) #0 {
 ; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
 ; CHECK-LABEL: define {{[^@]+}}@ret_undef_arg_arg
-; CHECK-SAME: (ptr nofree nonnull readnone returned "no-capture-maybe-returned" [[B:%.*]]) #[[ATTR0]] {
+; CHECK-SAME: (ptr nofree readnone returned [[B:%.*]]) #[[ATTR0]] {
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    br label [[IF_END:%.*]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[B]], null
+; CHECK-NEXT:    br i1 [[CMP]], label [[RET_UNDEF:%.*]], label [[IF_END:%.*]]
 ; CHECK:       ret_undef:
-; CHECK-NEXT:    unreachable
+; CHECK-NEXT:    ret ptr undef
 ; CHECK:       if.end:
-; CHECK-NEXT:    br label [[RET_ARG1:%.*]]
+; CHECK-NEXT:    br i1 [[CMP]], label [[RET_ARG0:%.*]], label [[RET_ARG1:%.*]]
 ; CHECK:       ret_arg0:
-; CHECK-NEXT:    unreachable
+; CHECK-NEXT:    ret ptr [[B]]
 ; CHECK:       ret_arg1:
 ; CHECK-NEXT:    ret ptr [[B]]
 ;
+; CHECK-DL: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
+; CHECK-DL-LABEL: define {{[^@]+}}@ret_undef_arg_arg
+; CHECK-DL-SAME: (ptr nofree nonnull readnone returned "no-capture-maybe-returned" [[B:%.*]]) #[[ATTR0]] {
+; CHECK-DL-NEXT:  entry:
+; CHECK-DL-NEXT:    br label [[IF_END:%.*]]
+; CHECK-DL:       ret_undef:
+; CHECK-DL-NEXT:    unreachable
+; CHECK-DL:       if.end:
+; CHECK-DL-NEXT:    br label [[RET_ARG1:%.*]]
+; CHECK-DL:       ret_arg0:
+; CHECK-DL-NEXT:    unreachable
+; CHECK-DL:       ret_arg1:
+; CHECK-DL-NEXT:    ret ptr [[B]]
+;
 entry:
   %cmp = icmp eq ptr %b, null
   br i1 %cmp, label %ret_undef, label %if.end
@@ -977,18 +851,33 @@ ret_arg1:
 define ptr @ret_undef_arg_undef(ptr %b) #0 {
 ; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
 ; CHECK-LABEL: define {{[^@]+}}@ret_undef_arg_undef
-; CHECK-SAME: (ptr nocapture nofree nonnull readnone [[B:%.*]]) #[[ATTR0]] {
+; CHECK-SAME: (ptr nofree readnone returned [[B:%.*]]) #[[ATTR0]] {
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    br label [[IF_END:%.*]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[B]], null
+; CHECK-NEXT:    br i1 [[CMP]], label [[RET_UNDEF0:%.*]], label [[IF_END:%.*]]
 ; CHECK:       ret_undef0:
-; CHECK-NEXT:    unreachable
+; CHECK-NEXT:    ret ptr undef
 ; CHECK:       if.end:
-; CHECK-NEXT:    br label [[RET_UNDEF1:%.*]]
+; CHECK-NEXT:    br i1 [[CMP]], label [[RET_ARG:%.*]], label [[RET_UNDEF1:%.*]]
 ; CHECK:       ret_arg:
-; CHECK-NEXT:    unreachable
+; CHECK-NEXT:    ret ptr [[B]]
 ; CHECK:       ret_undef1:
 ; CHECK-NEXT:    ret ptr undef
 ;
+; CHECK-DL: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
+; CHECK-DL-LABEL: define {{[^@]+}}@ret_undef_arg_undef
+; CHECK-DL-SAME: (ptr nocapture nofree nonnull readnone [[B:%.*]]) #[[ATTR0]] {
+; CHECK-DL-NEXT:  entry:
+; CHECK-DL-NEXT:    br label [[IF_END:%.*]]
+; CHECK-DL:       ret_undef0:
+; CHECK-DL-NEXT:    unreachable
+; CHECK-DL:       if.end:
+; CHECK-DL-NEXT:    br label [[RET_UNDEF1:%.*]]
+; CHECK-DL:       ret_arg:
+; CHECK-DL-NEXT:    unreachable
+; CHECK-DL:       ret_undef1:
+; CHECK-DL-NEXT:    ret ptr undef
+;
 entry:
   %cmp = icmp eq ptr %b, null
   br i1 %cmp, label %ret_undef0, label %if.end
@@ -1018,28 +907,30 @@ ret_undef1:
 ;
 declare ptr @unknown(ptr)
 
+
 define ptr @ret_arg_or_unknown(ptr %b) #0 {
-; TUNIT: Function Attrs: noinline nounwind uwtable
-; TUNIT-LABEL: define {{[^@]+}}@ret_arg_or_unknown
-; TUNIT-SAME: (ptr nonnull [[B:%.*]]) #[[ATTR5]] {
-; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    br label [[RET_UNKNOWN:%.*]]
-; TUNIT:       ret_arg:
-; TUNIT-NEXT:    unreachable
-; TUNIT:       ret_unknown:
-; TUNIT-NEXT:    [[CALL:%.*]] = call nonnull ptr @unknown(ptr nonnull [[B]])
-; TUNIT-NEXT:    ret ptr [[CALL]]
-;
-; CGSCC: Function Attrs: noinline nounwind uwtable
-; CGSCC-LABEL: define {{[^@]+}}@ret_arg_or_unknown
-; CGSCC-SAME: (ptr nonnull [[B:%.*]]) #[[ATTR4]] {
-; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    br label [[RET_UNKNOWN:%.*]]
-; CGSCC:       ret_arg:
-; CGSCC-NEXT:    unreachable
-; CGSCC:       ret_unknown:
-; CGSCC-NEXT:    [[CALL:%.*]] = call nonnull ptr @unknown(ptr nonnull [[B]])
-; CGSCC-NEXT:    ret ptr [[CALL]]
+; CHECK: Function Attrs: noinline nounwind uwtable
+; CHECK-LABEL: define {{[^@]+}}@ret_arg_or_unknown
+; CHECK-SAME: (ptr [[B:%.*]]) #[[ATTR4]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[B]], null
+; CHECK-NEXT:    br i1 [[CMP]], label [[RET_ARG:%.*]], label [[RET_UNKNOWN:%.*]]
+; CHECK:       ret_arg:
+; CHECK-NEXT:    ret ptr [[B]]
+; CHECK:       ret_unknown:
+; CHECK-NEXT:    [[CALL:%.*]] = call ptr @unknown(ptr nonnull [[B]])
+; CHECK-NEXT:    ret ptr [[CALL]]
+;
+; CHECK-DL: Function Attrs: noinline nounwind uwtable
+; CHECK-DL-LABEL: define {{[^@]+}}@ret_arg_or_unknown
+; CHECK-DL-SAME: (ptr nonnull [[B:%.*]]) #[[ATTR4]] {
+; CHECK-DL-NEXT:  entry:
+; CHECK-DL-NEXT:    br label [[RET_UNKNOWN:%.*]]
+; CHECK-DL:       ret_arg:
+; CHECK-DL-NEXT:    unreachable
+; CHECK-DL:       ret_unknown:
+; CHECK-DL-NEXT:    [[CALL:%.*]] = call nonnull ptr @unknown(ptr nonnull [[B]])
+; CHECK-DL-NEXT:    ret ptr [[CALL]]
 ;
 entry:
   %cmp = icmp eq ptr %b, null
@@ -1054,31 +945,33 @@ ret_unknown:
 }
 
 define ptr @ret_arg_or_unknown_through_phi(ptr %b) #0 {
-; TUNIT: Function Attrs: noinline nounwind uwtable
-; TUNIT-LABEL: define {{[^@]+}}@ret_arg_or_unknown_through_phi
-; TUNIT-SAME: (ptr nonnull [[B:%.*]]) #[[ATTR5]] {
-; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    br label [[RET_UNKNOWN:%.*]]
-; TUNIT:       ret_arg:
-; TUNIT-NEXT:    unreachable
-; TUNIT:       ret_unknown:
-; TUNIT-NEXT:    [[CALL:%.*]] = call nonnull ptr @unknown(ptr nonnull [[B]])
-; TUNIT-NEXT:    br label [[R:%.*]]
-; TUNIT:       r:
-; TUNIT-NEXT:    ret ptr [[CALL]]
-;
-; CGSCC: Function Attrs: noinline nounwind uwtable
-; CGSCC-LABEL: define {{[^@]+}}@ret_arg_or_unknown_through_phi
-; CGSCC-SAME: (ptr nonnull [[B:%.*]]) #[[ATTR4]] {
-; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    br label [[RET_UNKNOWN:%.*]]
-; CGSCC:       ret_arg:
-; CGSCC-NEXT:    unreachable
-; CGSCC:       ret_unknown:
-; CGSCC-NEXT:    [[CALL:%.*]] = call nonnull ptr @unknown(ptr nonnull [[B]])
-; CGSCC-NEXT:    br label [[R:%.*]]
-; CGSCC:       r:
-; CGSCC-NEXT:    ret ptr [[CALL]]
+; CHECK: Function Attrs: noinline nounwind uwtable
+; CHECK-LABEL: define {{[^@]+}}@ret_arg_or_unknown_through_phi
+; CHECK-SAME: (ptr [[B:%.*]]) #[[ATTR4]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[B]], null
+; CHECK-NEXT:    br i1 [[CMP]], label [[RET_ARG:%.*]], label [[RET_UNKNOWN:%.*]]
+; CHECK:       ret_arg:
+; CHECK-NEXT:    br label [[R:%.*]]
+; CHECK:       ret_unknown:
+; CHECK-NEXT:    [[CALL:%.*]] = call ptr @unknown(ptr nonnull [[B]])
+; CHECK-NEXT:    br label [[R]]
+; CHECK:       r:
+; CHECK-NEXT:    [[PHI:%.*]] = phi ptr [ [[B]], [[RET_ARG]] ], [ [[CALL]], [[RET_UNKNOWN]] ]
+; CHECK-NEXT:    ret ptr [[PHI]]
+;
+; CHECK-DL: Function Attrs: noinline nounwind uwtable
+; CHECK-DL-LABEL: define {{[^@]+}}@ret_arg_or_unknown_through_phi
+; CHECK-DL-SAME: (ptr nonnull [[B:%.*]]) #[[ATTR4]] {
+; CHECK-DL-NEXT:  entry:
+; CHECK-DL-NEXT:    br label [[RET_UNKNOWN:%.*]]
+; CHECK-DL:       ret_arg:
+; CHECK-DL-NEXT:    unreachable
+; CHECK-DL:       ret_unknown:
+; CHECK-DL-NEXT:    [[CALL:%.*]] = call nonnull ptr @unknown(ptr nonnull [[B]])
+; CHECK-DL-NEXT:    br label [[R:%.*]]
+; CHECK-DL:       r:
+; CHECK-DL-NEXT:    ret ptr [[CALL]]
 ;
 entry:
   %cmp = icmp eq ptr %b, null
@@ -1096,157 +989,12 @@ r:
   ret ptr %phi
 }
 
-; TEST inconsistent IR in dead code.
-;
-define i32 @deadblockcall1(i32 %A) #0 {
-; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
-; CHECK-LABEL: define {{[^@]+}}@deadblockcall1
-; CHECK-SAME: (i32 returned [[A:%.*]]) #[[ATTR0]] {
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    ret i32 [[A]]
-; CHECK:       unreachableblock:
-; CHECK-NEXT:    unreachable
-;
-entry:
-  ret i32 %A
-unreachableblock:
-  %B = call i32 @deadblockcall1(i32 %B)
-  ret i32 %B
-}
-
-declare i32 @deadblockcall_helper(i32 returned %A);
-
-define i32 @deadblockcall2(i32 %A) #0 {
-; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
-; CHECK-LABEL: define {{[^@]+}}@deadblockcall2
-; CHECK-SAME: (i32 returned [[A:%.*]]) #[[ATTR0]] {
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    ret i32 [[A]]
-; CHECK:       unreachableblock1:
-; CHECK-NEXT:    unreachable
-; CHECK:       unreachableblock2:
-; CHECK-NEXT:    unreachable
-;
-entry:
-  ret i32 %A
-unreachableblock1:
-  %B = call i32 @deadblockcall_helper(i32 %B)
-  ret i32 %B
-unreachableblock2:
-  %C = call i32 @deadblockcall1(i32 %C)
-  ret i32 %C
-}
-
-define i32 @deadblockphi1(i32 %A) #0 {
-; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
-; CHECK-LABEL: define {{[^@]+}}@deadblockphi1
-; CHECK-SAME: (i32 returned [[A:%.*]]) #[[ATTR0]] {
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    br label [[R:%.*]]
-; CHECK:       unreachableblock1:
-; CHECK-NEXT:    unreachable
-; CHECK:       unreachableblock2:
-; CHECK-NEXT:    unreachable
-; CHECK:       r:
-; CHECK-NEXT:    ret i32 [[A]]
-;
-entry:
-  br label %r
-unreachableblock1:
-  %B = call i32 @deadblockcall_helper(i32 %B)
-  ret i32 %B
-unreachableblock2:
-  %C = call i32 @deadblockcall1(i32 %C)
-  br label %r
-r:
-  %PHI = phi i32 [%A, %entry], [%C, %unreachableblock2]
-  ret i32 %PHI
-}
-
-define i32 @deadblockphi2(i32 %A) #0 {
-; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
-; CHECK-LABEL: define {{[^@]+}}@deadblockphi2
-; CHECK-SAME: (i32 returned [[A:%.*]]) #[[ATTR0]] {
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    br label [[R:%.*]]
-; CHECK:       unreachableblock1:
-; CHECK-NEXT:    unreachable
-; CHECK:       unreachableblock2:
-; CHECK-NEXT:    unreachable
-; CHECK:       unreachableblock3:
-; CHECK-NEXT:    unreachable
-; CHECK:       r:
-; CHECK-NEXT:    ret i32 [[A]]
-;
-entry:
-  br label %r
-unreachableblock1:
-  %B = call i32 @deadblockcall_helper(i32 %B)
-  br label %unreachableblock3
-unreachableblock2:
-  %C = call i32 @deadblockcall1(i32 %C)
-  br label %unreachableblock3
-unreachableblock3:
-  %PHI1 = phi i32 [%B, %unreachableblock1], [%C, %unreachableblock2]
-  br label %r
-r:
-  %PHI2 = phi i32 [%A, %entry], [%PHI1, %unreachableblock3]
-  ret i32 %PHI2
-}
-
-declare void @noreturn() noreturn;
-
-define i32 @deadblockphi3(i32 %A, i1 %c) #0 {
-; TUNIT: Function Attrs: noinline nounwind uwtable
-; TUNIT-LABEL: define {{[^@]+}}@deadblockphi3
-; TUNIT-SAME: (i32 returned [[A:%.*]], i1 noundef [[C:%.*]]) #[[ATTR5]] {
-; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    br i1 [[C]], label [[R:%.*]], label [[UNREACHABLECALL:%.*]]
-; TUNIT:       unreachablecall:
-; TUNIT-NEXT:    call void @noreturn() #[[ATTR6:[0-9]+]]
-; TUNIT-NEXT:    unreachable
-; TUNIT:       unreachableblock2:
-; TUNIT-NEXT:    unreachable
-; TUNIT:       unreachableblock3:
-; TUNIT-NEXT:    unreachable
-; TUNIT:       r:
-; TUNIT-NEXT:    ret i32 [[A]]
-;
-; CGSCC: Function Attrs: noinline nounwind uwtable
-; CGSCC-LABEL: define {{[^@]+}}@deadblockphi3
-; CGSCC-SAME: (i32 returned [[A:%.*]], i1 noundef [[C:%.*]]) #[[ATTR4]] {
-; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    br i1 [[C]], label [[R:%.*]], label [[UNREACHABLECALL:%.*]]
-; CGSCC:       unreachablecall:
-; CGSCC-NEXT:    call void @noreturn() #[[ATTR5:[0-9]+]]
-; CGSCC-NEXT:    unreachable
-; CGSCC:       unreachableblock2:
-; CGSCC-NEXT:    unreachable
-; CGSCC:       unreachableblock3:
-; CGSCC-NEXT:    unreachable
-; CGSCC:       r:
-; CGSCC-NEXT:    ret i32 [[A]]
-;
-entry:
-  br i1 %c, label %r, label %unreachablecall
-unreachablecall:
-  call void @noreturn();
-  %B = call i32 @deadblockcall_helper(i32 0)
-  br label %unreachableblock3
-unreachableblock2:
-  %C = call i32 @deadblockcall1(i32 %C)
-  br label %unreachableblock3
-unreachableblock3:
-  %PHI1 = phi i32 [%B, %unreachablecall], [%C, %unreachableblock2]
-  br label %r
-r:
-  %PHI2 = phi i32 [%A, %entry], [%PHI1, %unreachableblock3]
-  ret i32 %PHI2
-}
-
 define weak_odr i32 @non_exact_0() {
 ; CHECK-LABEL: define {{[^@]+}}@non_exact_0() {
 ; CHECK-NEXT:    ret i32 0
+;
+; CHECK-DL-LABEL: define {{[^@]+}}@non_exact_0() {
+; CHECK-DL-NEXT:    ret i32 0
 ;
   ret i32 0
 }
@@ -1254,6 +1002,10 @@ define weak_odr i32 @non_exact_1(i32 %a) {
 ; CHECK-LABEL: define {{[^@]+}}@non_exact_1
 ; CHECK-SAME: (i32 [[A:%.*]]) {
 ; CHECK-NEXT:    ret i32 [[A]]
+;
+; CHECK-DL-LABEL: define {{[^@]+}}@non_exact_1
+; CHECK-DL-SAME: (i32 [[A:%.*]]) {
+; CHECK-DL-NEXT:    ret i32 [[A]]
 ;
   ret i32 %a
 }
@@ -1261,6 +1013,10 @@ define weak_odr i32 @non_exact_2(i32 returned %a) {
 ; CHECK-LABEL: define {{[^@]+}}@non_exact_2
 ; CHECK-SAME: (i32 returned [[A:%.*]]) {
 ; CHECK-NEXT:    ret i32 [[A]]
+;
+; CHECK-DL-LABEL: define {{[^@]+}}@non_exact_2
+; CHECK-DL-SAME: (i32 returned [[A:%.*]]) {
+; CHECK-DL-NEXT:    ret i32 [[A]]
 ;
   ret i32 %a
 }
@@ -1268,6 +1024,10 @@ define weak_odr align 16 ptr @non_exact_3(ptr align 32 returned %a) {
 ; CHECK-LABEL: define {{[^@]+}}@non_exact_3
 ; CHECK-SAME: (ptr returned align 32 [[A:%.*]]) {
 ; CHECK-NEXT:    ret ptr [[A]]
+;
+; CHECK-DL-LABEL: define {{[^@]+}}@non_exact_3
+; CHECK-DL-SAME: (ptr returned align 32 [[A:%.*]]) {
+; CHECK-DL-NEXT:    ret ptr [[A]]
 ;
   ret ptr %a
 }
@@ -1275,6 +1035,10 @@ define weak_odr align 16 ptr @non_exact_4(ptr align 32 %a) {
 ; CHECK-LABEL: define {{[^@]+}}@non_exact_4
 ; CHECK-SAME: (ptr align 32 [[A:%.*]]) {
 ; CHECK-NEXT:    ret ptr [[A]]
+;
+; CHECK-DL-LABEL: define {{[^@]+}}@non_exact_4
+; CHECK-DL-SAME: (ptr align 32 [[A:%.*]]) {
+; CHECK-DL-NEXT:    ret ptr [[A]]
 ;
   ret ptr %a
 }
@@ -1284,12 +1048,12 @@ define weak_odr align 16 ptr @non_exact_4(ptr align 32 %a) {
 ; %c2 and %c3 should be replaced but not %c0 or %c1!
 define i32 @exact(ptr align 8 %a, ptr align 8 %b) {
 ; CHECK-LABEL: define {{[^@]+}}@exact
-; CHECK-SAME: (ptr nonnull align 8 [[A:%.*]], ptr nonnull align 8 [[B:%.*]]) {
+; CHECK-SAME: (ptr align 8 [[A:%.*]], ptr align 8 [[B:%.*]]) {
 ; CHECK-NEXT:    [[C0:%.*]] = call i32 @non_exact_0()
 ; CHECK-NEXT:    [[C1:%.*]] = call i32 @non_exact_1(i32 noundef 1)
 ; CHECK-NEXT:    [[C2:%.*]] = call i32 @non_exact_2(i32 noundef 2)
-; CHECK-NEXT:    [[C3:%.*]] = call align 32 ptr @non_exact_3(ptr nonnull align 32 [[A]])
-; CHECK-NEXT:    [[C4:%.*]] = call align 16 ptr @non_exact_4(ptr nonnull align 32 [[B]])
+; CHECK-NEXT:    [[C3:%.*]] = call align 32 ptr @non_exact_3(ptr align 32 [[A]])
+; CHECK-NEXT:    [[C4:%.*]] = call align 16 ptr @non_exact_4(ptr align 32 [[B]])
 ; CHECK-NEXT:    [[C3L:%.*]] = load i32, ptr [[A]], align 32
 ; CHECK-NEXT:    [[C4L:%.*]] = load i32, ptr [[C4]], align 16
 ; CHECK-NEXT:    [[ADD1:%.*]] = add i32 [[C0]], [[C1]]
@@ -1297,6 +1061,21 @@ define i32 @exact(ptr align 8 %a, ptr align 8 %b) {
 ; CHECK-NEXT:    [[ADD3:%.*]] = add i32 [[ADD2]], [[C3L]]
 ; CHECK-NEXT:    [[ADD4:%.*]] = add i32 [[ADD3]], [[C4L]]
 ; CHECK-NEXT:    ret i32 [[ADD4]]
+;
+; CHECK-DL-LABEL: define {{[^@]+}}@exact
+; CHECK-DL-SAME: (ptr nonnull align 8 [[A:%.*]], ptr nonnull align 8 [[B:%.*]]) {
+; CHECK-DL-NEXT:    [[C0:%.*]] = call i32 @non_exact_0()
+; CHECK-DL-NEXT:    [[C1:%.*]] = call i32 @non_exact_1(i32 noundef 1)
+; CHECK-DL-NEXT:    [[C2:%.*]] = call i32 @non_exact_2(i32 noundef 2)
+; CHECK-DL-NEXT:    [[C3:%.*]] = call align 32 ptr @non_exact_3(ptr nonnull align 32 [[A]])
+; CHECK-DL-NEXT:    [[C4:%.*]] = call align 16 ptr @non_exact_4(ptr nonnull align 32 [[B]])
+; CHECK-DL-NEXT:    [[C3L:%.*]] = load i32, ptr [[A]], align 32
+; CHECK-DL-NEXT:    [[C4L:%.*]] = load i32, ptr [[C4]], align 16
+; CHECK-DL-NEXT:    [[ADD1:%.*]] = add i32 [[C0]], [[C1]]
+; CHECK-DL-NEXT:    [[ADD2:%.*]] = add i32 [[ADD1]], 2
+; CHECK-DL-NEXT:    [[ADD3:%.*]] = add i32 [[ADD2]], [[C3L]]
+; CHECK-DL-NEXT:    [[ADD4:%.*]] = add i32 [[ADD3]], [[C4L]]
+; CHECK-DL-NEXT:    ret i32 [[ADD4]]
 ;
   %c0 = call i32 @non_exact_0()
   %c1 = call i32 @non_exact_1(i32 1)
@@ -1312,82 +1091,6 @@ define i32 @exact(ptr align 8 %a, ptr align 8 %b) {
   ret i32 %add4
 }
 
- at G = external global i8
-define ptr @ret_const() #0 {
-; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
-; CHECK-LABEL: define {{[^@]+}}@ret_const
-; CHECK-SAME: () #[[ATTR0]] {
-; CHECK-NEXT:    ret ptr @G
-;
-  ret ptr @G
-}
-define ptr @use_const() #0 {
-; TUNIT: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
-; TUNIT-LABEL: define {{[^@]+}}@use_const
-; TUNIT-SAME: () #[[ATTR0]] {
-; TUNIT-NEXT:    ret ptr @G
-;
-; CGSCC: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable
-; CGSCC-LABEL: define {{[^@]+}}@use_const
-; CGSCC-SAME: () #[[ATTR3]] {
-; CGSCC-NEXT:    [[C:%.*]] = call noundef nonnull dereferenceable(1) ptr @ret_const() #[[ATTR10:[0-9]+]]
-; CGSCC-NEXT:    ret ptr [[C]]
-;
-  %c = call ptr @ret_const()
-  ret ptr %c
-}
-define ptr @dont_use_const() #0 {
-; TUNIT: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
-; TUNIT-LABEL: define {{[^@]+}}@dont_use_const
-; TUNIT-SAME: () #[[ATTR0]] {
-; TUNIT-NEXT:    ret ptr @G
-;
-; CGSCC: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable
-; CGSCC-LABEL: define {{[^@]+}}@dont_use_const
-; CGSCC-SAME: () #[[ATTR3]] {
-; CGSCC-NEXT:    [[C:%.*]] = musttail call noundef nonnull dereferenceable(1) ptr @ret_const() #[[ATTR10]]
-; CGSCC-NEXT:    ret ptr [[C]]
-;
-  %c = musttail call ptr @ret_const()
-  ret ptr %c
-}
-
-; UTC_ARGS: --disable
-;
-; Verify we do not derive constraints for @_Z3fooP1X as if it was returning `null`.
-;
-; CHEKC-NOT: noalias
-; CHECK-NOT: align 536870912
-
-%struct.Y = type { %struct.X }
-%struct.X = type { ptr }
-
- at _ZTI1X = external dso_local constant { ptr, ptr }, align 8
- at _ZTI1Y = external dso_local constant { ptr, ptr, ptr }, align 8
-
-define internal ptr @_ZN1Y3barEv(ptr %this) align 2 {
-entry:
-  ret ptr %this
-}
-
-define dso_local ptr @_Z3fooP1X(ptr %x) {
-entry:
-  %0 = icmp eq ptr %x, null
-  br i1 %0, label %dynamic_cast.null, label %dynamic_cast.notnull
-
-dynamic_cast.notnull:                             ; preds = %entry
-  %1 = call ptr @__dynamic_cast(ptr %x, ptr @_ZTI1X, ptr @_ZTI1Y, i64 0) #2
-  br label %dynamic_cast.end
-
-dynamic_cast.null:                                ; preds = %entry
-  br label %dynamic_cast.end
-
-dynamic_cast.end:                                 ; preds = %dynamic_cast.null, %dynamic_cast.notnull
-  %QQ5 = phi ptr [ %1, %dynamic_cast.notnull ], [ null, %dynamic_cast.null ]
-  %call = call ptr @_ZN1Y3barEv(ptr %QQ5)
-  ret ptr %call
-}
-
 declare dso_local ptr @__dynamic_cast(ptr, ptr, ptr, i64)
 
 ; UTC_ARGS: --enable
@@ -1396,26 +1099,37 @@ attributes #0 = { noinline nounwind uwtable }
 ;.
 ; TUNIT: attributes #[[ATTR0]] = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable }
 ; TUNIT: attributes #[[ATTR1]] = { nofree noinline nosync nounwind memory(none) uwtable }
-; TUNIT: attributes #[[ATTR2]] = { nofree noinline norecurse nosync nounwind memory(none) uwtable }
-; TUNIT: attributes #[[ATTR3]] = { nofree noinline nosync nounwind memory(argmem: read) uwtable }
-; TUNIT: attributes #[[ATTR4]] = { mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable }
-; TUNIT: attributes #[[ATTR5]] = { noinline nounwind uwtable }
-; TUNIT: attributes #[[ATTR6]] = { noreturn }
-; TUNIT: attributes #[[ATTR7:[0-9]+]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
-; TUNIT: attributes #[[ATTR8]] = { nofree nosync nounwind memory(none) }
-; TUNIT: attributes #[[ATTR9]] = { nofree nosync nounwind memory(read) }
-; TUNIT: attributes #[[ATTR10]] = { nounwind }
-; TUNIT: attributes #[[ATTR11:[0-9]+]] = { nounwind memory(none) }
+; TUNIT: attributes #[[ATTR2]] = { nofree noinline nosync nounwind memory(argmem: read) uwtable }
+; TUNIT: attributes #[[ATTR3]] = { mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable }
+; TUNIT: attributes #[[ATTR4]] = { noinline nounwind uwtable }
+; TUNIT: attributes #[[ATTR5]] = { nofree nosync nounwind memory(none) }
+; TUNIT: attributes #[[ATTR6]] = { nofree nosync nounwind memory(read) }
+; TUNIT: attributes #[[ATTR7]] = { nounwind }
+;.
+; TUNIT-DL: attributes #[[ATTR0]] = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable }
+; TUNIT-DL: attributes #[[ATTR1]] = { nofree noinline nosync nounwind memory(none) uwtable }
+; TUNIT-DL: attributes #[[ATTR2]] = { nofree noinline nosync nounwind memory(argmem: read) uwtable }
+; TUNIT-DL: attributes #[[ATTR3]] = { mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable }
+; TUNIT-DL: attributes #[[ATTR4]] = { noinline nounwind uwtable }
+; TUNIT-DL: attributes #[[ATTR5]] = { nofree nosync nounwind memory(none) }
+; TUNIT-DL: attributes #[[ATTR6]] = { nofree nosync nounwind memory(read) }
+; TUNIT-DL: attributes #[[ATTR7]] = { nounwind }
 ;.
 ; CGSCC: attributes #[[ATTR0]] = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable }
 ; CGSCC: attributes #[[ATTR1]] = { nofree noinline nosync nounwind memory(none) uwtable }
 ; CGSCC: attributes #[[ATTR2]] = { nofree noinline nosync nounwind memory(argmem: read) uwtable }
 ; CGSCC: attributes #[[ATTR3]] = { mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable }
 ; CGSCC: attributes #[[ATTR4]] = { noinline nounwind uwtable }
-; CGSCC: attributes #[[ATTR5]] = { noreturn }
-; CGSCC: attributes #[[ATTR6:[0-9]+]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
-; CGSCC: attributes #[[ATTR7]] = { nofree nosync nounwind memory(none) }
-; CGSCC: attributes #[[ATTR8]] = { nofree nosync nounwind memory(read) }
-; CGSCC: attributes #[[ATTR9]] = { nounwind }
-; CGSCC: attributes #[[ATTR10]] = { nofree nosync willreturn }
+; CGSCC: attributes #[[ATTR5]] = { nofree nosync nounwind memory(none) }
+; CGSCC: attributes #[[ATTR6]] = { nofree nosync nounwind memory(read) }
+; CGSCC: attributes #[[ATTR7]] = { nounwind }
+;.
+; CGSCC-DL: attributes #[[ATTR0]] = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable }
+; CGSCC-DL: attributes #[[ATTR1]] = { nofree noinline nosync nounwind memory(none) uwtable }
+; CGSCC-DL: attributes #[[ATTR2]] = { nofree noinline nosync nounwind memory(argmem: read) uwtable }
+; CGSCC-DL: attributes #[[ATTR3]] = { mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable }
+; CGSCC-DL: attributes #[[ATTR4]] = { noinline nounwind uwtable }
+; CGSCC-DL: attributes #[[ATTR5]] = { nofree nosync nounwind memory(none) }
+; CGSCC-DL: attributes #[[ATTR6]] = { nofree nosync nounwind memory(read) }
+; CGSCC-DL: attributes #[[ATTR7]] = { nounwind }
 ;.
diff --git a/llvm/test/Transforms/Attributor/value-simplify-dl-sentinel.ll b/llvm/test/Transforms/Attributor/value-simplify-dl-sentinel.ll
index c01c4418ffb85..244cc49ab5018 100755
--- a/llvm/test/Transforms/Attributor/value-simplify-dl-sentinel.ll
+++ b/llvm/test/Transforms/Attributor/value-simplify-dl-sentinel.ll
@@ -1,8 +1,9 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
 ; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal  -attributor-annotate-decl-cs  -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal  -attributor-annotate-decl-cs  -data-layout=z0:1-z2:neg1-z3:neg1-z5:neg1 -S < %s | FileCheck %s --check-prefixes=CHECK-DL,TUNIT-DL
 ; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal  -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal  -attributor-annotate-decl-cs  -data-layout=z0:1-z2:neg1-z3:neg1-z5:neg1 -S < %s | FileCheck %s --check-prefixes=CHECK-DL,CGSCC-DL
 
-target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-z0:1-z2:neg1-z3:neg1-z5:neg1-S128"
 declare void @f(i32)
 declare token @llvm.call.preallocated.setup(i32)
 declare ptr @llvm.call.preallocated.arg(token, i32)
@@ -13,532 +14,78 @@ declare ptr @llvm.call.preallocated.arg(token, i32)
 @ConstWeakPtr = weak constant i32 0, align 4
 @ConstWeakODRPtr = weak_odr constant i32 0, align 4
 
+; Do not touch complicated arguments (for now)
+%struct.X = type { ptr }
 ;.
 ; CHECK: @str = private unnamed_addr addrspace(4) constant [1 x i8] zeroinitializer, align 1
 ; CHECK: @ConstAS3Ptr = addrspace(3) global i32 0, align 4
 ; CHECK: @ConstPtr = constant i32 0, align 4
 ; CHECK: @ConstWeakPtr = weak constant i32 0, align 4
 ; CHECK: @ConstWeakODRPtr = weak_odr constant i32 0, align 4
-; CHECK: @S = external global %struct.X
-; CHECK: @g = internal constant { [2 x ptr] } { [2 x ptr] [ptr @f1, ptr @f2] }
-; CHECK: @x = external global i32
 ;.
-define internal ptr addrspace(3) @const_ptr_return_as3() {
-; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@const_ptr_return_as3
-; CGSCC-SAME: () #[[ATTR1:[0-9]+]] {
-; CGSCC-NEXT:    ret ptr addrspace(3) @ConstAS3Ptr
-;
-  ret ptr addrspace(3) @ConstAS3Ptr
-}
-define internal ptr @const_ptr_return() {
-; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@const_ptr_return
-; CGSCC-SAME: () #[[ATTR1]] {
-; CGSCC-NEXT:    ret ptr addrspacecast (ptr addrspace(3) @ConstAS3Ptr to ptr)
-;
-  ret ptr addrspacecast (ptr addrspace(3) @ConstAS3Ptr to ptr)
-}
-
-; Test1: Replace argument with constant
-define internal void @test1(i32 %a) {
-; TUNIT: Function Attrs: memory(readwrite, argmem: none)
-; TUNIT-LABEL: define {{[^@]+}}@test1
-; TUNIT-SAME: () #[[ATTR1:[0-9]+]] {
-; TUNIT-NEXT:    tail call void @f(i32 noundef 1)
-; TUNIT-NEXT:    ret void
-;
-; CGSCC: Function Attrs: memory(readwrite, argmem: none)
-; CGSCC-LABEL: define {{[^@]+}}@test1
-; CGSCC-SAME: () #[[ATTR2:[0-9]+]] {
-; CGSCC-NEXT:    tail call void @f(i32 noundef 1)
-; CGSCC-NEXT:    ret void
-;
-  tail call void @f(i32 %a)
-  ret void
-}
-
-define void @test1_helper() {
-; CHECK-LABEL: define {{[^@]+}}@test1_helper() {
-; CHECK-NEXT:    tail call void @test1()
-; CHECK-NEXT:    ret void
-;
-  tail call void @test1(i32 1)
-  ret void
-}
-
-; TEST 2 : Simplify return value
-define i32 @return0() {
-; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; TUNIT-LABEL: define {{[^@]+}}@return0
-; TUNIT-SAME: () #[[ATTR2:[0-9]+]] {
-; TUNIT-NEXT:    ret i32 0
-;
-; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@return0
-; CGSCC-SAME: () #[[ATTR1]] {
-; CGSCC-NEXT:    ret i32 0
-;
-  ret i32 0
-}
-
-define i32 @return1() {
-; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; TUNIT-LABEL: define {{[^@]+}}@return1
-; TUNIT-SAME: () #[[ATTR2]] {
-; TUNIT-NEXT:    ret i32 1
-;
-; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@return1
-; CGSCC-SAME: () #[[ATTR1]] {
-; CGSCC-NEXT:    ret i32 1
-;
-  ret i32 1
-}
-
-define i32 @test2_1(i1 %c) {
-; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; TUNIT-LABEL: define {{[^@]+}}@test2_1
-; TUNIT-SAME: (i1 noundef [[C:%.*]]) #[[ATTR2]] {
-; TUNIT-NEXT:    br i1 [[C]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
-; TUNIT:       if.true:
-; TUNIT-NEXT:    [[RET0:%.*]] = add i32 0, 1
-; TUNIT-NEXT:    br label [[END:%.*]]
-; TUNIT:       if.false:
-; TUNIT-NEXT:    br label [[END]]
-; TUNIT:       end:
-; TUNIT-NEXT:    [[RET:%.*]] = phi i32 [ [[RET0]], [[IF_TRUE]] ], [ 1, [[IF_FALSE]] ]
-; TUNIT-NEXT:    ret i32 1
-;
-; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@test2_1
-; CGSCC-SAME: (i1 noundef [[C:%.*]]) #[[ATTR3:[0-9]+]] {
-; CGSCC-NEXT:    br i1 [[C]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
-; CGSCC:       if.true:
-; CGSCC-NEXT:    [[CALL:%.*]] = tail call i32 @return0() #[[ATTR12:[0-9]+]]
-; CGSCC-NEXT:    [[RET0:%.*]] = add i32 [[CALL]], 1
-; CGSCC-NEXT:    br label [[END:%.*]]
-; CGSCC:       if.false:
-; CGSCC-NEXT:    [[RET1:%.*]] = tail call i32 @return1() #[[ATTR12]]
-; CGSCC-NEXT:    br label [[END]]
-; CGSCC:       end:
-; CGSCC-NEXT:    [[RET:%.*]] = phi i32 [ [[RET0]], [[IF_TRUE]] ], [ [[RET1]], [[IF_FALSE]] ]
-; CGSCC-NEXT:    ret i32 1
-;
-  br i1 %c, label %if.true, label %if.false
-if.true:
-  %call = tail call i32 @return0()
-  %ret0 = add i32 %call, 1
-  br label %end
-if.false:
-  %ret1 = tail call i32 @return1()
-  br label %end
-end:
-
-  %ret = phi i32 [ %ret0, %if.true ], [ %ret1, %if.false ]
-
-  ret i32 1
-}
-
-
-
-define i32 @test2_2(i1 %c) {
-; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; TUNIT-LABEL: define {{[^@]+}}@test2_2
-; TUNIT-SAME: (i1 [[C:%.*]]) #[[ATTR2]] {
-; TUNIT-NEXT:    ret i32 1
-;
-; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@test2_2
-; CGSCC-SAME: (i1 noundef [[C:%.*]]) #[[ATTR3]] {
-; CGSCC-NEXT:    [[RET:%.*]] = tail call noundef i32 @test2_1(i1 noundef [[C]]) #[[ATTR12]]
-; CGSCC-NEXT:    ret i32 [[RET]]
-;
-  %ret = tail call i32 @test2_1(i1 %c)
-  ret i32 %ret
-}
-
-declare void @use(i32)
-define void @test3(i1 %c) {
-; TUNIT-LABEL: define {{[^@]+}}@test3
-; TUNIT-SAME: (i1 noundef [[C:%.*]]) {
-; TUNIT-NEXT:    br i1 [[C]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
-; TUNIT:       if.true:
-; TUNIT-NEXT:    br label [[END:%.*]]
-; TUNIT:       if.false:
-; TUNIT-NEXT:    br label [[END]]
-; TUNIT:       end:
-; TUNIT-NEXT:    [[R:%.*]] = phi i32 [ 1, [[IF_TRUE]] ], [ 1, [[IF_FALSE]] ]
-; TUNIT-NEXT:    tail call void @use(i32 noundef 1)
-; TUNIT-NEXT:    ret void
-;
-; CGSCC-LABEL: define {{[^@]+}}@test3
-; CGSCC-SAME: (i1 noundef [[C:%.*]]) {
-; CGSCC-NEXT:    br i1 [[C]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
-; CGSCC:       if.true:
-; CGSCC-NEXT:    br label [[END:%.*]]
-; CGSCC:       if.false:
-; CGSCC-NEXT:    [[RET1:%.*]] = tail call i32 @return1() #[[ATTR13:[0-9]+]]
-; CGSCC-NEXT:    br label [[END]]
-; CGSCC:       end:
-; CGSCC-NEXT:    [[R:%.*]] = phi i32 [ 1, [[IF_TRUE]] ], [ [[RET1]], [[IF_FALSE]] ]
-; CGSCC-NEXT:    tail call void @use(i32 noundef [[R]])
-; CGSCC-NEXT:    ret void
-;
-  br i1 %c, label %if.true, label %if.false
-if.true:
-  br label %end
-if.false:
-  %ret1 = tail call i32 @return1()
-  br label %end
-end:
-
-  %r = phi i32 [ 1, %if.true ], [ %ret1, %if.false ]
-
-  tail call void @use(i32 %r)
-  ret void
-}
-
-define void @test-select-phi(i1 %c) {
-; CHECK-LABEL: define {{[^@]+}}@test-select-phi
-; CHECK-SAME: (i1 [[C:%.*]]) {
-; CHECK-NEXT:    tail call void @use(i32 noundef 1)
-; CHECK-NEXT:    [[SELECT_NOT_SAME:%.*]] = select i1 [[C]], i32 1, i32 0
-; CHECK-NEXT:    tail call void @use(i32 noundef [[SELECT_NOT_SAME]])
-; CHECK-NEXT:    br i1 [[C]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
-; CHECK:       if-true:
-; CHECK-NEXT:    br label [[END:%.*]]
-; CHECK:       if-false:
-; CHECK-NEXT:    br label [[END]]
-; CHECK:       end:
-; CHECK-NEXT:    [[PHI_SAME:%.*]] = phi i32 [ 1, [[IF_TRUE]] ], [ 1, [[IF_FALSE]] ]
-; CHECK-NEXT:    [[PHI_NOT_SAME:%.*]] = phi i32 [ 0, [[IF_TRUE]] ], [ 1, [[IF_FALSE]] ]
-; CHECK-NEXT:    [[PHI_SAME_PROP:%.*]] = phi i32 [ 1, [[IF_TRUE]] ], [ 1, [[IF_FALSE]] ]
-; CHECK-NEXT:    [[PHI_SAME_UNDEF:%.*]] = phi i32 [ 1, [[IF_TRUE]] ], [ undef, [[IF_FALSE]] ]
-; CHECK-NEXT:    [[SELECT_NOT_SAME_UNDEF:%.*]] = select i1 [[C]], i32 [[PHI_NOT_SAME]], i32 undef
-; CHECK-NEXT:    tail call void @use(i32 noundef 1)
-; CHECK-NEXT:    tail call void @use(i32 noundef [[PHI_NOT_SAME]])
-; CHECK-NEXT:    tail call void @use(i32 noundef 1)
-; CHECK-NEXT:    tail call void @use(i32 1)
-; CHECK-NEXT:    tail call void @use(i32 [[SELECT_NOT_SAME_UNDEF]])
-; CHECK-NEXT:    ret void
-;
-  %select-same = select i1 %c, i32 1, i32 1
-  tail call void @use(i32 %select-same)
-
-  %select-not-same = select i1 %c, i32 1, i32 0
-  tail call void @use(i32 %select-not-same)
-  br i1 %c, label %if-true, label %if-false
-if-true:
-  br label %end
-if-false:
-  br label %end
-end:
-  %phi-same = phi i32 [ 1, %if-true ], [ 1, %if-false ]
-  %phi-not-same = phi i32 [ 0, %if-true ], [ 1, %if-false ]
-  %phi-same-prop = phi i32 [ 1, %if-true ], [ %select-same, %if-false ]
-  %phi-same-undef = phi i32 [ 1, %if-true ], [ undef, %if-false ]
-  %select-not-same-undef = select i1 %c, i32 %phi-not-same, i32 undef
-
-
-  tail call void @use(i32 %phi-same)
-
-  tail call void @use(i32 %phi-not-same)
-
-  tail call void @use(i32 %phi-same-prop)
-
-  tail call void @use(i32 %phi-same-undef)
-
-  tail call void @use(i32 %select-not-same-undef)
-
-  ret void
-
-}
-
-define i32 @ipccp1(i32 %a) {
-; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; TUNIT-LABEL: define {{[^@]+}}@ipccp1
-; TUNIT-SAME: (i32 returned [[A:%.*]]) #[[ATTR2]] {
-; TUNIT-NEXT:    br i1 true, label [[T:%.*]], label [[F:%.*]]
-; TUNIT:       t:
-; TUNIT-NEXT:    ret i32 [[A]]
-; TUNIT:       f:
-; TUNIT-NEXT:    unreachable
-;
-; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@ipccp1
-; CGSCC-SAME: (i32 returned [[A:%.*]]) #[[ATTR1]] {
-; CGSCC-NEXT:    br i1 true, label [[T:%.*]], label [[F:%.*]]
-; CGSCC:       t:
-; CGSCC-NEXT:    ret i32 [[A]]
-; CGSCC:       f:
-; CGSCC-NEXT:    unreachable
-;
-  br i1 true, label %t, label %f
-t:
-  ret i32 %a
-f:
-  %r = call i32 @ipccp1(i32 5)
-  ret i32 %r
-}
-
-define internal i1 @ipccp2i(i1 %a) {
-; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@ipccp2i
-; CGSCC-SAME: () #[[ATTR1]] {
-; CGSCC-NEXT:    br label [[T:%.*]]
-; CGSCC:       t:
-; CGSCC-NEXT:    ret i1 true
-; CGSCC:       f:
-; CGSCC-NEXT:    unreachable
-;
-  br i1 %a, label %t, label %f
-t:
-  ret i1 %a
-f:
-  %r = call i1 @ipccp2i(i1 false)
-  ret i1 %r
-}
-
-define i1 @ipccp2() {
-; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; TUNIT-LABEL: define {{[^@]+}}@ipccp2
-; TUNIT-SAME: () #[[ATTR2]] {
-; TUNIT-NEXT:    ret i1 true
-;
-; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@ipccp2
-; CGSCC-SAME: () #[[ATTR3]] {
-; CGSCC-NEXT:    [[R:%.*]] = call noundef i1 @ipccp2i() #[[ATTR12]]
-; CGSCC-NEXT:    ret i1 [[R]]
-;
-  %r = call i1 @ipccp2i(i1 true)
-  ret i1 %r
-}
-
-define internal i1 @ipccp2ib(i1 %a) {
-; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@ipccp2ib
-; CGSCC-SAME: () #[[ATTR1]] {
-; CGSCC-NEXT:    br label [[T:%.*]]
-; CGSCC:       t:
-; CGSCC-NEXT:    ret i1 true
-; CGSCC:       f:
-; CGSCC-NEXT:    unreachable
-;
-  br i1 %a, label %t, label %f
-t:
-  ret i1 true
-f:
-  %r = call i1 @ipccp2ib(i1 false)
-  ret i1 %r
-}
-
-define i1 @ipccp2b() {
-; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; TUNIT-LABEL: define {{[^@]+}}@ipccp2b
-; TUNIT-SAME: () #[[ATTR2]] {
-; TUNIT-NEXT:    ret i1 true
-;
-; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@ipccp2b
-; CGSCC-SAME: () #[[ATTR3]] {
-; CGSCC-NEXT:    [[R:%.*]] = call noundef i1 @ipccp2ib() #[[ATTR12]]
-; CGSCC-NEXT:    ret i1 [[R]]
-;
-  %r = call i1 @ipccp2ib(i1 true)
-  ret i1 %r
-}
-
-define internal i32 @ipccp3i(i32 %a) {
-; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@ipccp3i
-; CGSCC-SAME: () #[[ATTR1]] {
-; CGSCC-NEXT:    br label [[T:%.*]]
-; CGSCC:       t:
-; CGSCC-NEXT:    ret i32 7
-; CGSCC:       f:
-; CGSCC-NEXT:    unreachable
-;
-  %c = icmp eq i32 %a, 7
-  br i1 %c, label %t, label %f
-t:
-  ret i32 %a
-f:
-  %r = call i32 @ipccp3i(i32 5)
-  ret i32 %r
-}
-
-define i32 @ipccp3() {
-; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; TUNIT-LABEL: define {{[^@]+}}@ipccp3
-; TUNIT-SAME: () #[[ATTR2]] {
-; TUNIT-NEXT:    ret i32 7
-;
-; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@ipccp3
-; CGSCC-SAME: () #[[ATTR3]] {
-; CGSCC-NEXT:    [[R:%.*]] = call noundef i32 @ipccp3i() #[[ATTR12]]
-; CGSCC-NEXT:    ret i32 [[R]]
-;
-  %r = call i32 @ipccp3i(i32 7)
-  ret i32 %r
-}
-
-define internal i32 @ipccp4ia(i1 %c) {
-; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@ipccp4ia
-; CGSCC-SAME: (i1 noundef [[C:%.*]]) #[[ATTR1]] {
-; CGSCC-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
-; CGSCC:       t:
-; CGSCC-NEXT:    ret i32 0
-; CGSCC:       f:
-; CGSCC-NEXT:    ret i32 1
-;
-  br i1 %c, label %t, label %f
-t:
-  ret i32 0
-f:
-  ret i32 1
-}
-define internal i32 @ipccp4ib(i32 %a) {
-; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@ipccp4ib
-; CGSCC-SAME: () #[[ATTR3]] {
-; CGSCC-NEXT:    br label [[T:%.*]]
-; CGSCC:       t:
-; CGSCC-NEXT:    [[R:%.*]] = call noundef i32 @ipccp4ia(i1 noundef true) #[[ATTR12]]
-; CGSCC-NEXT:    ret i32 [[R]]
-; CGSCC:       f:
-; CGSCC-NEXT:    unreachable
-;
-  %c = icmp eq i32 %a, 7
-  br i1 %c, label %t, label %f
-t:
-  %r = call i32 @ipccp4ia(i1 %c)
-  ret i32 %r
-f:
-  ret i32 1
-}
-
-define i32 @ipccp4(i1 %c) {
-; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; TUNIT-LABEL: define {{[^@]+}}@ipccp4
-; TUNIT-SAME: (i1 noundef [[C:%.*]]) #[[ATTR2]] {
-; TUNIT-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
-; TUNIT:       t:
-; TUNIT-NEXT:    br label [[F]]
-; TUNIT:       f:
-; TUNIT-NEXT:    ret i32 0
-;
-; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@ipccp4
-; CGSCC-SAME: (i1 noundef [[C:%.*]]) #[[ATTR3]] {
-; CGSCC-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
-; CGSCC:       t:
-; CGSCC-NEXT:    br label [[F]]
-; CGSCC:       f:
-; CGSCC-NEXT:    [[R:%.*]] = call noundef i32 @ipccp4ib() #[[ATTR12]]
-; CGSCC-NEXT:    ret i32 [[R]]
-;
-  br i1 %c, label %t, label %f
-t:
-  %q = call i32 @ipccp4ia(i1 undef)
-  br label %f
-f:
-  %r = call i32 @ipccp4ib(i32 7)
-  ret i32 %r
-}
-
-; Do not touch complicated arguments (for now)
-%struct.X = type { ptr }
+; TUNIT-DL: @str = private unnamed_addr addrspace(4) constant [1 x i8] zeroinitializer, align 1
+; TUNIT-DL: @ConstAS3Ptr = addrspace(3) global i32 0, align 4
+; TUNIT-DL: @ConstPtr = constant i32 0, align 4
+; TUNIT-DL: @ConstWeakPtr = weak constant i32 0, align 4
+; TUNIT-DL: @ConstWeakODRPtr = weak_odr constant i32 0, align 4
+;.
+; CGSCC-DL: @str = private unnamed_addr addrspace(4) constant [1 x i8] zeroinitializer, align 1
+; CGSCC-DL: @ConstAS3Ptr = addrspace(3) global i32 0, align 4
+; CGSCC-DL: @ConstPtr = constant i32 0, align 4
+; CGSCC-DL: @ConstWeakPtr = weak constant i32 0, align 4
+; CGSCC-DL: @ConstWeakODRPtr = weak_odr constant i32 0, align 4
+;.
 define internal ptr @test_inalloca(ptr inalloca(i32) %a) {
-; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; TUNIT-LABEL: define {{[^@]+}}@test_inalloca
-; TUNIT-SAME: (ptr noalias nofree nonnull returned writeonly inalloca(i32) dereferenceable(4) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR2]] {
-; TUNIT-NEXT:    ret ptr [[A]]
-;
-; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
 ; CGSCC-LABEL: define {{[^@]+}}@test_inalloca
-; CGSCC-SAME: (ptr noalias nofree noundef nonnull returned writeonly inalloca(i32) dereferenceable(4) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR1]] {
+; CGSCC-SAME: (ptr inalloca(i32) [[A:%.*]]) {
 ; CGSCC-NEXT:    ret ptr [[A]]
 ;
-  ret ptr %a
-}
-define ptr @complicated_args_inalloca(ptr %arg) {
-; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; TUNIT-LABEL: define {{[^@]+}}@complicated_args_inalloca
-; TUNIT-SAME: (ptr nofree nonnull readnone "no-capture-maybe-returned" [[ARG:%.*]]) #[[ATTR2]] {
-; TUNIT-NEXT:    [[CALL:%.*]] = call nonnull dereferenceable(4) ptr @test_inalloca(ptr noalias nofree nonnull writeonly inalloca(i32) "no-capture-maybe-returned" [[ARG]]) #[[ATTR9:[0-9]+]]
-; TUNIT-NEXT:    ret ptr [[CALL]]
-;
-; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@complicated_args_inalloca
-; CGSCC-SAME: (ptr nofree noundef nonnull readnone dereferenceable(4) [[ARG:%.*]]) #[[ATTR3]] {
-; CGSCC-NEXT:    [[CALL:%.*]] = call noalias noundef nonnull dereferenceable(4) ptr @test_inalloca(ptr noalias nofree noundef nonnull writeonly inalloca(i32) dereferenceable(4) [[ARG]]) #[[ATTR12]]
-; CGSCC-NEXT:    ret ptr [[CALL]]
-;
-  %call = call ptr @test_inalloca(ptr inalloca(i32) %arg)
-  ret ptr %call
-}
-
-define internal ptr @test_preallocated(ptr preallocated(i32) %a) {
-; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; TUNIT-LABEL: define {{[^@]+}}@test_preallocated
-; TUNIT-SAME: (ptr noalias nofree noundef nonnull returned writeonly preallocated(i32) align 4294967296 dereferenceable(4) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR2]] {
-; TUNIT-NEXT:    ret ptr [[A]]
-;
-; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@test_preallocated
-; CGSCC-SAME: (ptr noalias nofree noundef nonnull returned writeonly preallocated(i32) align 4294967296 dereferenceable(4) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR1]] {
-; CGSCC-NEXT:    ret ptr [[A]]
+; CGSCC-DL-LABEL: define {{[^@]+}}@test_inalloca
+; CGSCC-DL-SAME: (ptr inalloca(i32) [[A:%.*]]) {
+; CGSCC-DL-NEXT:    ret ptr [[A]]
 ;
   ret ptr %a
 }
-define ptr @complicated_args_preallocated() {
-; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn
-; TUNIT-LABEL: define {{[^@]+}}@complicated_args_preallocated
-; TUNIT-SAME: () #[[ATTR3:[0-9]+]] {
-; TUNIT-NEXT:    [[C:%.*]] = call token @llvm.call.preallocated.setup(i32 noundef 1) #[[ATTR10:[0-9]+]]
-; TUNIT-NEXT:    [[CALL:%.*]] = call noundef nonnull align 4294967296 dereferenceable(4) ptr @test_preallocated(ptr nofree noundef writeonly preallocated(i32) align 4294967296 null) #[[ATTR9]] [ "preallocated"(token [[C]]) ]
-; TUNIT-NEXT:    ret ptr [[CALL]]
-;
-; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn
-; CGSCC-LABEL: define {{[^@]+}}@complicated_args_preallocated
-; CGSCC-SAME: () #[[ATTR4:[0-9]+]] {
-; CGSCC-NEXT:    [[C:%.*]] = call token @llvm.call.preallocated.setup(i32 noundef 1) #[[ATTR13]]
-; CGSCC-NEXT:    [[CALL:%.*]] = call ptr @test_preallocated(ptr nofree noundef writeonly preallocated(i32) align 4294967296 null) #[[ATTR14:[0-9]+]] [ "preallocated"(token [[C]]) ]
-; CGSCC-NEXT:    unreachable
-;
-  %c = call token @llvm.call.preallocated.setup(i32 1)
-  %call = call ptr @test_preallocated(ptr preallocated(i32) null) ["preallocated"(token %c)]
-  ret ptr %call
-}
 
 define internal void @test_sret(ptr sret(%struct.X) %a, ptr %b) {
+; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
+; CHECK-LABEL: define {{[^@]+}}@test_sret
+; CHECK-SAME: (ptr noalias nofree noundef writeonly sret([[STRUCT_X:%.*]]) align 4294967296 dereferenceable_or_null(8) [[A:%.*]], ptr nocapture nofree noundef nonnull writeonly align 8 dereferenceable(8) [[B:%.*]]) #[[ATTR1:[0-9]+]] {
+; CHECK-NEXT:    store ptr [[A]], ptr [[B]], align 8
+; CHECK-NEXT:    ret void
 ;
-; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
-; CGSCC-LABEL: define {{[^@]+}}@test_sret
-; CGSCC-SAME: (ptr noalias nofree noundef nonnull writeonly sret([[STRUCT_X:%.*]]) align 4294967296 dereferenceable(8) [[A:%.*]], ptr nocapture nofree noundef nonnull writeonly align 8 dereferenceable(8) [[B:%.*]]) #[[ATTR5:[0-9]+]] {
-; CGSCC-NEXT:    store ptr [[A]], ptr [[B]], align 8
-; CGSCC-NEXT:    ret void
+; CGSCC-DL: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
+; CGSCC-DL-LABEL: define {{[^@]+}}@test_sret
+; CGSCC-DL-SAME: (ptr noalias nofree noundef nonnull writeonly sret([[STRUCT_X:%.*]]) align 4294967296 dereferenceable(8) [[A:%.*]], ptr nocapture nofree noundef nonnull writeonly align 8 dereferenceable(8) [[B:%.*]]) #[[ATTR1:[0-9]+]] {
+; CGSCC-DL-NEXT:    store ptr [[A]], ptr [[B]], align 8
+; CGSCC-DL-NEXT:    ret void
 ;
   store ptr %a, ptr %b
   ret void
 }
 ; FIXME: Alignment and dereferenceability are not propagated to the argument
 define void @complicated_args_sret(ptr %b) {
-;
-;
 ; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
 ; TUNIT-LABEL: define {{[^@]+}}@complicated_args_sret
-; TUNIT-SAME: (ptr nocapture nofree nonnull writeonly [[B:%.*]]) #[[ATTR4:[0-9]+]] {
-; TUNIT-NEXT:    unreachable
+; TUNIT-SAME: (ptr nocapture nofree writeonly [[B:%.*]]) #[[ATTR1]] {
+; TUNIT-NEXT:    call void @test_sret(ptr nofree noundef writeonly sret([[STRUCT_X:%.*]]) align 4294967296 null, ptr nocapture nofree noundef writeonly align 8 [[B]]) #[[ATTR3:[0-9]+]]
+; TUNIT-NEXT:    ret void
+;
+; TUNIT-DL: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
+; TUNIT-DL-LABEL: define {{[^@]+}}@complicated_args_sret
+; TUNIT-DL-SAME: (ptr nocapture nofree nonnull writeonly [[B:%.*]]) #[[ATTR1:[0-9]+]] {
+; TUNIT-DL-NEXT:    unreachable
 ;
 ; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(argmem: write)
 ; CGSCC-LABEL: define {{[^@]+}}@complicated_args_sret
-; CGSCC-SAME: (ptr nocapture nofree noundef nonnull writeonly align 8 dereferenceable(8) [[B:%.*]]) #[[ATTR6:[0-9]+]] {
-; CGSCC-NEXT:    unreachable
+; CGSCC-SAME: (ptr nocapture nofree noundef nonnull writeonly align 8 dereferenceable(8) [[B:%.*]]) #[[ATTR2:[0-9]+]] {
+; CGSCC-NEXT:    call void @test_sret(ptr nofree noundef writeonly sret([[STRUCT_X:%.*]]) align 4294967296 dereferenceable_or_null(8) null, ptr nocapture nofree noundef nonnull writeonly align 8 dereferenceable(8) [[B]]) #[[ATTR5:[0-9]+]]
+; CGSCC-NEXT:    ret void
+;
+; CGSCC-DL: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(argmem: write)
+; CGSCC-DL-LABEL: define {{[^@]+}}@complicated_args_sret
+; CGSCC-DL-SAME: (ptr nocapture nofree noundef nonnull writeonly align 8 dereferenceable(8) [[B:%.*]]) #[[ATTR2:[0-9]+]] {
+; CGSCC-DL-NEXT:    unreachable
 ;
   call void @test_sret(ptr sret(%struct.X) null, ptr %b)
   ret void
@@ -547,1186 +94,65 @@ define void @complicated_args_sret(ptr %b) {
 define internal ptr @test_nest(ptr nest %a) {
 ; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
 ; CGSCC-LABEL: define {{[^@]+}}@test_nest
-; CGSCC-SAME: (ptr nest noalias nocapture nofree nonnull readnone align 4294967296 [[A:%.*]]) #[[ATTR1]] {
-; CGSCC-NEXT:    unreachable
+; CGSCC-SAME: (ptr nest noalias nocapture nofree readnone align 4294967296 [[A:%.*]]) #[[ATTR3:[0-9]+]] {
+; CGSCC-NEXT:    ret ptr null
+;
+; CGSCC-DL: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CGSCC-DL-LABEL: define {{[^@]+}}@test_nest
+; CGSCC-DL-SAME: (ptr nest noalias nocapture nofree nonnull readnone align 4294967296 [[A:%.*]]) #[[ATTR3:[0-9]+]] {
+; CGSCC-DL-NEXT:    unreachable
 ;
   ret ptr %a
 }
 define ptr @complicated_args_nest() {
 ; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
 ; TUNIT-LABEL: define {{[^@]+}}@complicated_args_nest
-; TUNIT-SAME: () #[[ATTR2]] {
-; TUNIT-NEXT:    unreachable
+; TUNIT-SAME: () #[[ATTR2:[0-9]+]] {
+; TUNIT-NEXT:    ret ptr null
+;
+; TUNIT-DL: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; TUNIT-DL-LABEL: define {{[^@]+}}@complicated_args_nest
+; TUNIT-DL-SAME: () #[[ATTR2:[0-9]+]] {
+; TUNIT-DL-NEXT:    unreachable
 ;
 ; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
 ; CGSCC-LABEL: define {{[^@]+}}@complicated_args_nest
-; CGSCC-SAME: () #[[ATTR3]] {
-; CGSCC-NEXT:    unreachable
+; CGSCC-SAME: () #[[ATTR4:[0-9]+]] {
+; CGSCC-NEXT:    [[CALL:%.*]] = call noalias noundef align 4294967296 ptr @test_nest(ptr nofree noundef readnone align 4294967296 null) #[[ATTR6:[0-9]+]]
+; CGSCC-NEXT:    ret ptr [[CALL]]
+;
+; CGSCC-DL: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
+; CGSCC-DL-LABEL: define {{[^@]+}}@complicated_args_nest
+; CGSCC-DL-SAME: () #[[ATTR4:[0-9]+]] {
+; CGSCC-DL-NEXT:    unreachable
 ;
   %call = call ptr @test_nest(ptr null)
   ret ptr %call
 }
 
- at S = external global %struct.X
-define internal void @test_byval(ptr byval(%struct.X) %a) {
-; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
-; TUNIT-LABEL: define {{[^@]+}}@test_byval
-; TUNIT-SAME: (ptr [[TMP0:%.*]]) #[[ATTR4]] {
-; TUNIT-NEXT:    [[A_PRIV:%.*]] = alloca [[STRUCT_X:%.*]], align 8
-; TUNIT-NEXT:    store ptr [[TMP0]], ptr [[A_PRIV]], align 8
-; TUNIT-NEXT:    store ptr null, ptr [[A_PRIV]], align 8
-; TUNIT-NEXT:    ret void
-;
-; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
-; CGSCC-LABEL: define {{[^@]+}}@test_byval
-; CGSCC-SAME: (ptr nofree nonnull [[TMP0:%.*]]) #[[ATTR5]] {
-; CGSCC-NEXT:    [[A_PRIV:%.*]] = alloca [[STRUCT_X:%.*]], align 8
-; CGSCC-NEXT:    store ptr [[TMP0]], ptr [[A_PRIV]], align 8
-; CGSCC-NEXT:    store ptr null, ptr [[A_PRIV]], align 8
-; CGSCC-NEXT:    ret void
-;
-  store ptr null, ptr %a
-  ret void
-}
-define void @complicated_args_byval() {
-; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write)
-; TUNIT-LABEL: define {{[^@]+}}@complicated_args_byval
-; TUNIT-SAME: () #[[ATTR5:[0-9]+]] {
-; TUNIT-NEXT:    [[TMP1:%.*]] = load ptr, ptr @S, align 8
-; TUNIT-NEXT:    call void @test_byval(ptr [[TMP1]]) #[[ATTR11:[0-9]+]]
-; TUNIT-NEXT:    ret void
-;
-; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn
-; CGSCC-LABEL: define {{[^@]+}}@complicated_args_byval
-; CGSCC-SAME: () #[[ATTR4]] {
-; CGSCC-NEXT:    [[TMP1:%.*]] = load ptr, ptr @S, align 8
-; CGSCC-NEXT:    call void @test_byval(ptr nofree nonnull writeonly [[TMP1]]) #[[ATTR15:[0-9]+]]
-; CGSCC-NEXT:    ret void
-;
-  call void @test_byval(ptr byval(%struct.X) @S)
-  ret void
-}
-
-declare void @sync()
-; Make sure we *do not* load @S here!
-define internal ptr @test_byval2(ptr byval(%struct.X) %a) {
-; TUNIT-LABEL: define {{[^@]+}}@test_byval2
-; TUNIT-SAME: (ptr [[TMP0:%.*]]) {
-; TUNIT-NEXT:    [[A_PRIV:%.*]] = alloca [[STRUCT_X:%.*]], align 8
-; TUNIT-NEXT:    store ptr [[TMP0]], ptr [[A_PRIV]], align 8
-; TUNIT-NEXT:    call void @sync()
-; TUNIT-NEXT:    [[L:%.*]] = load ptr, ptr [[A_PRIV]], align 8
-; TUNIT-NEXT:    ret ptr [[L]]
-;
-; CGSCC-LABEL: define {{[^@]+}}@test_byval2
-; CGSCC-SAME: (ptr nonnull [[TMP0:%.*]]) {
-; CGSCC-NEXT:    [[A_PRIV:%.*]] = alloca [[STRUCT_X:%.*]], align 8
-; CGSCC-NEXT:    store ptr [[TMP0]], ptr [[A_PRIV]], align 8
-; CGSCC-NEXT:    call void @sync()
-; CGSCC-NEXT:    [[L:%.*]] = load ptr, ptr [[A_PRIV]], align 8
-; CGSCC-NEXT:    ret ptr [[L]]
-;
-  call void @sync()
-  %l = load ptr, ptr %a
-  ret ptr %l
-}
-define ptr @complicated_args_byval2() {
-;
-; TUNIT-LABEL: define {{[^@]+}}@complicated_args_byval2() {
-; TUNIT-NEXT:    [[TMP1:%.*]] = load ptr, ptr @S, align 8
-; TUNIT-NEXT:    [[C:%.*]] = call nonnull ptr @test_byval2(ptr [[TMP1]])
-; TUNIT-NEXT:    ret ptr [[C]]
-;
-; CGSCC-LABEL: define {{[^@]+}}@complicated_args_byval2() {
-; CGSCC-NEXT:    [[TMP1:%.*]] = load ptr, ptr @S, align 8
-; CGSCC-NEXT:    [[C:%.*]] = call nonnull ptr @test_byval2(ptr nonnull [[TMP1]])
-; CGSCC-NEXT:    ret ptr [[C]]
-;
-  %c = call ptr @test_byval2(ptr byval(%struct.X) @S)
-  ret ptr %c
-}
-
-define void @fixpoint_changed(ptr %p) {
-; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
-; TUNIT-LABEL: define {{[^@]+}}@fixpoint_changed
-; TUNIT-SAME: (ptr nocapture nofree nonnull writeonly [[P:%.*]]) #[[ATTR4]] {
-; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    br label [[FOR_COND:%.*]]
-; TUNIT:       for.cond:
-; TUNIT-NEXT:    [[J_0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[SW_EPILOG:%.*]] ]
-; TUNIT-NEXT:    [[CMP:%.*]] = icmp slt i32 [[J_0]], 30
-; TUNIT-NEXT:    br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]]
-; TUNIT:       for.body:
-; TUNIT-NEXT:    switch i32 [[J_0]], label [[SW_EPILOG]] [
-; TUNIT-NEXT:      i32 1, label [[SW_BB:%.*]]
-; TUNIT-NEXT:    ]
-; TUNIT:       sw.bb:
-; TUNIT-NEXT:    br label [[SW_EPILOG]]
-; TUNIT:       sw.epilog:
-; TUNIT-NEXT:    [[X_0:%.*]] = phi i32 [ 255, [[FOR_BODY]] ], [ 253, [[SW_BB]] ]
-; TUNIT-NEXT:    store i32 [[X_0]], ptr [[P]], align 4
-; TUNIT-NEXT:    [[INC]] = add nsw i32 [[J_0]], 1
-; TUNIT-NEXT:    br label [[FOR_COND]]
-; TUNIT:       for.end:
-; TUNIT-NEXT:    ret void
-;
-; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
-; CGSCC-LABEL: define {{[^@]+}}@fixpoint_changed
-; CGSCC-SAME: (ptr nocapture nofree nonnull writeonly [[P:%.*]]) #[[ATTR5]] {
-; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    br label [[FOR_COND:%.*]]
-; CGSCC:       for.cond:
-; CGSCC-NEXT:    [[J_0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[SW_EPILOG:%.*]] ]
-; CGSCC-NEXT:    [[CMP:%.*]] = icmp slt i32 [[J_0]], 30
-; CGSCC-NEXT:    br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]]
-; CGSCC:       for.body:
-; CGSCC-NEXT:    switch i32 [[J_0]], label [[SW_EPILOG]] [
-; CGSCC-NEXT:      i32 1, label [[SW_BB:%.*]]
-; CGSCC-NEXT:    ]
-; CGSCC:       sw.bb:
-; CGSCC-NEXT:    br label [[SW_EPILOG]]
-; CGSCC:       sw.epilog:
-; CGSCC-NEXT:    [[X_0:%.*]] = phi i32 [ 255, [[FOR_BODY]] ], [ 253, [[SW_BB]] ]
-; CGSCC-NEXT:    store i32 [[X_0]], ptr [[P]], align 4
-; CGSCC-NEXT:    [[INC]] = add nsw i32 [[J_0]], 1
-; CGSCC-NEXT:    br label [[FOR_COND]]
-; CGSCC:       for.end:
-; CGSCC-NEXT:    ret void
-;
-entry:
-  br label %for.cond
-
-for.cond:
-  %j.0 = phi i32 [ 0, %entry ], [ %inc, %sw.epilog ]
-  %cmp = icmp slt i32 %j.0, 30
-  br i1 %cmp, label %for.body, label %for.end
-
-for.body:
-  switch i32 %j.0, label %sw.epilog [
-  i32 1, label %sw.bb
-  ]
-
-sw.bb:
-  br label %sw.epilog
-
-sw.epilog:
-  %x.0 = phi i32 [ 255, %for.body ], [ 253, %sw.bb ]
-  store i32 %x.0, ptr %p
-  %inc = add nsw i32 %j.0, 1
-  br label %for.cond
-
-for.end:
-  ret void
-}
-
-; Check we merge undef and a constant properly.
-define i8 @caller0() {
-; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; TUNIT-LABEL: define {{[^@]+}}@caller0
-; TUNIT-SAME: () #[[ATTR2]] {
-; TUNIT-NEXT:    ret i8 49
-;
-; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@caller0
-; CGSCC-SAME: () #[[ATTR3]] {
-; CGSCC-NEXT:    [[C:%.*]] = call noundef i8 @callee() #[[ATTR12]]
-; CGSCC-NEXT:    ret i8 [[C]]
-;
-  %c = call i8 @callee(i8 undef)
-  ret i8 %c
-}
-define i8 @caller1() {
-; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; TUNIT-LABEL: define {{[^@]+}}@caller1
-; TUNIT-SAME: () #[[ATTR2]] {
-; TUNIT-NEXT:    ret i8 49
-;
-; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@caller1
-; CGSCC-SAME: () #[[ATTR3]] {
-; CGSCC-NEXT:    [[C:%.*]] = call noundef i8 @callee() #[[ATTR12]]
-; CGSCC-NEXT:    ret i8 [[C]]
-;
-  %c = call i8 @callee(i8 undef)
-  ret i8 %c
-}
-define i8 @caller2() {
-; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; TUNIT-LABEL: define {{[^@]+}}@caller2
-; TUNIT-SAME: () #[[ATTR2]] {
-; TUNIT-NEXT:    ret i8 49
-;
-; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@caller2
-; CGSCC-SAME: () #[[ATTR3]] {
-; CGSCC-NEXT:    [[C:%.*]] = call noundef i8 @callee() #[[ATTR12]]
-; CGSCC-NEXT:    ret i8 [[C]]
-;
-  %c = call i8 @callee(i8 undef)
-  ret i8 %c
-}
-define i8 @caller_middle() {
-; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; TUNIT-LABEL: define {{[^@]+}}@caller_middle
-; TUNIT-SAME: () #[[ATTR2]] {
-; TUNIT-NEXT:    ret i8 49
-;
-; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@caller_middle
-; CGSCC-SAME: () #[[ATTR3]] {
-; CGSCC-NEXT:    [[C:%.*]] = call noundef i8 @callee() #[[ATTR12]]
-; CGSCC-NEXT:    ret i8 [[C]]
-;
-  %c = call i8 @callee(i8 42)
-  ret i8 %c
-}
-define i8 @caller3() {
-; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; TUNIT-LABEL: define {{[^@]+}}@caller3
-; TUNIT-SAME: () #[[ATTR2]] {
-; TUNIT-NEXT:    ret i8 49
-;
-; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@caller3
-; CGSCC-SAME: () #[[ATTR3]] {
-; CGSCC-NEXT:    [[C:%.*]] = call noundef i8 @callee() #[[ATTR12]]
-; CGSCC-NEXT:    ret i8 [[C]]
-;
-  %c = call i8 @callee(i8 undef)
-  ret i8 %c
-}
-define i8 @caller4() {
-; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; TUNIT-LABEL: define {{[^@]+}}@caller4
-; TUNIT-SAME: () #[[ATTR2]] {
-; TUNIT-NEXT:    ret i8 49
-;
-; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@caller4
-; CGSCC-SAME: () #[[ATTR3]] {
-; CGSCC-NEXT:    [[C:%.*]] = call noundef i8 @callee() #[[ATTR12]]
-; CGSCC-NEXT:    ret i8 [[C]]
-;
-  %c = call i8 @callee(i8 undef)
-  ret i8 %c
-}
-define internal i8 @callee(i8 %a) {
-; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@callee
-; CGSCC-SAME: () #[[ATTR1]] {
-; CGSCC-NEXT:    ret i8 49
-;
-  %c = add i8 %a, 7
-  ret i8 %c
-}
-
-define void @user_as3() {
-; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write)
-; TUNIT-LABEL: define {{[^@]+}}@user_as3
-; TUNIT-SAME: () #[[ATTR5]] {
-; TUNIT-NEXT:    store i32 0, ptr addrspace(3) @ConstAS3Ptr, align 4
-; TUNIT-NEXT:    ret void
-;
-; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(write)
-; CGSCC-LABEL: define {{[^@]+}}@user_as3
-; CGSCC-SAME: () #[[ATTR7:[0-9]+]] {
-; CGSCC-NEXT:    [[CALL:%.*]] = call fastcc align 4 ptr addrspace(3) @const_ptr_return_as3() #[[ATTR12]]
-; CGSCC-NEXT:    store i32 0, ptr addrspace(3) [[CALL]], align 4
-; CGSCC-NEXT:    ret void
-;
-  %call = call fastcc ptr addrspace(3) @const_ptr_return_as3()
-  store i32 0, ptr addrspace(3) %call
-  ret void
-}
-define void @user() {
-; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write)
-; TUNIT-LABEL: define {{[^@]+}}@user
-; TUNIT-SAME: () #[[ATTR5]] {
-; TUNIT-NEXT:    [[TMP1:%.*]] = addrspacecast ptr addrspacecast (ptr addrspace(3) @ConstAS3Ptr to ptr) to ptr addrspace(3)
-; TUNIT-NEXT:    store i32 0, ptr addrspace(3) [[TMP1]], align 4
-; TUNIT-NEXT:    ret void
-;
-; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(write)
-; CGSCC-LABEL: define {{[^@]+}}@user
-; CGSCC-SAME: () #[[ATTR7]] {
-; CGSCC-NEXT:    [[CALL:%.*]] = call fastcc align 4 ptr @const_ptr_return() #[[ATTR12]]
-; CGSCC-NEXT:    store i32 0, ptr [[CALL]], align 4
-; CGSCC-NEXT:    ret void
-;
-  %call = call fastcc ptr @const_ptr_return()
-  store i32 0, ptr %call
-  ret void
-}
-
-
-define i1 @test_merge_with_undef_values_ptr(i1 %c) {
-; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; TUNIT-LABEL: define {{[^@]+}}@test_merge_with_undef_values_ptr
-; TUNIT-SAME: (i1 [[C:%.*]]) #[[ATTR2]] {
-; TUNIT-NEXT:    ret i1 false
-;
-; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@test_merge_with_undef_values_ptr
-; CGSCC-SAME: (i1 [[C:%.*]]) #[[ATTR3]] {
-; CGSCC-NEXT:    [[R1:%.*]] = call i1 @undef_then_null(i1 [[C]]) #[[ATTR12]]
-; CGSCC-NEXT:    ret i1 [[R1]]
-;
-  %r1 = call i1 @undef_then_null(i1 %c, ptr undef, ptr undef)
-  ret i1 %r1
-}
-define internal i1 @undef_then_null(i1 %c, ptr %i32Aptr, ptr %i32Bptr) {
-; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@undef_then_null
-; CGSCC-SAME: (i1 [[C:%.*]]) #[[ATTR3]] {
-; CGSCC-NEXT:    [[OR:%.*]] = or i1 false, [[C]]
-; CGSCC-NEXT:    br i1 [[OR]], label [[A:%.*]], label [[B:%.*]]
-; CGSCC:       a:
-; CGSCC-NEXT:    ret i1 false
-; CGSCC:       b:
-; CGSCC-NEXT:    ret i1 false
-;
-  %cmp1 = icmp eq ptr %i32Aptr, %i32Bptr
-  %cmp2 = icmp eq i1 %cmp1, false
-  %or = or i1 %cmp2, %c
-  br i1 %or, label %a, label %b
-a:
-  %r2 = call i1 @undef_then_null(i1 false, ptr null, ptr null)
-  ret i1 %r2
-b:
-  ret i1 %cmp2
-}
-
-define i1 @test_merge_with_undef_values(i1 %c) {
-; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; TUNIT-LABEL: define {{[^@]+}}@test_merge_with_undef_values
-; TUNIT-SAME: (i1 [[C:%.*]]) #[[ATTR2]] {
-; TUNIT-NEXT:    ret i1 false
-;
-; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@test_merge_with_undef_values
-; CGSCC-SAME: (i1 [[C:%.*]]) #[[ATTR3]] {
-; CGSCC-NEXT:    [[R1:%.*]] = call i1 @undef_then_1(i1 [[C]]) #[[ATTR12]]
-; CGSCC-NEXT:    ret i1 [[R1]]
-;
-  %r1 = call i1 @undef_then_1(i1 %c, i32 undef, i32 undef)
-  ret i1 %r1
-}
-define internal i1 @undef_then_1(i1 %c, i32 %i32A, i32 %i32B) {
-;
-; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@undef_then_1
-; CGSCC-SAME: (i1 [[C:%.*]]) #[[ATTR3]] {
-; CGSCC-NEXT:    [[OR:%.*]] = or i1 false, [[C]]
-; CGSCC-NEXT:    br i1 [[OR]], label [[A:%.*]], label [[B:%.*]]
-; CGSCC:       a:
-; CGSCC-NEXT:    ret i1 false
-; CGSCC:       b:
-; CGSCC-NEXT:    ret i1 false
-;
-  %cmp1 = icmp eq i32 %i32A, %i32B
-  %cmp2 = icmp eq i1 %cmp1, false
-  %or = or i1 %cmp2, %c
-  br i1 %or, label %a, label %b
-a:
-  %r2 = call i1 @undef_then_1(i1 false, i32 1, i32 1)
-  ret i1 %r2
-b:
-  ret i1 %cmp2
-}
-
-define i32 @test_select(i32 %c) {
-; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; TUNIT-LABEL: define {{[^@]+}}@test_select
-; TUNIT-SAME: (i32 [[C:%.*]]) #[[ATTR2]] {
-; TUNIT-NEXT:    ret i32 42
-;
-; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@test_select
-; CGSCC-SAME: (i32 [[C:%.*]]) #[[ATTR3]] {
-; CGSCC-NEXT:    [[CALL:%.*]] = call noundef i32 @select() #[[ATTR12]]
-; CGSCC-NEXT:    ret i32 [[CALL]]
-;
-  %call = call i32 @select(i1 1, i32 42, i32 %c)
-  ret i32 %call
-}
-
-define internal i32 @select(i1 %a, i32 %b, i32 %c) {
-; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@select
-; CGSCC-SAME: () #[[ATTR1]] {
-; CGSCC-NEXT:    ret i32 42
-;
-  %s = select i1 %a, i32 %b, i32 %c
-  ret i32 %s
-}
-
-define i1 @icmp() {
-; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; TUNIT-LABEL: define {{[^@]+}}@icmp
-; TUNIT-SAME: () #[[ATTR2]] {
-; TUNIT-NEXT:    ret i1 true
-;
-; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@icmp
-; CGSCC-SAME: () #[[ATTR1]] {
-; CGSCC-NEXT:    ret i1 true
-;
-  %c = icmp eq ptr null, null
-  ret i1 %c
-}
-
-define void @test_callee_is_undef(ptr %fn) {
-; TUNIT-LABEL: define {{[^@]+}}@test_callee_is_undef
-; TUNIT-SAME: (ptr nocapture nofree nonnull [[FN:%.*]]) {
-; TUNIT-NEXT:    call void @unknown_calle_arg_is_undef(ptr nocapture nofree noundef nonnull [[FN]])
-; TUNIT-NEXT:    ret void
-;
-; CGSCC-LABEL: define {{[^@]+}}@test_callee_is_undef
-; CGSCC-SAME: (ptr nocapture nofree noundef nonnull [[FN:%.*]]) {
-; CGSCC-NEXT:    call void @unknown_calle_arg_is_undef(ptr nocapture nofree noundef nonnull [[FN]])
-; CGSCC-NEXT:    ret void
-;
-  call void @callee_is_undef(ptr undef)
-  call void @unknown_calle_arg_is_undef(ptr %fn, i32 undef)
-  ret void
-}
-define internal void @callee_is_undef(ptr %fn) {
-;
-; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@callee_is_undef
-; CGSCC-SAME: () #[[ATTR1]] {
-; CGSCC-NEXT:    unreachable
-;
-  call void %fn()
-  ret void
-}
-define internal void @unknown_calle_arg_is_undef(ptr %fn, i32 %arg) {
-;
-; CHECK-LABEL: define {{[^@]+}}@unknown_calle_arg_is_undef
-; CHECK-SAME: (ptr nocapture nofree noundef nonnull [[FN:%.*]]) {
-; CHECK-NEXT:    call void [[FN]](i32 undef)
-; CHECK-NEXT:    ret void
-;
-  call void %fn(i32 %arg)
-  ret void
-}
-
-; Taken from 50683
-; {{{
-
- at g = internal constant { [2 x ptr] } { [2 x ptr] [ptr @f1, ptr @f2] }
-
-define internal void @f1(ptr %a) {
-; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
-; TUNIT-LABEL: define {{[^@]+}}@f1
-; TUNIT-SAME: (ptr nocapture nofree noundef nonnull writeonly align 8 dereferenceable(8) [[A:%.*]]) #[[ATTR4]] {
-; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    store ptr @g, ptr [[A]], align 8
-; TUNIT-NEXT:    ret void
-;
-; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
-; CGSCC-LABEL: define {{[^@]+}}@f1
-; CGSCC-SAME: (ptr nocapture nofree noundef nonnull writeonly align 8 dereferenceable(8) [[A:%.*]]) #[[ATTR5]] {
-; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    store ptr @g, ptr [[A]], align 8
-; CGSCC-NEXT:    ret void
-;
-entry:
-  store ptr @g , ptr %a, align 8
-  ret void
-}
-
-define internal void @f2(ptr %a) {
-; CHECK-LABEL: define {{[^@]+}}@f2
-; CHECK-SAME: (ptr nonnull [[A:%.*]]) {
-; CHECK-NEXT:  cont461:
-; CHECK-NEXT:    call void @f3(ptr nonnull [[A]], ptr nocapture nofree nonnull [[A]])
-; CHECK-NEXT:    ret void
-;
-cont461:
-  call void @f3(ptr %a, ptr %a)
-  ret void
-}
-
-define internal void @f3(ptr %a1, ptr %a) {
-; CHECK-LABEL: define {{[^@]+}}@f3
-; CHECK-SAME: (ptr nonnull [[A1:%.*]], ptr nocapture nofree nonnull [[A:%.*]]) {
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[CALL20:%.*]] = call i1 @f9()
-; CHECK-NEXT:    br i1 [[CALL20]], label [[LAND_LHS_TRUE:%.*]], label [[IF_END40:%.*]]
-; CHECK:       land.lhs.true:
-; CHECK-NEXT:    [[TMP0:%.*]] = call i1 [[A]](ptr [[A1]])
-; CHECK-NEXT:    br label [[IF_END40]]
-; CHECK:       if.end40:
-; CHECK-NEXT:    ret void
-;
-entry:
-  %call20 = call i1 @f9()
-  br i1 %call20, label %land.lhs.true, label %if.end40
-
-land.lhs.true:
-  call i1 %a(ptr %a1)
-  br label %if.end40
-
-if.end40:
-  ret void
-}
-
-define linkonce_odr i1 @f9() {
-; CHECK-LABEL: define {{[^@]+}}@f9() {
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    ret i1 false
-;
-entry:
-  ret i1 false
-}
-
-; }}}
-
-
-define i1 @test_cmp_null_after_cast() {
-; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; TUNIT-LABEL: define {{[^@]+}}@test_cmp_null_after_cast
-; TUNIT-SAME: () #[[ATTR2]] {
-; TUNIT-NEXT:    ret i1 true
-;
-; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@test_cmp_null_after_cast
-; CGSCC-SAME: () #[[ATTR3]] {
-; CGSCC-NEXT:    [[C:%.*]] = call noundef i1 @cmp_null_after_cast() #[[ATTR12]]
-; CGSCC-NEXT:    ret i1 [[C]]
-;
-  %c = call i1 @cmp_null_after_cast(i32 0, i8 0)
-  ret i1 %c
-}
-define internal i1 @cmp_null_after_cast(i32 %a, i8 %b) {
-; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@cmp_null_after_cast
-; CGSCC-SAME: () #[[ATTR1]] {
-; CGSCC-NEXT:    ret i1 true
-;
-  %t = trunc i32 %a to i8
-  %c = icmp eq i8 %t, %b
-  ret i1 %c
-}
-
-
-declare ptr @m()
-
-define i32 @test(i1 %c) {
-; TUNIT-LABEL: define {{[^@]+}}@test
-; TUNIT-SAME: (i1 [[C:%.*]]) {
-; TUNIT-NEXT:    [[R1:%.*]] = call i32 @ctx_test1(i1 noundef [[C]])
-; TUNIT-NEXT:    [[R2:%.*]] = call i32 @ctx_test2(i1 noundef [[C]]), !range [[RNG0:![0-9]+]]
-; TUNIT-NEXT:    [[ADD:%.*]] = add i32 [[R1]], [[R2]]
-; TUNIT-NEXT:    ret i32 [[ADD]]
-;
-; CGSCC-LABEL: define {{[^@]+}}@test
-; CGSCC-SAME: (i1 noundef [[C:%.*]]) {
-; CGSCC-NEXT:    [[R1:%.*]] = call i32 @ctx_test1(i1 noundef [[C]])
-; CGSCC-NEXT:    [[R2:%.*]] = call i32 @ctx_test2(i1 noundef [[C]])
-; CGSCC-NEXT:    [[ADD:%.*]] = add i32 [[R1]], [[R2]]
-; CGSCC-NEXT:    ret i32 [[ADD]]
-;
-  %r1 = call i32 @ctx_test1(i1 %c)
-  %r2 = call i32 @ctx_test2(i1 %c)
-  %add = add i32 %r1, %r2
-  ret i32 %add
-}
-
-define internal i32 @ctx_test1(i1 %c) {
-; CHECK-LABEL: define {{[^@]+}}@ctx_test1
-; CHECK-SAME: (i1 noundef [[C:%.*]]) {
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    br i1 [[C]], label [[THEN:%.*]], label [[JOIN:%.*]]
-; CHECK:       then:
-; CHECK-NEXT:    [[M:%.*]] = tail call ptr @m()
-; CHECK-NEXT:    [[I:%.*]] = ptrtoint ptr [[M]] to i64
-; CHECK-NEXT:    br label [[JOIN]]
-; CHECK:       join:
-; CHECK-NEXT:    [[PHI:%.*]] = phi i64 [ [[I]], [[THEN]] ], [ undef, [[ENTRY:%.*]] ]
-; CHECK-NEXT:    [[RET:%.*]] = trunc i64 [[PHI]] to i32
-; CHECK-NEXT:    ret i32 [[RET]]
-;
-entry:
-  br i1 %c, label %then, label %join
-
-then:
-  %m = tail call ptr @m()
-  %i = ptrtoint ptr %m to i64
-  br label %join
-
-join:
-  %phi = phi i64 [ %i, %then ], [ undef, %entry ]
-  %ret = trunc i64 %phi to i32
-  ret i32 %ret
-}
-
-define internal i32 @ctx_test2(i1 %c) {
-; CHECK-LABEL: define {{[^@]+}}@ctx_test2
-; CHECK-SAME: (i1 noundef [[C:%.*]]) {
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    br i1 [[C]], label [[THEN:%.*]], label [[JOIN:%.*]]
-; CHECK:       then:
-; CHECK-NEXT:    [[M:%.*]] = tail call ptr @m()
-; CHECK-NEXT:    [[I:%.*]] = ptrtoint ptr [[M]] to i32
-; CHECK-NEXT:    br label [[JOIN]]
-; CHECK:       join:
-; CHECK-NEXT:    [[PHI:%.*]] = phi i32 [ [[I]], [[THEN]] ], [ undef, [[ENTRY:%.*]] ]
-; CHECK-NEXT:    [[RET:%.*]] = lshr i32 [[PHI]], 1
-; CHECK-NEXT:    ret i32 [[RET]]
-;
-entry:
-  br i1 %c, label %then, label %join
-
-then:
-  %m = tail call ptr @m()
-  %i = ptrtoint ptr %m to i32
-  br label %join
-
-join:
-  %phi = phi i32 [ %i, %then ], [ undef, %entry ]
-  %ret = lshr i32 %phi, 1
-  ret i32 %ret
-
-  uselistorder label %join, { 1, 0 }
-}
-
-define i1 @test_liveness(i1 %c) {
-; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; TUNIT-LABEL: define {{[^@]+}}@test_liveness
-; TUNIT-SAME: (i1 noundef [[C:%.*]]) #[[ATTR2]] {
-; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
-; TUNIT:       t:
-; TUNIT-NEXT:    br label [[F]]
-; TUNIT:       f:
-; TUNIT-NEXT:    ret i1 false
-;
-; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@test_liveness
-; CGSCC-SAME: (i1 noundef [[C:%.*]]) #[[ATTR3]] {
-; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
-; CGSCC:       t:
-; CGSCC-NEXT:    br label [[F]]
-; CGSCC:       f:
-; CGSCC-NEXT:    [[P:%.*]] = phi i1 [ true, [[ENTRY:%.*]] ], [ false, [[T]] ]
-; CGSCC-NEXT:    [[RC1:%.*]] = call noundef i1 @ret(i1 noundef [[P]]) #[[ATTR12]]
-; CGSCC-NEXT:    ret i1 [[RC1]]
-;
-entry:
-  br i1 %c, label %t, label %f
-t:
-  br label %f
-f:
-  %p = phi i1 [true, %entry], [false, %t]
-  %rc1 = call i1 @ret(i1 %p)
-  ret i1 %rc1
-}
-
-define internal i1 @ret(i1 %c) {
-; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@ret
-; CGSCC-SAME: (i1 noundef [[C:%.*]]) #[[ATTR1]] {
-; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
-; CGSCC:       t:
-; CGSCC-NEXT:    br label [[F]]
-; CGSCC:       f:
-; CGSCC-NEXT:    [[P:%.*]] = phi i1 [ [[C]], [[ENTRY:%.*]] ], [ false, [[T]] ]
-; CGSCC-NEXT:    ret i1 false
-;
-entry:
-  br i1 %c, label %t, label %f
-t:
-  br label %f
-f:
-  %p = phi i1 [%c, %entry], [false, %t]
-  ret i1 %p
-}
-
-declare ptr @unknown()
-define internal i8 @dead_ret() {
-; CHECK-LABEL: define {{[^@]+}}@dead_ret() {
-; CHECK-NEXT:    [[R:%.*]] = call ptr @unknown()
-; CHECK-NEXT:    ret i8 undef
-;
-  %r = call ptr @unknown()
-  %l = load i8, ptr %r
-  ret i8 %l
-}
-
-define void @dead_ret_caller() {
-; CHECK-LABEL: define {{[^@]+}}@dead_ret_caller() {
-; CHECK-NEXT:    [[R:%.*]] = call i8 @dead_ret()
-; CHECK-NEXT:    ret void
-;
-  %r = call i8 @dead_ret()
-  ret void
-}
-
-declare void @llvm.memcpy(ptr %dest, ptr %src, i32 %len, i1 %isvolatile)
-define internal i8 @memcpy_uses_store(i8 %arg) {
-; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; TUNIT-LABEL: define {{[^@]+}}@memcpy_uses_store
-; TUNIT-SAME: (i8 [[ARG:%.*]]) #[[ATTR2]] {
-; TUNIT-NEXT:    [[SRC:%.*]] = alloca i8, align 1
-; TUNIT-NEXT:    [[DST:%.*]] = alloca i8, align 1
-; TUNIT-NEXT:    store i8 [[ARG]], ptr [[SRC]], align 1
-; TUNIT-NEXT:    call void @llvm.memcpy.p0.p0.i32(ptr noalias nocapture nofree noundef nonnull writeonly dereferenceable(1) [[DST]], ptr noalias nocapture nofree noundef nonnull readonly dereferenceable(1) [[SRC]], i32 noundef 1, i1 noundef false) #[[ATTR12:[0-9]+]]
-; TUNIT-NEXT:    [[L:%.*]] = load i8, ptr [[DST]], align 1
-; TUNIT-NEXT:    ret i8 [[L]]
-;
-; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@memcpy_uses_store
-; CGSCC-SAME: (i8 [[ARG:%.*]]) #[[ATTR1]] {
-; CGSCC-NEXT:    [[SRC:%.*]] = alloca i8, align 1
-; CGSCC-NEXT:    [[DST:%.*]] = alloca i8, align 1
-; CGSCC-NEXT:    store i8 [[ARG]], ptr [[SRC]], align 1
-; CGSCC-NEXT:    call void @llvm.memcpy.p0.p0.i32(ptr noalias nocapture nofree noundef nonnull writeonly dereferenceable(1) [[DST]], ptr noalias nocapture nofree noundef nonnull readonly dereferenceable(1) [[SRC]], i32 noundef 1, i1 noundef false) #[[ATTR16:[0-9]+]]
-; CGSCC-NEXT:    [[L:%.*]] = load i8, ptr [[DST]], align 1
-; CGSCC-NEXT:    ret i8 [[L]]
-;
-  %src = alloca i8
-  %dst = alloca i8
-  store i8 %arg, ptr %src
-  call void @llvm.memcpy(ptr %dst, ptr %src, i32 1, i1 false)
-  %l = load i8, ptr %dst
-  ret i8 %l
-}
-
-define i8 @memcpy_uses_store_caller(i8 %arg) {
-; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; TUNIT-LABEL: define {{[^@]+}}@memcpy_uses_store_caller
-; TUNIT-SAME: (i8 [[ARG:%.*]]) #[[ATTR2]] {
-; TUNIT-NEXT:    [[R:%.*]] = call i8 @memcpy_uses_store(i8 [[ARG]]) #[[ATTR13:[0-9]+]]
-; TUNIT-NEXT:    ret i8 [[R]]
-;
-; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@memcpy_uses_store_caller
-; CGSCC-SAME: (i8 [[ARG:%.*]]) #[[ATTR3]] {
-; CGSCC-NEXT:    [[R:%.*]] = call i8 @memcpy_uses_store(i8 [[ARG]]) #[[ATTR12]]
-; CGSCC-NEXT:    ret i8 [[R]]
-;
-  %r = call i8 @memcpy_uses_store(i8 %arg)
-  ret i8 %r
-}
-
-
-declare i32 @speculatable() speculatable readnone
-
-define i32 @test_speculatable_expr() norecurse {
-; TUNIT: Function Attrs: norecurse nosync memory(none)
-; TUNIT-LABEL: define {{[^@]+}}@test_speculatable_expr
-; TUNIT-SAME: () #[[ATTR7:[0-9]+]] {
-; TUNIT-NEXT:    [[STACK:%.*]] = alloca i32, align 4
-; TUNIT-NEXT:    [[SPEC_RESULT:%.*]] = call i32 @speculatable() #[[ATTR14:[0-9]+]]
-; TUNIT-NEXT:    [[PLUS1:%.*]] = add i32 [[SPEC_RESULT]], 1
-; TUNIT-NEXT:    store i32 [[PLUS1]], ptr [[STACK]], align 4
-; TUNIT-NEXT:    [[TMP1:%.*]] = load i32, ptr [[STACK]], align 4
-; TUNIT-NEXT:    [[RSPEC:%.*]] = call i32 @ret_speculatable_expr(i32 [[TMP1]]) #[[ATTR15:[0-9]+]]
-; TUNIT-NEXT:    ret i32 [[RSPEC]]
-;
-; CGSCC: Function Attrs: norecurse nosync memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@test_speculatable_expr
-; CGSCC-SAME: () #[[ATTR9:[0-9]+]] {
-; CGSCC-NEXT:    [[STACK:%.*]] = alloca i32, align 4
-; CGSCC-NEXT:    [[SPEC_RESULT:%.*]] = call i32 @speculatable() #[[ATTR17:[0-9]+]]
-; CGSCC-NEXT:    [[PLUS1:%.*]] = add i32 [[SPEC_RESULT]], 1
-; CGSCC-NEXT:    store i32 [[PLUS1]], ptr [[STACK]], align 4
-; CGSCC-NEXT:    [[RSPEC:%.*]] = call i32 @ret_speculatable_expr(i32 [[PLUS1]]) #[[ATTR17]]
-; CGSCC-NEXT:    ret i32 [[RSPEC]]
-;
-  %stack = alloca i32
-  %spec_result = call i32 @speculatable()
-  %plus1 = add i32 %spec_result, 1
-  store i32 %plus1, ptr %stack
-  %rspec = call i32 @ret_speculatable_expr(ptr %stack, i32 13)
-  ret i32 %rspec
-}
-
-define internal i32 @ret_speculatable_expr(ptr %mem, i32 %a2) {
-; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; TUNIT-LABEL: define {{[^@]+}}@ret_speculatable_expr
-; TUNIT-SAME: (i32 [[TMP0:%.*]]) #[[ATTR2]] {
-; TUNIT-NEXT:    [[MEM_PRIV:%.*]] = alloca i32, align 4
-; TUNIT-NEXT:    store i32 [[TMP0]], ptr [[MEM_PRIV]], align 4
-; TUNIT-NEXT:    [[L:%.*]] = load i32, ptr [[MEM_PRIV]], align 4
-; TUNIT-NEXT:    [[MUL:%.*]] = mul i32 [[L]], 13
-; TUNIT-NEXT:    [[ADD:%.*]] = add i32 [[MUL]], 7
-; TUNIT-NEXT:    ret i32 [[ADD]]
-;
-; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@ret_speculatable_expr
-; CGSCC-SAME: (i32 [[TMP0:%.*]]) #[[ATTR1]] {
-; CGSCC-NEXT:    [[MEM_PRIV:%.*]] = alloca i32, align 4
-; CGSCC-NEXT:    store i32 [[TMP0]], ptr [[MEM_PRIV]], align 4
-; CGSCC-NEXT:    [[L:%.*]] = load i32, ptr [[MEM_PRIV]], align 4
-; CGSCC-NEXT:    [[MUL:%.*]] = mul i32 [[L]], 13
-; CGSCC-NEXT:    [[ADD:%.*]] = add i32 [[MUL]], 7
-; CGSCC-NEXT:    ret i32 [[ADD]]
-;
-  %l = load i32, ptr %mem
-  %mul = mul i32 %l, %a2
-  %add = add i32 %mul, 7
-  ret i32 %add
-}
-
-define internal void @not_called1() {
-; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; TUNIT-LABEL: define {{[^@]+}}@not_called1
-; TUNIT-SAME: () #[[ATTR2]] {
-; TUNIT-NEXT:    ret void
-;
-; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@not_called1
-; CGSCC-SAME: () #[[ATTR1]] {
-; CGSCC-NEXT:    ret void
-;
-  ret void
-}
-define internal void @not_called2() {
-; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; TUNIT-LABEL: define {{[^@]+}}@not_called2
-; TUNIT-SAME: () #[[ATTR2]] {
-; TUNIT-NEXT:    ret void
-;
-; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@not_called2
-; CGSCC-SAME: () #[[ATTR1]] {
-; CGSCC-NEXT:    ret void
-;
-  ret void
-}
-define internal void @not_called3() {
-; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; TUNIT-LABEL: define {{[^@]+}}@not_called3
-; TUNIT-SAME: () #[[ATTR2]] {
-; TUNIT-NEXT:    ret void
-;
-; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@not_called3
-; CGSCC-SAME: () #[[ATTR1]] {
-; CGSCC-NEXT:    ret void
-;
-  ret void
-}
-declare void @useFnDecl(ptr addrspace(42));
-define void @useFnDef(ptr addrspace(42) %arg) {
-; CHECK-LABEL: define {{[^@]+}}@useFnDef
-; CHECK-SAME: (ptr addrspace(42) [[ARG:%.*]]) {
-; CHECK-NEXT:    call void @useFnDecl(ptr addrspace(42) [[ARG]])
-; CHECK-NEXT:    ret void
-;
-  call void @useFnDecl(ptr addrspace(42) %arg)
-  ret void
-}
-define i1 @user_of_not_called() {
-; CHECK-LABEL: define {{[^@]+}}@user_of_not_called() {
-; CHECK-NEXT:    call void @useFnDecl(ptr addrspace(42) noundef nonnull addrspacecast (ptr @not_called1 to ptr addrspace(42)))
-; CHECK-NEXT:    call void @useFnDef(ptr addrspace(42) noundef nonnull addrspacecast (ptr @not_called2 to ptr addrspace(42)))
-; CHECK-NEXT:    ret i1 icmp eq (ptr addrspace(42) addrspacecast (ptr @not_called3 to ptr addrspace(42)), ptr addrspace(42) null)
-;
-  call void @useFnDecl(ptr addrspace(42) addrspacecast (ptr @not_called1 to ptr addrspace(42)))
-  call void @useFnDef(ptr addrspace(42) addrspacecast (ptr @not_called2 to ptr addrspace(42)))
-  %cmp = icmp eq ptr addrspace(42) addrspacecast (ptr @not_called3 to ptr addrspace(42)), null
-  ret i1 %cmp
-}
-
- at x = external global i32
-define internal void @indirect() {
-; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write)
-; TUNIT-LABEL: define {{[^@]+}}@indirect
-; TUNIT-SAME: () #[[ATTR5]] {
-; TUNIT-NEXT:    store i32 0, ptr @x, align 4
-; TUNIT-NEXT:    ret void
-;
-; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write)
-; CGSCC-LABEL: define {{[^@]+}}@indirect
-; CGSCC-SAME: () #[[ATTR10:[0-9]+]] {
-; CGSCC-NEXT:    store i32 0, ptr @x, align 4
-; CGSCC-NEXT:    ret void
-;
-  store i32 0, ptr @x
-  ret void
-}
-
-define internal void @broker(ptr %ptr) {
-; TUNIT: Function Attrs: memory(readwrite, argmem: none)
-; TUNIT-LABEL: define {{[^@]+}}@broker
-; TUNIT-SAME: () #[[ATTR1]] {
-; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    call void @indirect() #[[ATTR16:[0-9]+]]
-; TUNIT-NEXT:    call void @unknown()
-; TUNIT-NEXT:    ret void
-;
-; CGSCC: Function Attrs: memory(readwrite, argmem: none)
-; CGSCC-LABEL: define {{[^@]+}}@broker
-; CGSCC-SAME: () #[[ATTR2]] {
-; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    call void @indirect() #[[ATTR18:[0-9]+]]
-; CGSCC-NEXT:    call void @unknown()
-; CGSCC-NEXT:    ret void
-;
-entry:
-  call void %ptr()
-  call void @unknown()
-  ret void
-}
-
-define void @entry() {
-; CHECK-LABEL: define {{[^@]+}}@entry() {
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    call void @broker()
-; CHECK-NEXT:    ret void
-;
-entry:
-  call void @broker(ptr @indirect)
-  ret void
-}
-
-define i1 @constexpr_icmp1() {
-; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; TUNIT-LABEL: define {{[^@]+}}@constexpr_icmp1
-; TUNIT-SAME: () #[[ATTR2]] {
-; TUNIT-NEXT:    ret i1 icmp ne (ptr addrspacecast (ptr addrspace(4) @str to ptr), ptr null)
-;
-; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@constexpr_icmp1
-; CGSCC-SAME: () #[[ATTR1]] {
-; CGSCC-NEXT:    ret i1 icmp ne (ptr addrspacecast (ptr addrspace(4) @str to ptr), ptr null)
-;
-  ret i1 icmp ne (ptr addrspacecast (ptr addrspace(4) @str to ptr), ptr null)
-}
-
-define i1 @constexpr_icmp2() {
-; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; TUNIT-LABEL: define {{[^@]+}}@constexpr_icmp2
-; TUNIT-SAME: () #[[ATTR2]] {
-; TUNIT-NEXT:    ret i1 icmp eq (ptr addrspacecast (ptr addrspace(4) @str to ptr), ptr null)
-;
-; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@constexpr_icmp2
-; CGSCC-SAME: () #[[ATTR1]] {
-; CGSCC-NEXT:    ret i1 icmp eq (ptr addrspacecast (ptr addrspace(4) @str to ptr), ptr null)
-;
-  ret i1 icmp eq (ptr addrspacecast (ptr addrspace(4) @str to ptr), ptr null)
-}
-
-define i8 @switch(i1 %c1, i1 %c2) {
-; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; TUNIT-LABEL: define {{[^@]+}}@switch
-; TUNIT-SAME: (i1 noundef [[C1:%.*]], i1 [[C2:%.*]]) #[[ATTR2]] {
-; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    br i1 [[C1]], label [[T:%.*]], label [[F:%.*]]
-; TUNIT:       t:
-; TUNIT-NEXT:    br label [[M:%.*]]
-; TUNIT:       f:
-; TUNIT-NEXT:    br label [[M]]
-; TUNIT:       m:
-; TUNIT-NEXT:    [[J:%.*]] = phi i32 [ 0, [[T]] ], [ 4, [[F]] ]
-; TUNIT-NEXT:    switch i32 [[J]], label [[DEFAULT1:%.*]] [
-; TUNIT-NEXT:      i32 1, label [[DEAD1:%.*]]
-; TUNIT-NEXT:      i32 2, label [[DEAD2:%.*]]
-; TUNIT-NEXT:      i32 3, label [[DEAD3:%.*]]
-; TUNIT-NEXT:      i32 4, label [[ALIVE1:%.*]]
-; TUNIT-NEXT:    ]
-; TUNIT:       default1:
-; TUNIT-NEXT:    br label [[ALIVE1]]
-; TUNIT:       alive1:
-; TUNIT-NEXT:    [[K:%.*]] = phi i32 [ 1, [[M]] ], [ 4, [[DEFAULT1]] ]
-; TUNIT-NEXT:    switch i32 [[K]], label [[DEAD4:%.*]] [
-; TUNIT-NEXT:      i32 1, label [[END1:%.*]]
-; TUNIT-NEXT:      i32 2, label [[DEAD5:%.*]]
-; TUNIT-NEXT:      i32 4, label [[END2:%.*]]
-; TUNIT-NEXT:    ]
-; TUNIT:       end1:
-; TUNIT-NEXT:    ret i8 -1
-; TUNIT:       end2:
-; TUNIT-NEXT:    ret i8 -2
-; TUNIT:       dead1:
-; TUNIT-NEXT:    unreachable
-; TUNIT:       dead2:
-; TUNIT-NEXT:    unreachable
-; TUNIT:       dead3:
-; TUNIT-NEXT:    unreachable
-; TUNIT:       dead4:
-; TUNIT-NEXT:    unreachable
-; TUNIT:       dead5:
-; TUNIT-NEXT:    unreachable
-;
-; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@switch
-; CGSCC-SAME: (i1 noundef [[C1:%.*]], i1 [[C2:%.*]]) #[[ATTR1]] {
-; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    br i1 [[C1]], label [[T:%.*]], label [[F:%.*]]
-; CGSCC:       t:
-; CGSCC-NEXT:    br label [[M:%.*]]
-; CGSCC:       f:
-; CGSCC-NEXT:    br label [[M]]
-; CGSCC:       m:
-; CGSCC-NEXT:    [[J:%.*]] = phi i32 [ 0, [[T]] ], [ 4, [[F]] ]
-; CGSCC-NEXT:    switch i32 [[J]], label [[DEFAULT1:%.*]] [
-; CGSCC-NEXT:      i32 1, label [[DEAD1:%.*]]
-; CGSCC-NEXT:      i32 2, label [[DEAD2:%.*]]
-; CGSCC-NEXT:      i32 3, label [[DEAD3:%.*]]
-; CGSCC-NEXT:      i32 4, label [[ALIVE1:%.*]]
-; CGSCC-NEXT:    ]
-; CGSCC:       default1:
-; CGSCC-NEXT:    br label [[ALIVE1]]
-; CGSCC:       alive1:
-; CGSCC-NEXT:    [[K:%.*]] = phi i32 [ 1, [[M]] ], [ 4, [[DEFAULT1]] ]
-; CGSCC-NEXT:    switch i32 [[K]], label [[DEAD4:%.*]] [
-; CGSCC-NEXT:      i32 1, label [[END1:%.*]]
-; CGSCC-NEXT:      i32 2, label [[DEAD5:%.*]]
-; CGSCC-NEXT:      i32 4, label [[END2:%.*]]
-; CGSCC-NEXT:    ]
-; CGSCC:       end1:
-; CGSCC-NEXT:    ret i8 -1
-; CGSCC:       end2:
-; CGSCC-NEXT:    ret i8 -2
-; CGSCC:       dead1:
-; CGSCC-NEXT:    unreachable
-; CGSCC:       dead2:
-; CGSCC-NEXT:    unreachable
-; CGSCC:       dead3:
-; CGSCC-NEXT:    unreachable
-; CGSCC:       dead4:
-; CGSCC-NEXT:    unreachable
-; CGSCC:       dead5:
-; CGSCC-NEXT:    unreachable
-;
-entry:
-  br i1 %c1, label %t, label %f
-
-t:
-  br label %m
-
-f:
-  br label %m
-
-m:
-  %j = phi i32 [ 0, %t ], [ 4, %f ]
-  switch i32 %j, label %default1 [
-  i32 1, label %dead1
-  i32 2, label %dead2
-  i32 3, label %dead3
-  i32 4, label %alive1
-  ]
-
-default1:
-  br label %alive1
-
-alive1:
-  %k = phi i32 [ 1, %m ], [ 4, %default1 ]
-  switch i32 %k, label %dead4 [
-  i32 1, label %end1
-  i32 2, label %dead5
-  i32 4, label %end2
-  ]
-
-end1:
-  ret i8 -1
-end2:
-  ret i8 -2
-dead1:
-  ret i8 1
-dead2:
-  ret i8 2
-dead3:
-  ret i8 3
-dead4:
-  ret i8 4
-dead5:
-  ret i8 5
-}
-
-define i32 @readConst() {
-; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; TUNIT-LABEL: define {{[^@]+}}@readConst
-; TUNIT-SAME: () #[[ATTR2]] {
-; TUNIT-NEXT:    ret i32 0
-;
-; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@readConst
-; CGSCC-SAME: () #[[ATTR1]] {
-; CGSCC-NEXT:    ret i32 0
-;
-  %l = load i32, ptr @ConstPtr
-  ret i32 %l
-}
-
-define i32 @readWeakConst() {
-; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; TUNIT-LABEL: define {{[^@]+}}@readWeakConst
-; TUNIT-SAME: () #[[ATTR2]] {
-; TUNIT-NEXT:    [[L:%.*]] = load i32, ptr @ConstWeakPtr, align 4
-; TUNIT-NEXT:    ret i32 [[L]]
-;
-; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@readWeakConst
-; CGSCC-SAME: () #[[ATTR1]] {
-; CGSCC-NEXT:    [[L:%.*]] = load i32, ptr @ConstWeakPtr, align 4
-; CGSCC-NEXT:    ret i32 [[L]]
-;
-  %l = load i32, ptr @ConstWeakPtr
-  ret i32 %l
-}
-
-define i32 @readWeakOdrConst() {
-; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; TUNIT-LABEL: define {{[^@]+}}@readWeakOdrConst
-; TUNIT-SAME: () #[[ATTR2]] {
-; TUNIT-NEXT:    ret i32 0
-;
-; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define {{[^@]+}}@readWeakOdrConst
-; CGSCC-SAME: () #[[ATTR1]] {
-; CGSCC-NEXT:    ret i32 0
-;
-  %l = load i32, ptr @ConstWeakODRPtr
-  ret i32 %l
-}
-
 ;.
 ; TUNIT: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nosync nounwind willreturn }
-; TUNIT: attributes #[[ATTR1]] = { memory(readwrite, argmem: none) }
+; TUNIT: attributes #[[ATTR1]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) }
 ; TUNIT: attributes #[[ATTR2]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
-; TUNIT: attributes #[[ATTR3]] = { mustprogress nofree norecurse nosync nounwind willreturn }
-; TUNIT: attributes #[[ATTR4]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) }
-; TUNIT: attributes #[[ATTR5]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(write) }
-; TUNIT: attributes #[[ATTR6:[0-9]+]] = { speculatable memory(none) }
-; TUNIT: attributes #[[ATTR7]] = { norecurse nosync memory(none) }
-; TUNIT: attributes #[[ATTR8:[0-9]+]] = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }
-; TUNIT: attributes #[[ATTR9]] = { nofree nosync nounwind willreturn memory(none) }
-; TUNIT: attributes #[[ATTR10]] = { nofree willreturn }
-; TUNIT: attributes #[[ATTR11]] = { nofree nosync nounwind willreturn memory(write) }
-; TUNIT: attributes #[[ATTR12]] = { nofree willreturn memory(readwrite) }
-; TUNIT: attributes #[[ATTR13]] = { nofree nosync nounwind willreturn }
-; TUNIT: attributes #[[ATTR14]] = { nosync }
-; TUNIT: attributes #[[ATTR15]] = { nosync nounwind memory(read) }
-; TUNIT: attributes #[[ATTR16]] = { nounwind memory(write) }
+; TUNIT: attributes #[[ATTR3]] = { nofree nosync nounwind willreturn memory(write) }
 ;.
-; TUNIT: [[RNG0]] = !{i32 0, i32 -2147483648}
+; TUNIT-DL: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nosync nounwind willreturn }
+; TUNIT-DL: attributes #[[ATTR1]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) }
+; TUNIT-DL: attributes #[[ATTR2]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
 ;.
 ; CGSCC: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nosync nounwind willreturn }
-; CGSCC: attributes #[[ATTR1]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
-; CGSCC: attributes #[[ATTR2]] = { memory(readwrite, argmem: none) }
-; CGSCC: attributes #[[ATTR3]] = { mustprogress nofree nosync nounwind willreturn memory(none) }
-; CGSCC: attributes #[[ATTR4]] = { mustprogress nofree nosync nounwind willreturn }
-; CGSCC: attributes #[[ATTR5]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) }
-; CGSCC: attributes #[[ATTR6]] = { mustprogress nofree nosync nounwind willreturn memory(argmem: write) }
-; CGSCC: attributes #[[ATTR7]] = { mustprogress nofree nosync nounwind willreturn memory(write) }
-; CGSCC: attributes #[[ATTR8:[0-9]+]] = { speculatable memory(none) }
-; CGSCC: attributes #[[ATTR9]] = { norecurse nosync memory(none) }
-; CGSCC: attributes #[[ATTR10]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(write) }
-; CGSCC: attributes #[[ATTR11:[0-9]+]] = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }
-; CGSCC: attributes #[[ATTR12]] = { nofree nosync willreturn }
-; CGSCC: attributes #[[ATTR13]] = { nofree willreturn }
-; CGSCC: attributes #[[ATTR14]] = { nofree nounwind willreturn }
-; CGSCC: attributes #[[ATTR15]] = { nofree nounwind willreturn memory(write) }
-; CGSCC: attributes #[[ATTR16]] = { nofree willreturn memory(readwrite) }
-; CGSCC: attributes #[[ATTR17]] = { nosync }
-; CGSCC: attributes #[[ATTR18]] = { nounwind }
+; CGSCC: attributes #[[ATTR1]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) }
+; CGSCC: attributes #[[ATTR2]] = { mustprogress nofree nosync nounwind willreturn memory(argmem: write) }
+; CGSCC: attributes #[[ATTR3]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
+; CGSCC: attributes #[[ATTR4]] = { mustprogress nofree nosync nounwind willreturn memory(none) }
+; CGSCC: attributes #[[ATTR5]] = { nofree nounwind willreturn memory(write) }
+; CGSCC: attributes #[[ATTR6]] = { nofree nosync willreturn }
+;.
+; CGSCC-DL: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nosync nounwind willreturn }
+; CGSCC-DL: attributes #[[ATTR1]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) }
+; CGSCC-DL: attributes #[[ATTR2]] = { mustprogress nofree nosync nounwind willreturn memory(argmem: write) }
+; CGSCC-DL: attributes #[[ATTR3]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
+; CGSCC-DL: attributes #[[ATTR4]] = { mustprogress nofree nosync nounwind willreturn memory(none) }
 ;.
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK-DL: {{.*}}
diff --git a/llvm/test/Transforms/InstCombine/alloca-cast-debuginfo-dl-sentinel.ll b/llvm/test/Transforms/InstCombine/alloca-cast-debuginfo-dl-sentinel.ll
deleted file mode 100755
index 3a763cde2f0d1..0000000000000
--- a/llvm/test/Transforms/InstCombine/alloca-cast-debuginfo-dl-sentinel.ll
+++ /dev/null
@@ -1,88 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt < %s -S -passes=instcombine -instcombine-lower-dbg-declare=0 | FileCheck %s
-
-; In this example, instcombine wants to turn "local" into an i64, since that's
-; how it is stored. It should keep the debug info referring to the alloca when
-; it does the replacement.
-
-; C source:
-; struct Foo {
-;   int x, y;
-; };
-; void escape(const ptr);
-; void f(struct Foo *p) {
-;   struct Foo local;
-;   *(__int64 *)&local = *(__int64 *)p;
-;   escape(&local);
-; }
-
-; ModuleID = '<stdin>'
-source_filename = "t.c"
-target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-z0:1-z2:neg1-z3:neg1-z5:neg1-S128"
-target triple = "x86_64-pc-windows-msvc19.11.25508"
-
-%struct.Foo = type { i32, i32 }
-
-define void @f(ptr %p) !dbg !11 {
-; CHECK-LABEL: @f(
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[LOCAL:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4
-; CHECK-NEXT:    tail call void @llvm.dbg.declare(metadata ptr [[LOCAL]], metadata [[META22:![0-9]+]], metadata !DIExpression()), !dbg [[DBG23:![0-9]+]]
-; CHECK-NEXT:    [[TMP0:%.*]] = load i64, ptr [[P:%.*]], align 8, !dbg [[DBG24:![0-9]+]], !tbaa [[TBAA25:![0-9]+]]
-; CHECK-NEXT:    store i64 [[TMP0]], ptr [[LOCAL]], align 4, !dbg [[DBG29:![0-9]+]], !tbaa [[TBAA25]]
-; CHECK-NEXT:    call void @escape(ptr nonnull [[LOCAL]]), !dbg [[DBG30:![0-9]+]]
-; CHECK-NEXT:    ret void, !dbg [[DBG31:![0-9]+]]
-;
-entry:
-  %local = alloca %struct.Foo, align 4
-  call void @llvm.dbg.declare(metadata ptr %local, metadata !22, metadata !DIExpression()), !dbg !25
-  %0 = load i64, ptr %p, align 8, !dbg !26, !tbaa !27
-  store i64 %0, ptr %local, align 4, !dbg !32, !tbaa !27
-  call void @escape(ptr %local), !dbg !34
-  ret void, !dbg !35
-}
-
-declare void @llvm.dbg.declare(metadata, metadata, metadata)
-
-declare void @escape(ptr)
-
-!llvm.dbg.cu = !{!0}
-!llvm.module.flags = !{!6, !7, !8, !9}
-!llvm.ident = !{!10}
-
-!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 6.0.0 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3)
-!1 = !DIFile(filename: "t.c", directory: "C:\5Csrc\5Cllvm-project\5Cbuild", checksumkind: CSK_MD5, checksum: "d7473625866433067a75fd7d03d2abf7")
-!2 = !{}
-!3 = !{!4}
-!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64)
-!5 = !DIBasicType(name: "long long int", size: 64, encoding: DW_ATE_signed)
-!6 = !{i32 2, !"CodeView", i32 1}
-!7 = !{i32 2, !"Debug Info Version", i32 3}
-!8 = !{i32 1, !"wchar_size", i32 2}
-!9 = !{i32 7, !"PIC Level", i32 2}
-!10 = !{!"clang version 6.0.0 "}
-!11 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 5, type: !12, isLocal: false, isDefinition: true, scopeLine: 5, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !20)
-!12 = !DISubroutineType(types: !13)
-!13 = !{null, !14}
-!14 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !15, size: 64)
-!15 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Foo", file: !1, line: 1, size: 64, elements: !16)
-!16 = !{!17, !19}
-!17 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !15, file: !1, line: 2, baseType: !18, size: 32)
-!18 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
-!19 = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: !15, file: !1, line: 2, baseType: !18, size: 32, offset: 32)
-!20 = !{!21, !22}
-!21 = !DILocalVariable(name: "p", arg: 1, scope: !11, file: !1, line: 5, type: !14)
-!22 = !DILocalVariable(name: "local", scope: !11, file: !1, line: 6, type: !15)
-!23 = !DILocation(line: 5, column: 20, scope: !11)
-!24 = !DILocation(line: 6, column: 3, scope: !11)
-!25 = !DILocation(line: 6, column: 14, scope: !11)
-!26 = !DILocation(line: 7, column: 24, scope: !11)
-!27 = !{!28, !28, i64 0}
-!28 = !{!"long long", !29, i64 0}
-!29 = !{!"omnipotent char", !30, i64 0}
-!30 = !{!"Simple C/C++ TBAA"}
-!31 = !DILocation(line: 7, column: 3, scope: !11)
-!32 = !DILocation(line: 7, column: 22, scope: !11)
-!33 = !DILocation(line: 8, column: 10, scope: !11)
-!34 = !DILocation(line: 8, column: 3, scope: !11)
-!35 = !DILocation(line: 9, column: 1, scope: !11)
diff --git a/llvm/test/Transforms/InstCombine/alloca-in-non-alloca-as-sentinel.ll b/llvm/test/Transforms/InstCombine/alloca-in-non-alloca-as-sentinel.ll
index d495881f8c2ca..941d649bff054 100755
--- a/llvm/test/Transforms/InstCombine/alloca-in-non-alloca-as-sentinel.ll
+++ b/llvm/test/Transforms/InstCombine/alloca-in-non-alloca-as-sentinel.ll
@@ -1,25 +1,31 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
 ; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+; RUN: opt < %s -passes=instcombine -data-layout=z0:1-z2:neg1-z3:neg1-z5:neg1 -S | FileCheck -check-prefixes=CHECK-DL %s
 
 ; Gracefully handle the alloca that is not in the alloca AS (=5)
 
-target datalayout = "e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32-p7:160:256:256:32-p8:128:128-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-z0:1-z2:neg1-z3:neg1-z5:neg1-S32-A5-G1-ni:7:8:9"
-target triple = "amdgcn-amd-amdhsa"
-
 declare void @use(ptr)
 declare void @use2(ptr, ptr)
 
-define weak amdgpu_kernel void @__omp_offloading_802_ea0109_main_l8(ptr %a) {
+define void @__omp_offloading_802_ea0109_main_l8(ptr %a) {
 ; CHECK-LABEL: @__omp_offloading_802_ea0109_main_l8(
 ; CHECK-NEXT:  .master:
-; CHECK-NEXT:    [[TMP0:%.*]] = alloca [8 x i8], align 1
-; CHECK-NEXT:    call void @use2(ptr nonnull [[TMP0]], ptr nonnull [[TMP0]])
+; CHECK-NEXT:    [[ALLOCA1:%.*]] = alloca [8 x i8], align 1, addrspace(5)
+; CHECK-NEXT:    store ptr null, ptr addrspace(5) [[ALLOCA1]], align 8
+; CHECK-NEXT:    call void @use2(ptr addrspace(5) [[ALLOCA1]], ptr addrspace(5) [[ALLOCA1]])
 ; CHECK-NEXT:    ret void
 ;
+; CHECK-DL-LABEL: @__omp_offloading_802_ea0109_main_l8(
+; CHECK-DL-NEXT:  .master:
+; CHECK-DL-NEXT:    [[ALLOCA1:%.*]] = alloca [8 x i8], align 1, addrspace(5)
+; CHECK-DL-NEXT:    store ptr null, ptr addrspace(5) [[ALLOCA1]], align 8
+; CHECK-DL-NEXT:    call void @use2(ptr addrspace(5) nonnull [[ALLOCA1]], ptr addrspace(5) nonnull [[ALLOCA1]])
+; CHECK-DL-NEXT:    ret void
+;
 .master:
-  %0 = alloca i8, i64 8, align 1
-  store ptr undef, ptr %0, align 8
-  call void @use2(ptr %0, ptr %0)
+  %alloca = alloca i8, i64 8, align 1, addrspace(5)
+  store ptr null, ptr  addrspace(5) %alloca, align 8
+  call void @use2(ptr  addrspace(5) %alloca, ptr  addrspace(5) %alloca)
   ret void
 }
 
@@ -28,21 +34,50 @@ define weak amdgpu_kernel void @__omp_offloading_802_ea0109_main_l8(ptr %a) {
 define void @spam(ptr %arg1) {
 ; CHECK-LABEL: @spam(
 ; CHECK-NEXT:  bb:
-; CHECK-NEXT:    [[ALLOCA1:%.*]] = alloca [0 x [30 x %struct.widget]], align 16
-; CHECK-NEXT:    call void @zot(ptr nonnull [[ALLOCA1]])
+; CHECK-NEXT:    [[ALLOCA1:%.*]] = alloca [0 x [30 x %struct.widget]], align 16, addrspace(5)
+; CHECK-NEXT:    call void @zot(ptr addrspace(5) [[ALLOCA1]])
 ; CHECK-NEXT:    ret void
 ;
+; CHECK-DL-LABEL: @spam(
+; CHECK-DL-NEXT:  bb:
+; CHECK-DL-NEXT:    [[ALLOCA1:%.*]] = alloca [0 x [30 x %struct.widget]], align 16, addrspace(5)
+; CHECK-DL-NEXT:    call void @zot(ptr addrspace(5) nonnull [[ALLOCA1]])
+; CHECK-DL-NEXT:    ret void
+;
 bb:
-  %alloca = alloca [30 x %struct.widget], i32 0, align 16
-  call void @zot(ptr %alloca)
+  %alloca = alloca [30 x %struct.widget], i32 0, align 16, addrspace(5)
+  call void @zot(ptr  addrspace(5) %alloca)
   ret void
 }
 
+define i1 @alloca_addrspace_3_nonnull() {
+; CHECK-LABEL: @alloca_addrspace_3_nonnull(
+; CHECK-NEXT:    [[ALLOCA:%.*]] = alloca i8, align 1, addrspace(3)
+; CHECK-NEXT:    call void @use(ptr addrspace(3) [[ALLOCA]])
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne ptr addrspace(3) [[ALLOCA]], null
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+; CHECK-DL-LABEL: @alloca_addrspace_3_nonnull(
+; CHECK-DL-NEXT:    [[ALLOCA:%.*]] = alloca i8, align 1, addrspace(3)
+; CHECK-DL-NEXT:    call void @use(ptr addrspace(3) nonnull [[ALLOCA]])
+; CHECK-DL-NEXT:    ret i1 true
+;
+  %alloca = alloca i8, addrspace(3)
+  call void @use(ptr addrspace(3) %alloca)
+  %cmp = icmp ne ptr addrspace(3) %alloca, null
+  ret i1 %cmp
+}
+
 define i1 @alloca_addrspace_0_nonnull() {
 ; CHECK-LABEL: @alloca_addrspace_0_nonnull(
 ; CHECK-NEXT:    [[ALLOCA:%.*]] = alloca i8, align 1
 ; CHECK-NEXT:    call void @use(ptr nonnull [[ALLOCA]])
 ; CHECK-NEXT:    ret i1 true
+;
+; CHECK-DL-LABEL: @alloca_addrspace_0_nonnull(
+; CHECK-DL-NEXT:    [[ALLOCA:%.*]] = alloca i8, align 1
+; CHECK-DL-NEXT:    call void @use(ptr nonnull [[ALLOCA]])
+; CHECK-DL-NEXT:    ret i1 true
 ;
   %alloca = alloca i8
   call void @use(ptr %alloca)
@@ -53,8 +88,14 @@ define i1 @alloca_addrspace_0_nonnull() {
 define i1 @alloca_addrspace_5_nonnull() {
 ; CHECK-LABEL: @alloca_addrspace_5_nonnull(
 ; CHECK-NEXT:    [[ALLOCA:%.*]] = alloca i8, align 1, addrspace(5)
-; CHECK-NEXT:    call void @use(ptr addrspace(5) nonnull [[ALLOCA]])
-; CHECK-NEXT:    ret i1 true
+; CHECK-NEXT:    call void @use(ptr addrspace(5) [[ALLOCA]])
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne ptr addrspace(5) [[ALLOCA]], null
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+; CHECK-DL-LABEL: @alloca_addrspace_5_nonnull(
+; CHECK-DL-NEXT:    [[ALLOCA:%.*]] = alloca i8, align 1, addrspace(5)
+; CHECK-DL-NEXT:    call void @use(ptr addrspace(5) nonnull [[ALLOCA]])
+; CHECK-DL-NEXT:    ret i1 true
 ;
   %alloca = alloca i8, addrspace(5)
   call void @use(ptr addrspace(5) %alloca)
diff --git a/llvm/test/Transforms/InstCombine/assume-dl-sentinel.ll b/llvm/test/Transforms/InstCombine/assume-dl-sentinel.ll
index 3f8ed71b2eacf..01bff51cab0e2 100755
--- a/llvm/test/Transforms/InstCombine/assume-dl-sentinel.ll
+++ b/llvm/test/Transforms/InstCombine/assume-dl-sentinel.ll
@@ -1,276 +1,31 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
 ; RUN: opt < %s -passes=instcombine -S | FileCheck --check-prefixes=CHECK,DEFAULT %s
+; RUN: opt < %s -passes=instcombine -data-layout=z0:1-z2:neg1-z3:neg1-z5:neg1 -S | FileCheck --check-prefixes=CHECK-DL,DEFAULT-DL %s
 ; RUN: opt < %s -passes=instcombine --enable-knowledge-retention -S | FileCheck --check-prefixes=CHECK,BUNDLES %s
+; RUN: opt < %s -passes=instcombine --enable-knowledge-retention -data-layout=z0:1-z2:neg1-z3:neg1-z5:neg1 -S | FileCheck --check-prefixes=CHECK-DL,BUNDLES-DL %s
 
 ; RUN: opt < %s -passes=instcombine -S --try-experimental-debuginfo-iterators | FileCheck --check-prefixes=CHECK,DEFAULT %s
+; RUN: opt < %s -passes=instcombine -data-layout=z0:1-z2:neg1-z3:neg1-z5:neg1 -S --try-experimental-debuginfo-iterators | FileCheck --check-prefixes=CHECK-DL,DEFAULT-DL %s
 ; RUN: opt < %s -passes=instcombine --enable-knowledge-retention -S --try-experimental-debuginfo-iterators | FileCheck --check-prefixes=CHECK,BUNDLES %s
+; RUN: opt < %s -passes=instcombine --enable-knowledge-retention -data-layout=z0:1-z2:neg1-z3:neg1-z5:neg1 -S --try-experimental-debuginfo-iterators | FileCheck --check-prefixes=CHECK-DL,BUNDLES-DL %s
 
-target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-z0:1-z2:neg1-z3:neg1-z5:neg1-S128"
 target triple = "x86_64-unknown-linux-gnu"
 
 declare void @llvm.assume(i1) #1
-
-; Check that the assume has not been removed:
-
-define i32 @foo1(ptr %a) #0 {
-; DEFAULT-LABEL: @foo1(
-; DEFAULT-NEXT:    [[T0:%.*]] = load i32, ptr [[A:%.*]], align 4
-; DEFAULT-NEXT:    [[PTRINT:%.*]] = ptrtoint ptr [[A]] to i64
-; DEFAULT-NEXT:    [[MASKEDPTR:%.*]] = and i64 [[PTRINT]], 31
-; DEFAULT-NEXT:    [[MASKCOND:%.*]] = icmp eq i64 [[MASKEDPTR]], 0
-; DEFAULT-NEXT:    tail call void @llvm.assume(i1 [[MASKCOND]])
-; DEFAULT-NEXT:    ret i32 [[T0]]
-;
-; BUNDLES-LABEL: @foo1(
-; BUNDLES-NEXT:    [[T0:%.*]] = load i32, ptr [[A:%.*]], align 4
-; BUNDLES-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[A]], i64 32) ]
-; BUNDLES-NEXT:    ret i32 [[T0]]
-;
-  %t0 = load i32, ptr %a, align 4
-  %ptrint = ptrtoint ptr %a to i64
-  %maskedptr = and i64 %ptrint, 31
-  %maskcond = icmp eq i64 %maskedptr, 0
-  tail call void @llvm.assume(i1 %maskcond)
-  ret i32 %t0
-}
-
-; Same check as in @foo1, but make sure it works if the assume is first too.
-
-define i32 @foo2(ptr %a) #0 {
-; DEFAULT-LABEL: @foo2(
-; DEFAULT-NEXT:    [[PTRINT:%.*]] = ptrtoint ptr [[A:%.*]] to i64
-; DEFAULT-NEXT:    [[MASKEDPTR:%.*]] = and i64 [[PTRINT]], 31
-; DEFAULT-NEXT:    [[MASKCOND:%.*]] = icmp eq i64 [[MASKEDPTR]], 0
-; DEFAULT-NEXT:    tail call void @llvm.assume(i1 [[MASKCOND]])
-; DEFAULT-NEXT:    [[T0:%.*]] = load i32, ptr [[A]], align 4
-; DEFAULT-NEXT:    ret i32 [[T0]]
-;
-; BUNDLES-LABEL: @foo2(
-; BUNDLES-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[A:%.*]], i64 32) ]
-; BUNDLES-NEXT:    [[T0:%.*]] = load i32, ptr [[A]], align 4
-; BUNDLES-NEXT:    ret i32 [[T0]]
-;
-  %ptrint = ptrtoint ptr %a to i64
-  %maskedptr = and i64 %ptrint, 31
-  %maskcond = icmp eq i64 %maskedptr, 0
-  tail call void @llvm.assume(i1 %maskcond)
-  %t0 = load i32, ptr %a, align 4
-  ret i32 %t0
-}
-
-define i32 @simple(i32 %a) #1 {
-; CHECK-LABEL: @simple(
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[A:%.*]], 4
-; CHECK-NEXT:    tail call void @llvm.assume(i1 [[CMP]])
-; CHECK-NEXT:    ret i32 [[A]]
-;
-  %cmp = icmp eq i32 %a, 4
-  tail call void @llvm.assume(i1 %cmp)
-  ret i32 %a
-}
-
-define i32 @can1(i1 %a, i1 %b, i1 %c) {
-; CHECK-LABEL: @can1(
-; CHECK-NEXT:    call void @llvm.assume(i1 [[A:%.*]])
-; CHECK-NEXT:    call void @llvm.assume(i1 [[B:%.*]])
-; CHECK-NEXT:    call void @llvm.assume(i1 [[C:%.*]])
-; CHECK-NEXT:    ret i32 5
-;
-  %and1 = and i1 %a, %b
-  %and  = and i1 %and1, %c
-  tail call void @llvm.assume(i1 %and)
-  ret i32 5
-}
-
-define i32 @can1_logical(i1 %a, i1 %b, i1 %c) {
-; CHECK-LABEL: @can1_logical(
-; CHECK-NEXT:    call void @llvm.assume(i1 [[A:%.*]])
-; CHECK-NEXT:    call void @llvm.assume(i1 [[B:%.*]])
-; CHECK-NEXT:    call void @llvm.assume(i1 [[C:%.*]])
-; CHECK-NEXT:    ret i32 5
-;
-  %and1 = select i1 %a, i1 %b, i1 false
-  %and  = select i1 %and1, i1 %c, i1 false
-  tail call void @llvm.assume(i1 %and)
-  ret i32 5
-}
-
-define i32 @can2(i1 %a, i1 %b, i1 %c) {
-; CHECK-LABEL: @can2(
-; CHECK-NEXT:    [[TMP1:%.*]] = xor i1 [[A:%.*]], true
-; CHECK-NEXT:    call void @llvm.assume(i1 [[TMP1]])
-; CHECK-NEXT:    [[TMP2:%.*]] = xor i1 [[B:%.*]], true
-; CHECK-NEXT:    call void @llvm.assume(i1 [[TMP2]])
-; CHECK-NEXT:    ret i32 5
-;
-  %v = or i1 %a, %b
-  %w = xor i1 %v, 1
-  tail call void @llvm.assume(i1 %w)
-  ret i32 5
-}
-
-define i32 @can2_logical(i1 %a, i1 %b, i1 %c) {
-; CHECK-LABEL: @can2_logical(
-; CHECK-NEXT:    [[TMP1:%.*]] = xor i1 [[A:%.*]], true
-; CHECK-NEXT:    call void @llvm.assume(i1 [[TMP1]])
-; CHECK-NEXT:    [[TMP2:%.*]] = xor i1 [[B:%.*]], true
-; CHECK-NEXT:    call void @llvm.assume(i1 [[TMP2]])
-; CHECK-NEXT:    ret i32 5
-;
-  %v = select i1 %a, i1 true, i1 %b
-  %w = xor i1 %v, 1
-  tail call void @llvm.assume(i1 %w)
-  ret i32 5
-}
-
-define i32 @bar1(i32 %a) #0 {
-; CHECK-LABEL: @bar1(
-; CHECK-NEXT:    [[AND:%.*]] = and i32 [[A:%.*]], 7
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[AND]], 1
-; CHECK-NEXT:    tail call void @llvm.assume(i1 [[CMP]])
-; CHECK-NEXT:    ret i32 1
-;
-  %and1 = and i32 %a, 3
-  %and = and i32 %a, 7
-  %cmp = icmp eq i32 %and, 1
-  tail call void @llvm.assume(i1 %cmp)
-  ret i32 %and1
-}
-
-define i32 @bar2(i32 %a) #0 {
-; CHECK-LABEL: @bar2(
-; CHECK-NEXT:    [[AND:%.*]] = and i32 [[A:%.*]], 7
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[AND]], 1
-; CHECK-NEXT:    tail call void @llvm.assume(i1 [[CMP]])
-; CHECK-NEXT:    ret i32 1
-;
-  %and = and i32 %a, 7
-  %cmp = icmp eq i32 %and, 1
-  tail call void @llvm.assume(i1 %cmp)
-  %and1 = and i32 %a, 3
-  ret i32 %and1
-}
-
-define i32 @bar3(i32 %a, i1 %x, i1 %y) #0 {
-; CHECK-LABEL: @bar3(
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    tail call void @llvm.assume(i1 [[X:%.*]])
-; CHECK-NEXT:    [[AND:%.*]] = and i32 [[A:%.*]], 7
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[AND]], 1
-; CHECK-NEXT:    tail call void @llvm.assume(i1 [[CMP]])
-; CHECK-NEXT:    tail call void @llvm.assume(i1 [[Y:%.*]])
-; CHECK-NEXT:    ret i32 1
-;
-entry:
-  %and1 = and i32 %a, 3
-
-; Don't be fooled by other assumes around.
-
-  tail call void @llvm.assume(i1 %x)
-
-  %and = and i32 %a, 7
-  %cmp = icmp eq i32 %and, 1
-  tail call void @llvm.assume(i1 %cmp)
-
-  tail call void @llvm.assume(i1 %y)
-
-  ret i32 %and1
-}
-
-; If we allow recursive known bits queries based on
-; assumptions, we could do better here:
-; a == b and a & 7 == 1, so b & 7 == 1, so b & 3 == 1, so return 1.
-
-define i32 @known_bits_recursion_via_assumes(i32 %a, i32 %b) {
-; CHECK-LABEL: @known_bits_recursion_via_assumes(
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[B:%.*]], 3
-; CHECK-NEXT:    [[AND:%.*]] = and i32 [[A:%.*]], 7
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[AND]], 1
-; CHECK-NEXT:    tail call void @llvm.assume(i1 [[CMP]])
-; CHECK-NEXT:    [[CMP2:%.*]] = icmp eq i32 [[A]], [[B]]
-; CHECK-NEXT:    tail call void @llvm.assume(i1 [[CMP2]])
-; CHECK-NEXT:    ret i32 [[AND1]]
-;
-entry:
-  %and1 = and i32 %b, 3
-  %and = and i32 %a, 7
-  %cmp = icmp eq i32 %and, 1
-  tail call void @llvm.assume(i1 %cmp)
-  %cmp2 = icmp eq i32 %a, %b
-  tail call void @llvm.assume(i1 %cmp2)
-  ret i32 %and1
-}
-
-define i32 @icmp1(i32 %a) #0 {
-; CHECK-LABEL: @icmp1(
-; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[A:%.*]], 5
-; CHECK-NEXT:    tail call void @llvm.assume(i1 [[CMP]])
-; CHECK-NEXT:    [[CONV:%.*]] = zext i1 [[CMP]] to i32
-; CHECK-NEXT:    ret i32 [[CONV]]
-;
-  %cmp = icmp sgt i32 %a, 5
-  tail call void @llvm.assume(i1 %cmp)
-  %conv = zext i1 %cmp to i32
-  ret i32 %conv
-}
-
-define i32 @icmp2(i32 %a) #0 {
-; CHECK-LABEL: @icmp2(
-; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[A:%.*]], 5
-; CHECK-NEXT:    tail call void @llvm.assume(i1 [[CMP]])
-; CHECK-NEXT:    ret i32 0
-;
-  %cmp = icmp sgt i32 %a, 5
-  tail call void @llvm.assume(i1 %cmp)
-  %t0 = zext i1 %cmp to i32
-  %lnot.ext = xor i32 %t0, 1
-  ret i32 %lnot.ext
-}
-
-; If the 'not' of a condition is known true, then the condition must be false.
-
-define i1 @assume_not(i1 %cond) {
-; CHECK-LABEL: @assume_not(
-; CHECK-NEXT:    [[NOTCOND:%.*]] = xor i1 [[COND:%.*]], true
-; CHECK-NEXT:    call void @llvm.assume(i1 [[NOTCOND]])
-; CHECK-NEXT:    ret i1 [[COND]]
-;
-  %notcond = xor i1 %cond, true
-  call void @llvm.assume(i1 %notcond)
-  ret i1 %cond
-}
-
 declare void @escape(ptr %a)
 
-; Canonicalize a nonnull assumption on a load into metadata form.
-
-define i32 @bundle1(ptr %P) {
-; CHECK-LABEL: @bundle1(
-; CHECK-NEXT:    tail call void @llvm.assume(i1 true) [ "nonnull"(ptr [[P:%.*]]) ]
-; CHECK-NEXT:    [[LOAD:%.*]] = load i32, ptr [[P]], align 4
-; CHECK-NEXT:    ret i32 [[LOAD]]
-;
-  tail call void @llvm.assume(i1 true) ["nonnull"(ptr %P)]
-  %load = load i32, ptr %P
-  ret i32 %load
-}
-
-define i32 @bundle2(ptr %P) {
-; CHECK-LABEL: @bundle2(
-; CHECK-NEXT:    [[LOAD:%.*]] = load i32, ptr [[P:%.*]], align 4
-; CHECK-NEXT:    ret i32 [[LOAD]]
-;
-  tail call void @llvm.assume(i1 true) ["ignore"(ptr undef)]
-  %load = load i32, ptr %P
-  ret i32 %load
-}
+; Check that the assume has not been removed:
 
 define i1 @nonnull1(ptr %a) {
 ; CHECK-LABEL: @nonnull1(
-; CHECK-NEXT:    [[LOAD:%.*]] = load ptr, ptr [[A:%.*]], align 8
+; CHECK-NEXT:    [[LOAD:%.*]] = load ptr, ptr [[A:%.*]], align 8, !nonnull [[META6:![0-9]+]], !noundef [[META6]]
 ; CHECK-NEXT:    tail call void @escape(ptr nonnull [[LOAD]])
 ; CHECK-NEXT:    ret i1 false
+;
+; CHECK-DL-LABEL: @nonnull1(
+; CHECK-DL-NEXT:    [[LOAD:%.*]] = load ptr, ptr [[A:%.*]], align 8
+; CHECK-DL-NEXT:    tail call void @escape(ptr nonnull [[LOAD]])
+; CHECK-DL-NEXT:    ret i1 false
 ;
   %load = load ptr, ptr %a
   %cmp = icmp ne ptr %load, null
@@ -280,37 +35,42 @@ define i1 @nonnull1(ptr %a) {
   ret i1 %rval
 }
 
-; Make sure the above canonicalization applies only
-; to pointer types.  Doing otherwise would be illegal.
-
-define i1 @nonnull2(ptr %a) {
-; CHECK-LABEL: @nonnull2(
-; CHECK-NEXT:    [[LOAD:%.*]] = load i32, ptr [[A:%.*]], align 4
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[LOAD]], 0
-; CHECK-NEXT:    tail call void @llvm.assume(i1 [[CMP]])
-; CHECK-NEXT:    ret i1 false
-;
-  %load = load i32, ptr %a
-  %cmp = icmp ne i32 %load, 0
-  tail call void @llvm.assume(i1 %cmp)
-  %rval = icmp eq i32 %load, 0
-  ret i1 %rval
-}
-
 ; Make sure the above canonicalization does not trigger
 ; if the assume is control dependent on something else
 
 define i1 @nonnull3(ptr %a, i1 %control) {
 ; FIXME: in the BUNDLES version we could duplicate the load and keep the assume nonnull.
-; CHECK-LABEL: @nonnull3(
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    br i1 [[CONTROL:%.*]], label [[TAKEN:%.*]], label [[NOT_TAKEN:%.*]]
-; CHECK:       taken:
-; CHECK-NEXT:    ret i1 false
-; CHECK:       not_taken:
-; CHECK-NEXT:    [[LOAD:%.*]] = load ptr, ptr [[A:%.*]], align 8
-; CHECK-NEXT:    [[RVAL_2:%.*]] = icmp sgt ptr [[LOAD]], null
-; CHECK-NEXT:    ret i1 [[RVAL_2]]
+; DEFAULT-LABEL: @nonnull3(
+; DEFAULT-NEXT:  entry:
+; DEFAULT-NEXT:    [[LOAD:%.*]] = load ptr, ptr [[A:%.*]], align 8
+; DEFAULT-NEXT:    [[CMP:%.*]] = icmp ne ptr [[LOAD]], null
+; DEFAULT-NEXT:    br i1 [[CONTROL:%.*]], label [[TAKEN:%.*]], label [[NOT_TAKEN:%.*]]
+; DEFAULT:       taken:
+; DEFAULT-NEXT:    tail call void @llvm.assume(i1 [[CMP]])
+; DEFAULT-NEXT:    ret i1 false
+; DEFAULT:       not_taken:
+; DEFAULT-NEXT:    [[RVAL_2:%.*]] = icmp sgt ptr [[LOAD]], null
+; DEFAULT-NEXT:    ret i1 [[RVAL_2]]
+;
+; CHECK-DL-LABEL: @nonnull3(
+; CHECK-DL-NEXT:  entry:
+; CHECK-DL-NEXT:    br i1 [[CONTROL:%.*]], label [[TAKEN:%.*]], label [[NOT_TAKEN:%.*]]
+; CHECK-DL:       taken:
+; CHECK-DL-NEXT:    ret i1 false
+; CHECK-DL:       not_taken:
+; CHECK-DL-NEXT:    [[LOAD:%.*]] = load ptr, ptr [[A:%.*]], align 8
+; CHECK-DL-NEXT:    [[RVAL_2:%.*]] = icmp sgt ptr [[LOAD]], null
+; CHECK-DL-NEXT:    ret i1 [[RVAL_2]]
+;
+; BUNDLES-LABEL: @nonnull3(
+; BUNDLES-NEXT:  entry:
+; BUNDLES-NEXT:    br i1 [[CONTROL:%.*]], label [[TAKEN:%.*]], label [[NOT_TAKEN:%.*]]
+; BUNDLES:       taken:
+; BUNDLES-NEXT:    ret i1 false
+; BUNDLES:       not_taken:
+; BUNDLES-NEXT:    [[LOAD:%.*]] = load ptr, ptr [[A:%.*]], align 8
+; BUNDLES-NEXT:    [[RVAL_2:%.*]] = icmp sgt ptr [[LOAD]], null
+; BUNDLES-NEXT:    ret i1 [[RVAL_2]]
 ;
 entry:
   %load = load ptr, ptr %a
@@ -330,10 +90,23 @@ not_taken:
 ; interrupted by an exception being thrown
 
 define i1 @nonnull4(ptr %a) {
-; CHECK-LABEL: @nonnull4(
-; CHECK-NEXT:    [[LOAD:%.*]] = load ptr, ptr [[A:%.*]], align 8
-; CHECK-NEXT:    tail call void @escape(ptr nonnull [[LOAD]])
-; CHECK-NEXT:    ret i1 false
+; DEFAULT-LABEL: @nonnull4(
+; DEFAULT-NEXT:    [[LOAD:%.*]] = load ptr, ptr [[A:%.*]], align 8
+; DEFAULT-NEXT:    tail call void @escape(ptr [[LOAD]])
+; DEFAULT-NEXT:    [[CMP:%.*]] = icmp ne ptr [[LOAD]], null
+; DEFAULT-NEXT:    tail call void @llvm.assume(i1 [[CMP]])
+; DEFAULT-NEXT:    ret i1 false
+;
+; CHECK-DL-LABEL: @nonnull4(
+; CHECK-DL-NEXT:    [[LOAD:%.*]] = load ptr, ptr [[A:%.*]], align 8
+; CHECK-DL-NEXT:    tail call void @escape(ptr nonnull [[LOAD]])
+; CHECK-DL-NEXT:    ret i1 false
+;
+; BUNDLES-LABEL: @nonnull4(
+; BUNDLES-NEXT:    [[LOAD:%.*]] = load ptr, ptr [[A:%.*]], align 8
+; BUNDLES-NEXT:    tail call void @escape(ptr [[LOAD]])
+; BUNDLES-NEXT:    call void @llvm.assume(i1 true) [ "nonnull"(ptr [[LOAD]]) ]
+; BUNDLES-NEXT:    ret i1 false
 ;
   %load = load ptr, ptr %a
   ;; This call may throw!
@@ -346,10 +119,17 @@ define i1 @nonnull4(ptr %a) {
 define i1 @nonnull5(ptr %a) {
 ; CHECK-LABEL: @nonnull5(
 ; CHECK-NEXT:    [[LOAD:%.*]] = load ptr, ptr [[A:%.*]], align 8
-; CHECK-NEXT:    tail call void @escape(ptr nonnull [[LOAD]])
+; CHECK-NEXT:    tail call void @escape(ptr [[LOAD]])
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp slt ptr [[LOAD]], null
 ; CHECK-NEXT:    tail call void @llvm.assume(i1 [[CMP]])
 ; CHECK-NEXT:    ret i1 false
+;
+; CHECK-DL-LABEL: @nonnull5(
+; CHECK-DL-NEXT:    [[LOAD:%.*]] = load ptr, ptr [[A:%.*]], align 8
+; CHECK-DL-NEXT:    tail call void @escape(ptr nonnull [[LOAD]])
+; CHECK-DL-NEXT:    [[CMP:%.*]] = icmp slt ptr [[LOAD]], null
+; CHECK-DL-NEXT:    tail call void @llvm.assume(i1 [[CMP]])
+; CHECK-DL-NEXT:    ret i1 false
 ;
   %load = load ptr, ptr %a
   ;; This call may throw!
@@ -361,74 +141,38 @@ define i1 @nonnull5(ptr %a) {
   ret i1 %rval
 }
 
-; PR35846 - https://bugs.llvm.org/show_bug.cgi?id=35846
-
-define i32 @assumption_conflicts_with_known_bits(i32 %a, i32 %b) {
-; CHECK-LABEL: @assumption_conflicts_with_known_bits(
-; CHECK-NEXT:    store i1 true, ptr poison, align 1
-; CHECK-NEXT:    ret i32 poison
-;
-  %and1 = and i32 %b, 3
-  %B1 = lshr i32 %and1, %and1
-  %B3 = shl nuw nsw i32 %and1, %B1
-  %cmp = icmp eq i32 %B3, 1
-  tail call void @llvm.assume(i1 %cmp)
-  %cmp2 = icmp eq i32 %B1, %B3
-  tail call void @llvm.assume(i1 %cmp2)
-  ret i32 %and1
-}
-
-; PR37726 - https://bugs.llvm.org/show_bug.cgi?id=37726
-; There's a loophole in eliminating a redundant assumption when
-; we have conflicting assumptions. Verify that debuginfo doesn't
-; get in the way of the fold.
-
-define void @debug_interference(i8 %x) {
-; CHECK-LABEL: @debug_interference(
-; CHECK-NEXT:    tail call void @llvm.dbg.value(metadata i32 5, metadata [[META6:![0-9]+]], metadata !DIExpression()), !dbg [[DBG8:![0-9]+]]
-; CHECK-NEXT:    store i1 true, ptr poison, align 1
-; CHECK-NEXT:    ret void
-;
-  %cmp1 = icmp eq i8 %x, 0
-  %cmp2 = icmp ne i8 %x, 0
-  tail call void @llvm.assume(i1 %cmp1)
-  tail call void @llvm.dbg.value(metadata i32 5, metadata !1, metadata !DIExpression()), !dbg !9
-  tail call void @llvm.assume(i1 %cmp1)
-  tail call void @llvm.dbg.value(metadata i32 5, metadata !1, metadata !DIExpression()), !dbg !9
-  tail call void @llvm.assume(i1 %cmp2)
-  tail call void @llvm.dbg.value(metadata i32 5, metadata !1, metadata !DIExpression()), !dbg !9
-  tail call void @llvm.assume(i1 %cmp2)
-  ret void
-}
-
-; This would crash.
-; Does it ever make sense to peek through a bitcast of the icmp operand?
-
-define i32 @PR40940(<4 x i8> %x) {
-; CHECK-LABEL: @PR40940(
-; CHECK-NEXT:    [[SHUF:%.*]] = shufflevector <4 x i8> [[X:%.*]], <4 x i8> poison, <4 x i32> <i32 1, i32 1, i32 2, i32 3>
-; CHECK-NEXT:    [[T2:%.*]] = bitcast <4 x i8> [[SHUF]] to i32
-; CHECK-NEXT:    [[T3:%.*]] = icmp ult i32 [[T2]], 65536
-; CHECK-NEXT:    call void @llvm.assume(i1 [[T3]])
-; CHECK-NEXT:    ret i32 [[T2]]
-;
-  %shuf = shufflevector <4 x i8> %x, <4 x i8> undef, <4 x i32> <i32 1, i32 1, i32 2, i32 3>
-  %t2 = bitcast <4 x i8> %shuf to i32
-  %t3 = icmp ult i32 %t2, 65536
-  call void @llvm.assume(i1 %t3)
-  ret i32 %t2
-}
-
 define i1 @nonnull3A(ptr %a, i1 %control) {
-; CHECK-LABEL: @nonnull3A(
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    br i1 [[CONTROL:%.*]], label [[TAKEN:%.*]], label [[NOT_TAKEN:%.*]]
-; CHECK:       taken:
-; CHECK-NEXT:    ret i1 true
-; CHECK:       not_taken:
-; CHECK-NEXT:    [[LOAD:%.*]] = load ptr, ptr [[A:%.*]], align 8
-; CHECK-NEXT:    [[RVAL_2:%.*]] = icmp sgt ptr [[LOAD]], null
-; CHECK-NEXT:    ret i1 [[RVAL_2]]
+; DEFAULT-LABEL: @nonnull3A(
+; DEFAULT-NEXT:  entry:
+; DEFAULT-NEXT:    [[LOAD:%.*]] = load ptr, ptr [[A:%.*]], align 8
+; DEFAULT-NEXT:    br i1 [[CONTROL:%.*]], label [[TAKEN:%.*]], label [[NOT_TAKEN:%.*]]
+; DEFAULT:       taken:
+; DEFAULT-NEXT:    [[CMP:%.*]] = icmp ne ptr [[LOAD]], null
+; DEFAULT-NEXT:    call void @llvm.assume(i1 [[CMP]])
+; DEFAULT-NEXT:    ret i1 [[CMP]]
+; DEFAULT:       not_taken:
+; DEFAULT-NEXT:    [[RVAL_2:%.*]] = icmp sgt ptr [[LOAD]], null
+; DEFAULT-NEXT:    ret i1 [[RVAL_2]]
+;
+; CHECK-DL-LABEL: @nonnull3A(
+; CHECK-DL-NEXT:  entry:
+; CHECK-DL-NEXT:    br i1 [[CONTROL:%.*]], label [[TAKEN:%.*]], label [[NOT_TAKEN:%.*]]
+; CHECK-DL:       taken:
+; CHECK-DL-NEXT:    ret i1 true
+; CHECK-DL:       not_taken:
+; CHECK-DL-NEXT:    [[LOAD:%.*]] = load ptr, ptr [[A:%.*]], align 8
+; CHECK-DL-NEXT:    [[RVAL_2:%.*]] = icmp sgt ptr [[LOAD]], null
+; CHECK-DL-NEXT:    ret i1 [[RVAL_2]]
+;
+; BUNDLES-LABEL: @nonnull3A(
+; BUNDLES-NEXT:  entry:
+; BUNDLES-NEXT:    br i1 [[CONTROL:%.*]], label [[TAKEN:%.*]], label [[NOT_TAKEN:%.*]]
+; BUNDLES:       taken:
+; BUNDLES-NEXT:    ret i1 true
+; BUNDLES:       not_taken:
+; BUNDLES-NEXT:    [[LOAD:%.*]] = load ptr, ptr [[A:%.*]], align 8
+; BUNDLES-NEXT:    [[RVAL_2:%.*]] = icmp sgt ptr [[LOAD]], null
+; BUNDLES-NEXT:    ret i1 [[RVAL_2]]
 ;
 entry:
   %load = load ptr, ptr %a
@@ -446,15 +190,26 @@ not_taken:
 define i1 @nonnull3B(ptr %a, i1 %control) {
 ; CHECK-LABEL: @nonnull3B(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[LOAD:%.*]] = load ptr, ptr [[A:%.*]], align 8
 ; CHECK-NEXT:    br i1 [[CONTROL:%.*]], label [[TAKEN:%.*]], label [[NOT_TAKEN:%.*]]
 ; CHECK:       taken:
-; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "nonnull"(ptr [[LOAD]]) ]
-; CHECK-NEXT:    ret i1 true
+; CHECK-NEXT:    [[LOAD:%.*]] = load ptr, ptr [[A:%.*]], align 8
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne ptr [[LOAD]], null
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]]) [ "nonnull"(ptr [[LOAD]]) ]
+; CHECK-NEXT:    ret i1 [[CMP]]
 ; CHECK:       not_taken:
-; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "nonnull"(ptr [[LOAD]]) ]
 ; CHECK-NEXT:    ret i1 [[CONTROL]]
 ;
+; CHECK-DL-LABEL: @nonnull3B(
+; CHECK-DL-NEXT:  entry:
+; CHECK-DL-NEXT:    [[LOAD:%.*]] = load ptr, ptr [[A:%.*]], align 8
+; CHECK-DL-NEXT:    br i1 [[CONTROL:%.*]], label [[TAKEN:%.*]], label [[NOT_TAKEN:%.*]]
+; CHECK-DL:       taken:
+; CHECK-DL-NEXT:    call void @llvm.assume(i1 true) [ "nonnull"(ptr [[LOAD]]) ]
+; CHECK-DL-NEXT:    ret i1 true
+; CHECK-DL:       not_taken:
+; CHECK-DL-NEXT:    call void @llvm.assume(i1 true) [ "nonnull"(ptr [[LOAD]]) ]
+; CHECK-DL-NEXT:    ret i1 [[CONTROL]]
+;
 entry:
   %load = load ptr, ptr %a
   %cmp = icmp ne ptr %load, null
@@ -472,17 +227,30 @@ declare i1 @tmp1(i1)
 define i1 @nonnull3C(ptr %a, i1 %control) {
 ; CHECK-LABEL: @nonnull3C(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[LOAD:%.*]] = load ptr, ptr [[A:%.*]], align 8
 ; CHECK-NEXT:    br i1 [[CONTROL:%.*]], label [[TAKEN:%.*]], label [[NOT_TAKEN:%.*]]
 ; CHECK:       taken:
-; CHECK-NEXT:    [[CMP2:%.*]] = call i1 @tmp1(i1 true)
+; CHECK-NEXT:    [[LOAD:%.*]] = load ptr, ptr [[A:%.*]], align 8
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne ptr [[LOAD]], null
+; CHECK-NEXT:    [[CMP2:%.*]] = call i1 @tmp1(i1 [[CMP]])
 ; CHECK-NEXT:    br label [[EXIT:%.*]]
 ; CHECK:       exit:
-; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "nonnull"(ptr [[LOAD]]) ]
 ; CHECK-NEXT:    ret i1 [[CMP2]]
 ; CHECK:       not_taken:
 ; CHECK-NEXT:    ret i1 [[CONTROL]]
 ;
+; CHECK-DL-LABEL: @nonnull3C(
+; CHECK-DL-NEXT:  entry:
+; CHECK-DL-NEXT:    [[LOAD:%.*]] = load ptr, ptr [[A:%.*]], align 8
+; CHECK-DL-NEXT:    br i1 [[CONTROL:%.*]], label [[TAKEN:%.*]], label [[NOT_TAKEN:%.*]]
+; CHECK-DL:       taken:
+; CHECK-DL-NEXT:    [[CMP2:%.*]] = call i1 @tmp1(i1 true)
+; CHECK-DL-NEXT:    br label [[EXIT:%.*]]
+; CHECK-DL:       exit:
+; CHECK-DL-NEXT:    call void @llvm.assume(i1 true) [ "nonnull"(ptr [[LOAD]]) ]
+; CHECK-DL-NEXT:    ret i1 [[CMP2]]
+; CHECK-DL:       not_taken:
+; CHECK-DL-NEXT:    ret i1 [[CONTROL]]
+;
 entry:
   %load = load ptr, ptr %a
   %cmp = icmp ne ptr %load, null
@@ -502,17 +270,30 @@ not_taken:
 define i1 @nonnull3D(ptr %a, i1 %control) {
 ; CHECK-LABEL: @nonnull3D(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[LOAD:%.*]] = load ptr, ptr [[A:%.*]], align 8
 ; CHECK-NEXT:    br i1 [[CONTROL:%.*]], label [[TAKEN:%.*]], label [[NOT_TAKEN:%.*]]
 ; CHECK:       taken:
-; CHECK-NEXT:    [[CMP2:%.*]] = call i1 @tmp1(i1 true)
+; CHECK-NEXT:    [[LOAD:%.*]] = load ptr, ptr [[A:%.*]], align 8
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne ptr [[LOAD]], null
+; CHECK-NEXT:    [[CMP2:%.*]] = call i1 @tmp1(i1 [[CMP]])
 ; CHECK-NEXT:    br label [[EXIT:%.*]]
 ; CHECK:       exit:
 ; CHECK-NEXT:    ret i1 [[CMP2]]
 ; CHECK:       not_taken:
-; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "nonnull"(ptr [[LOAD]]) ]
 ; CHECK-NEXT:    ret i1 [[CONTROL]]
 ;
+; CHECK-DL-LABEL: @nonnull3D(
+; CHECK-DL-NEXT:  entry:
+; CHECK-DL-NEXT:    [[LOAD:%.*]] = load ptr, ptr [[A:%.*]], align 8
+; CHECK-DL-NEXT:    br i1 [[CONTROL:%.*]], label [[TAKEN:%.*]], label [[NOT_TAKEN:%.*]]
+; CHECK-DL:       taken:
+; CHECK-DL-NEXT:    [[CMP2:%.*]] = call i1 @tmp1(i1 true)
+; CHECK-DL-NEXT:    br label [[EXIT:%.*]]
+; CHECK-DL:       exit:
+; CHECK-DL-NEXT:    ret i1 [[CMP2]]
+; CHECK-DL:       not_taken:
+; CHECK-DL-NEXT:    call void @llvm.assume(i1 true) [ "nonnull"(ptr [[LOAD]]) ]
+; CHECK-DL-NEXT:    ret i1 [[CONTROL]]
+;
 entry:
   %load = load ptr, ptr %a
   %cmp = icmp ne ptr %load, null
@@ -527,402 +308,6 @@ not_taken:
   ret i1 %control
 }
 
-
-define void @always_true_assumption() {
-; CHECK-LABEL: @always_true_assumption(
-; CHECK-NEXT:    ret void
-;
-  call void @llvm.assume(i1 true)
-  ret void
-}
-
-; The alloca guarantees that the low bits of %a are zero because of alignment.
-; The assume says the opposite. Make sure we don't crash.
-
-define i64 @PR31809() {
-; CHECK-LABEL: @PR31809(
-; CHECK-NEXT:    store i1 true, ptr poison, align 1
-; CHECK-NEXT:    ret i64 poison
-;
-  %a = alloca i32
-  %t1 = ptrtoint ptr %a to i64
-  %cond = icmp eq i64 %t1, 3
-  call void @llvm.assume(i1 %cond)
-  ret i64 %t1
-}
-
-; Similar to above: there's no way to know which assumption is truthful,
-; so just don't crash.
-
-define i8 @conflicting_assumptions(i8 %x){
-; CHECK-LABEL: @conflicting_assumptions(
-; CHECK-NEXT:    store i1 true, ptr poison, align 1
-; CHECK-NEXT:    ret i8 poison
-;
-  %add = add i8 %x, 1
-  %cond1 = icmp eq i8 %x, 3
-  call void @llvm.assume(i1 %cond1)
-  %cond2 = icmp eq i8 %x, 4
-  call void @llvm.assume(i1 %cond2)
-  ret i8 %add
-}
-
-; Another case of conflicting assumptions. This would crash because we'd
-; try to set more known bits than existed in the known bits struct.
-
-define void @PR36270(i32 %b) {
-; CHECK-LABEL: @PR36270(
-; CHECK-NEXT:    unreachable
-;
-  %B7 = xor i32 -1, 2147483647
-  %and1 = and i32 %b, 3
-  %B12 = lshr i32 %B7, %and1
-  %C1 = icmp ult i32 %and1, %B12
-  tail call void @llvm.assume(i1 %C1)
-  %cmp2 = icmp eq i32 0, %B12
-  tail call void @llvm.assume(i1 %cmp2)
-  unreachable
-}
-
-; PR47416
-
-define i32 @unreachable_assume(i32 %x, i32 %y) {
-; CHECK-LABEL: @unreachable_assume(
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[CMP0:%.*]] = icmp sgt i32 [[X:%.*]], 1
-; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i32 [[Y:%.*]], 1
-; CHECK-NEXT:    [[OR:%.*]] = or i1 [[CMP0]], [[CMP1]]
-; CHECK-NEXT:    tail call void @llvm.assume(i1 [[OR]])
-; CHECK-NEXT:    [[CMP2:%.*]] = icmp eq i32 [[X]], 1
-; CHECK-NEXT:    br i1 [[CMP2]], label [[IF:%.*]], label [[EXIT:%.*]]
-; CHECK:       if:
-; CHECK-NEXT:    [[A:%.*]] = and i32 [[Y]], -2
-; CHECK-NEXT:    [[CMP3:%.*]] = icmp ne i32 [[A]], 104
-; CHECK-NEXT:    tail call void @llvm.assume(i1 [[CMP3]])
-; CHECK-NEXT:    br label [[EXIT]]
-; CHECK:       exit:
-; CHECK-NEXT:    unreachable
-;
-entry:
-  %cmp0 = icmp sgt i32 %x, 1
-  %cmp1 = icmp eq i32 %y, 1
-  %or = or i1 %cmp0, %cmp1
-  tail call void @llvm.assume(i1 %or)
-  %cmp2 = icmp eq i32 %x, 1
-  br i1 %cmp2, label %if, label %exit
-
-if:
-  %a = and i32 %y, -2
-  %cmp3 = icmp ne i32 %a, 104
-  tail call void @llvm.assume(i1 %cmp3)
-  br label %exit
-
-exit:
-  %cmp4 = icmp eq i32 %x, 2
-  tail call void @llvm.assume(i1 %cmp4)
-  unreachable
-}
-
-define i32 @unreachable_assume_logical(i32 %x, i32 %y) {
-; CHECK-LABEL: @unreachable_assume_logical(
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[CMP0:%.*]] = icmp sgt i32 [[X:%.*]], 1
-; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i32 [[Y:%.*]], 1
-; CHECK-NEXT:    [[OR:%.*]] = select i1 [[CMP0]], i1 true, i1 [[CMP1]]
-; CHECK-NEXT:    tail call void @llvm.assume(i1 [[OR]])
-; CHECK-NEXT:    [[CMP2:%.*]] = icmp eq i32 [[X]], 1
-; CHECK-NEXT:    br i1 [[CMP2]], label [[IF:%.*]], label [[EXIT:%.*]]
-; CHECK:       if:
-; CHECK-NEXT:    [[A:%.*]] = and i32 [[Y]], -2
-; CHECK-NEXT:    [[CMP3:%.*]] = icmp ne i32 [[A]], 104
-; CHECK-NEXT:    tail call void @llvm.assume(i1 [[CMP3]])
-; CHECK-NEXT:    br label [[EXIT]]
-; CHECK:       exit:
-; CHECK-NEXT:    unreachable
-;
-entry:
-  %cmp0 = icmp sgt i32 %x, 1
-  %cmp1 = icmp eq i32 %y, 1
-  %or = select i1 %cmp0, i1 true, i1 %cmp1
-  tail call void @llvm.assume(i1 %or)
-  %cmp2 = icmp eq i32 %x, 1
-  br i1 %cmp2, label %if, label %exit
-
-if:
-  %a = and i32 %y, -2
-  %cmp3 = icmp ne i32 %a, 104
-  tail call void @llvm.assume(i1 %cmp3)
-  br label %exit
-
-exit:
-  %cmp4 = icmp eq i32 %x, 2
-  tail call void @llvm.assume(i1 %cmp4)
-  unreachable
-}
-
-define i32 @unreachable_assumes_and_store(i32 %x, i32 %y, ptr %p) {
-; CHECK-LABEL: @unreachable_assumes_and_store(
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[CMP0:%.*]] = icmp sgt i32 [[X:%.*]], 1
-; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i32 [[Y:%.*]], 1
-; CHECK-NEXT:    [[OR:%.*]] = or i1 [[CMP0]], [[CMP1]]
-; CHECK-NEXT:    tail call void @llvm.assume(i1 [[OR]])
-; CHECK-NEXT:    [[CMP2:%.*]] = icmp eq i32 [[X]], 1
-; CHECK-NEXT:    br i1 [[CMP2]], label [[IF:%.*]], label [[EXIT:%.*]]
-; CHECK:       if:
-; CHECK-NEXT:    [[A:%.*]] = and i32 [[Y]], -2
-; CHECK-NEXT:    [[CMP3:%.*]] = icmp ne i32 [[A]], 104
-; CHECK-NEXT:    tail call void @llvm.assume(i1 [[CMP3]])
-; CHECK-NEXT:    br label [[EXIT]]
-; CHECK:       exit:
-; CHECK-NEXT:    unreachable
-;
-entry:
-  %cmp0 = icmp sgt i32 %x, 1
-  %cmp1 = icmp eq i32 %y, 1
-  %or = or i1 %cmp0, %cmp1
-  tail call void @llvm.assume(i1 %or)
-  %cmp2 = icmp eq i32 %x, 1
-  br i1 %cmp2, label %if, label %exit
-
-if:
-  %a = and i32 %y, -2
-  %cmp3 = icmp ne i32 %a, 104
-  tail call void @llvm.assume(i1 %cmp3)
-  br label %exit
-
-exit:
-  %cmp4 = icmp eq i32 %x, 2
-  tail call void @llvm.assume(i1 %cmp4)
-  %cmp5 = icmp ugt i32 %y, 42
-  tail call void @llvm.assume(i1 %cmp5)
-  store i32 %x, ptr %p
-  unreachable
-}
-
-define i32 @unreachable_assumes_and_store_logical(i32 %x, i32 %y, ptr %p) {
-; CHECK-LABEL: @unreachable_assumes_and_store_logical(
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[CMP0:%.*]] = icmp sgt i32 [[X:%.*]], 1
-; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i32 [[Y:%.*]], 1
-; CHECK-NEXT:    [[OR:%.*]] = select i1 [[CMP0]], i1 true, i1 [[CMP1]]
-; CHECK-NEXT:    tail call void @llvm.assume(i1 [[OR]])
-; CHECK-NEXT:    [[CMP2:%.*]] = icmp eq i32 [[X]], 1
-; CHECK-NEXT:    br i1 [[CMP2]], label [[IF:%.*]], label [[EXIT:%.*]]
-; CHECK:       if:
-; CHECK-NEXT:    [[A:%.*]] = and i32 [[Y]], -2
-; CHECK-NEXT:    [[CMP3:%.*]] = icmp ne i32 [[A]], 104
-; CHECK-NEXT:    tail call void @llvm.assume(i1 [[CMP3]])
-; CHECK-NEXT:    br label [[EXIT]]
-; CHECK:       exit:
-; CHECK-NEXT:    unreachable
-;
-entry:
-  %cmp0 = icmp sgt i32 %x, 1
-  %cmp1 = icmp eq i32 %y, 1
-  %or = select i1 %cmp0, i1 true, i1 %cmp1
-  tail call void @llvm.assume(i1 %or)
-  %cmp2 = icmp eq i32 %x, 1
-  br i1 %cmp2, label %if, label %exit
-
-if:
-  %a = and i32 %y, -2
-  %cmp3 = icmp ne i32 %a, 104
-  tail call void @llvm.assume(i1 %cmp3)
-  br label %exit
-
-exit:
-  %cmp4 = icmp eq i32 %x, 2
-  tail call void @llvm.assume(i1 %cmp4)
-  %cmp5 = icmp ugt i32 %y, 42
-  tail call void @llvm.assume(i1 %cmp5)
-  store i32 %x, ptr %p
-  unreachable
-}
-
-define void @canonicalize_assume(ptr %0) {
-; DEFAULT-LABEL: @canonicalize_assume(
-; DEFAULT-NEXT:    [[TMP2:%.*]] = getelementptr inbounds i8, ptr [[TMP0:%.*]], i64 8
-; DEFAULT-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[TMP2]], i64 16) ]
-; DEFAULT-NEXT:    ret void
-;
-; BUNDLES-LABEL: @canonicalize_assume(
-; BUNDLES-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[TMP0:%.*]], i64 8) ]
-; BUNDLES-NEXT:    ret void
-;
-  %2 = getelementptr inbounds i32, ptr %0, i64 2
-  call void @llvm.assume(i1 true) [ "align"(ptr %2, i64 16) ]
-  ret void
-}
-
-define void @assume_makes_and_known_assume_on_arg(ptr %p, i32 %x) {
-; CHECK-LABEL: @assume_makes_and_known_assume_on_arg(
-; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], 1
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[AND]], 0
-; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
-; CHECK-NEXT:    store i32 0, ptr [[P:%.*]], align 4
-; CHECK-NEXT:    ret void
-;
-  %and = and i32 %x, 1
-  %cmp = icmp eq i32 %and, 0
-  call void @llvm.assume(i1 %cmp)
-  %and2 = and i32 %x, 1
-  store i32 %and2, ptr %p
-  ret void
-}
-
-define void @assume_makes_and_known_assume_on_mul(ptr %p, i32 %a, i32 %b) {
-; CHECK-LABEL: @assume_makes_and_known_assume_on_mul(
-; CHECK-NEXT:    [[X:%.*]] = mul i32 [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X]], 1
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[AND]], 0
-; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
-; CHECK-NEXT:    store i32 0, ptr [[P:%.*]], align 4
-; CHECK-NEXT:    ret void
-;
-  %x = mul i32 %a, %b
-  %and = and i32 %x, 1
-  %cmp = icmp eq i32 %and, 0
-  call void @llvm.assume(i1 %cmp)
-  %and2 = and i32 %x, 1
-  store i32 %and2, ptr %p
-  ret void
-}
-
-define void @assume_makes_and_known_assume_on_bitwise(ptr %p, i32 %a, i32 %b) {
-; CHECK-LABEL: @assume_makes_and_known_assume_on_bitwise(
-; CHECK-NEXT:    [[X:%.*]] = or i32 [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X]], 1
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[AND]], 0
-; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
-; CHECK-NEXT:    store i32 0, ptr [[P:%.*]], align 4
-; CHECK-NEXT:    ret void
-;
-  %x = or i32 %a, %b
-  %and = and i32 %x, 1
-  %cmp = icmp eq i32 %and, 0
-  call void @llvm.assume(i1 %cmp)
-  %and2 = and i32 %x, 1
-  store i32 %and2, ptr %p
-  ret void
-}
-
-define i32 @range_16_31_top28(i32 %x) {
-; CHECK-LABEL: @range_16_31_top28(
-; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[X:%.*]], -16
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[TMP1]], 16
-; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
-; CHECK-NEXT:    ret i32 16
-;
-  %add = add i32 %x, -16
-  %cmp = icmp ult i32 %add, 16
-  call void @llvm.assume(i1 %cmp)
-  %res = and i32 %x, u0xfffffff0
-  ret i32 %res
-}
-
-define i32 @range_16_31_top29(i32 %x) {
-; CHECK-LABEL: @range_16_31_top29(
-; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[X:%.*]], -16
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[TMP1]], 16
-; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
-; CHECK-NEXT:    [[RES:%.*]] = and i32 [[X]], 24
-; CHECK-NEXT:    ret i32 [[RES]]
-;
-  %add = add i32 %x, -16
-  %cmp = icmp ult i32 %add, 16
-  call void @llvm.assume(i1 %cmp)
-  %res = and i32 %x, u0xfffffff8
-  ret i32 %res
-}
-
-define i32 @range_16_30_top28(i32 %x) {
-; CHECK-LABEL: @range_16_30_top28(
-; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[X:%.*]], -16
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[ADD]], 15
-; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
-; CHECK-NEXT:    ret i32 16
-;
-  %add = add i32 %x, -16
-  %cmp = icmp ult i32 %add, 15
-  call void @llvm.assume(i1 %cmp)
-  %res = and i32 %x, u0xfffffff0
-  ret i32 %res
-}
-
-define i32 @range_16_32_top28(i32 %x) {
-; CHECK-LABEL: @range_16_32_top28(
-; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[X:%.*]], -16
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[ADD]], 17
-; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
-; CHECK-NEXT:    [[RES:%.*]] = and i32 [[X]], 48
-; CHECK-NEXT:    ret i32 [[RES]]
-;
-  %add = add i32 %x, -16
-  %cmp = icmp ult i32 %add, 17
-  call void @llvm.assume(i1 %cmp)
-  %res = and i32 %x, u0xfffffff0
-  ret i32 %res
-}
-
-define i32 @range_16_32_top27(i32 %x) {
-; CHECK-LABEL: @range_16_32_top27(
-; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[X:%.*]], -16
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[ADD]], 17
-; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
-; CHECK-NEXT:    [[RES:%.*]] = and i32 [[X]], 32
-; CHECK-NEXT:    ret i32 [[RES]]
-;
-  %add = add i32 %x, -16
-  %cmp = icmp ult i32 %add, 17
-  call void @llvm.assume(i1 %cmp)
-  %res = and i32 %x, u0xffffffe0
-  ret i32 %res
-}
-
-define i32 @range_16_32_top26(i32 %x) {
-; CHECK-LABEL: @range_16_32_top26(
-; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[X:%.*]], -16
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[ADD]], 17
-; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
-; CHECK-NEXT:    ret i32 0
-;
-  %add = add i32 %x, -16
-  %cmp = icmp ult i32 %add, 17
-  call void @llvm.assume(i1 %cmp)
-  %res = and i32 %x, u0xffffffc0
-  ret i32 %res
-}
-
-define i32 @range_15_31_top28(i32 %x) {
-; CHECK-LABEL: @range_15_31_top28(
-; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[X:%.*]], -15
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[ADD]], 16
-; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
-; CHECK-NEXT:    [[RES:%.*]] = and i32 [[X]], 16
-; CHECK-NEXT:    ret i32 [[RES]]
-;
-  %add = add i32 %x, -15
-  %cmp = icmp ult i32 %add, 16
-  call void @llvm.assume(i1 %cmp)
-  %res = and i32 %x, u0xfffffff0
-  ret i32 %res
-}
-
-define i32 @range_15_31_top27(i32 %x) {
-; CHECK-LABEL: @range_15_31_top27(
-; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[X:%.*]], -15
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[ADD]], 16
-; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
-; CHECK-NEXT:    ret i32 0
-;
-  %add = add i32 %x, -15
-  %cmp = icmp ult i32 %add, 16
-  call void @llvm.assume(i1 %cmp)
-  %res = and i32 %x, u0xffffffe0
-  ret i32 %res
-}
-
 declare void @llvm.dbg.value(metadata, metadata, metadata)
 
 !llvm.dbg.cu = !{!0}
@@ -942,3 +327,6 @@ declare void @llvm.dbg.value(metadata, metadata, metadata)
 attributes #0 = { nounwind uwtable }
 attributes #1 = { nounwind }
 
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; BUNDLES-DL: {{.*}}
+; DEFAULT-DL: {{.*}}
diff --git a/llvm/test/Transforms/InstCombine/assume-icmp-null-select-dl-sentinel.ll b/llvm/test/Transforms/InstCombine/assume-icmp-null-select-dl-sentinel.ll
index d49b6b30afcba..73aa9b64f6a61 100755
--- a/llvm/test/Transforms/InstCombine/assume-icmp-null-select-dl-sentinel.ll
+++ b/llvm/test/Transforms/InstCombine/assume-icmp-null-select-dl-sentinel.ll
@@ -1,27 +1,21 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
 ; RUN: opt < %s -passes=instcombine -S | FileCheck %s
-target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-z0:1-z2:neg1-z3:neg1-z5:neg1-S128"
-target triple = "x86_64-unknown-linux-gnu"
-
-define ptr @example(ptr dereferenceable(24) %x) {
-; CHECK-LABEL: @example(
-; CHECK-NEXT:    ret ptr [[X:%.*]]
-;
-  %y = load ptr, ptr %x, align 8
-  %y_is_null = icmp eq ptr %y, null
-
-  %res = select i1 %y_is_null, ptr null, ptr %x
+; RUN: opt < %s -passes=instcombine -data-layout=z0:1-z2:neg1-z3:neg1-z5:neg1 -S | FileCheck -check-prefixes=CHECK-DL %s
 
-  %nonnull = icmp ne ptr %res, null
-  call void @llvm.assume(i1 %nonnull)
-
-  ret ptr %res
-}
+target triple = "x86_64-unknown-linux-gnu"
 
 ; TODO: this should be folded to `ret ptr %x` as well.
 define ptr @example2(ptr %x) {
 ; CHECK-LABEL: @example2(
-; CHECK-NEXT:    ret ptr [[X:%.*]]
+; CHECK-NEXT:    [[Y:%.*]] = load ptr, ptr [[X:%.*]], align 8
+; CHECK-NEXT:    [[Y_IS_NULL:%.*]] = icmp eq ptr [[Y]], null
+; CHECK-NEXT:    [[RES:%.*]] = select i1 [[Y_IS_NULL]], ptr null, ptr [[X]]
+; CHECK-NEXT:    [[NONNULL:%.*]] = icmp ne ptr [[RES]], null
+; CHECK-NEXT:    call void @llvm.assume(i1 [[NONNULL]])
+; CHECK-NEXT:    ret ptr [[RES]]
+;
+; CHECK-DL-LABEL: @example2(
+; CHECK-DL-NEXT:    ret ptr [[X:%.*]]
 ;
   %y = load ptr, ptr %x, align 8
   %y_is_null = icmp eq ptr %y, null
diff --git a/llvm/test/Transforms/InstSimplify/compare-dl-sentinel.ll b/llvm/test/Transforms/InstSimplify/compare-dl-sentinel.ll
index 0fc0d22ed76c3..15ed6b9880a24 100755
--- a/llvm/test/Transforms/InstSimplify/compare-dl-sentinel.ll
+++ b/llvm/test/Transforms/InstSimplify/compare-dl-sentinel.ll
@@ -1,3071 +1,41 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
 ; RUN: opt < %s -passes=instsimplify -S | FileCheck %s
-target datalayout = "p:32:32-p1:64:64-z0:1-z2:neg1-z3:neg1-z5:neg1"
+; RUN: opt < %s -passes=instsimplify -data-layout=p:32:32-p1:64:64-z0:1-z2:neg1-z3:neg1-z5:neg1 -S < %s | FileCheck %s --check-prefixes=CHECK-DL
 
 declare void @llvm.assume(i1)
+declare dereferenceable(4) ptr @returns_nonnull_deref_helper()
 
-define i1 @ptrtoint() {
-; CHECK-LABEL: @ptrtoint(
-; CHECK-NEXT:    ret i1 false
-;
-  %a = alloca i8
-  %tmp = ptrtoint ptr %a to i32
-  %r = icmp eq i32 %tmp, 0
-  ret i1 %r
-}
-
-define i1 @bitcast() {
-; CHECK-LABEL: @bitcast(
-; CHECK-NEXT:    ret i1 false
-;
-  %a = alloca i32
-  %b = alloca i64
-  %cmp = icmp eq ptr %a, %b
-  ret i1 %cmp
-}
-
-define i1 @gep() {
-; CHECK-LABEL: @gep(
-; CHECK-NEXT:    ret i1 false
-;
-  %a = alloca [3 x i8], align 8
-  %cmp = icmp eq ptr %a, null
-  ret i1 %cmp
-}
-
-define i1 @gep2() {
-; CHECK-LABEL: @gep2(
-; CHECK-NEXT:    ret i1 true
-;
-  %a = alloca [3 x i8], align 8
-  %cmp = icmp eq ptr %a, %a
-  ret i1 %cmp
-}
-
-; PR11238
-%gept = type { i32, i32 }
- at gepy = global %gept zeroinitializer, align 8
- at gepz = extern_weak global %gept
-
-define i1 @gep3() {
-; CHECK-LABEL: @gep3(
-; CHECK-NEXT:    ret i1 false
-;
-  %x = alloca %gept, align 8
-  %b = getelementptr %gept, ptr %x, i64 0, i32 1
-  %equal = icmp eq ptr %x, %b
-  ret i1 %equal
-}
-
-define i1 @gep4() {
-; CHECK-LABEL: @gep4(
-; CHECK-NEXT:    ret i1 false
-;
-  %x = alloca %gept, align 8
-  %b = getelementptr %gept, ptr @gepy, i64 0, i32 1
-  %equal = icmp eq ptr @gepy, %b
-  ret i1 %equal
-}
-
- at a = common global [1 x i32] zeroinitializer, align 4
-
-define i1 @PR31262() {
-; CHECK-LABEL: @PR31262(
-; CHECK-NEXT:    ret i1 true
-;
-  %idx = getelementptr inbounds [1 x i32], ptr @a, i64 0, i64 undef
-  %cmp = icmp uge ptr %idx, @a
-  ret i1 %cmp
-}
-
-define i1 @gep5() {
-; CHECK-LABEL: @gep5(
-; CHECK-NEXT:    ret i1 false
-;
-  %x = alloca %gept, align 8
-  %a = getelementptr inbounds %gept, ptr %x, i64 0, i32 1
-  %equal = icmp eq ptr %a, @gepy
-  ret i1 %equal
-}
-
-define i1 @gep6(ptr %x) {
-; Same as @gep3 but potentially null.
-; CHECK-LABEL: @gep6(
-; CHECK-NEXT:    ret i1 false
-;
-  %b = getelementptr %gept, ptr %x, i64 0, i32 1
-  %equal = icmp eq ptr %x, %b
-  ret i1 %equal
-}
-
-define i1 @gep7(ptr %x) {
-; CHECK-LABEL: @gep7(
-; CHECK-NEXT:    [[EQUAL:%.*]] = icmp eq ptr [[X:%.*]], @gepz
-; CHECK-NEXT:    ret i1 [[EQUAL]]
-;
-  %equal = icmp eq ptr %x, @gepz
-  ret i1 %equal
-}
-
-define i1 @gep8(ptr %x) {
-; CHECK-LABEL: @gep8(
-; CHECK-NEXT:    [[A:%.*]] = getelementptr [[GEPT:%.*]], ptr [[X:%.*]], i32 1
-; CHECK-NEXT:    [[B:%.*]] = getelementptr [[GEPT]], ptr [[X]], i32 -1
-; CHECK-NEXT:    [[EQUAL:%.*]] = icmp ugt ptr [[A]], [[B]]
-; CHECK-NEXT:    ret i1 [[EQUAL]]
-;
-  %a = getelementptr %gept, ptr %x, i32 1
-  %b = getelementptr %gept, ptr %x, i32 -1
-  %equal = icmp ugt ptr %a, %b
-  ret i1 %equal
-}
-
-define i1 @gep9(ptr %ptr) {
-; CHECK-LABEL: @gep9(
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    ret i1 true
-;
-entry:
-  %first2 = getelementptr inbounds i8, ptr %ptr, i32 1
-  %first3 = getelementptr inbounds i8, ptr %first2, i32 2
-  %first4 = getelementptr inbounds i8, ptr %first3, i32 4
-  %last1 = getelementptr inbounds i8, ptr %first2, i32 48
-  %last2 = getelementptr inbounds i8, ptr %last1, i32 8
-  %last3 = getelementptr inbounds i8, ptr %last2, i32 -4
-  %last4 = getelementptr inbounds i8, ptr %last3, i32 -4
-  %first.int = ptrtoint ptr %first4 to i32
-  %last.int = ptrtoint ptr %last4 to i32
-  %cmp = icmp ne i32 %last.int, %first.int
-  ret i1 %cmp
-}
-
-define i1 @gep10(ptr %ptr) {
-; CHECK-LABEL: @gep10(
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    ret i1 true
-;
-entry:
-  %first1 = getelementptr inbounds i8, ptr %ptr, i32 -2
-  %first2 = getelementptr inbounds i8, ptr %first1, i32 44
-  %last1 = getelementptr inbounds i8, ptr %ptr, i32 48
-  %last2 = getelementptr inbounds i8, ptr %last1, i32 -6
-  %first.int = ptrtoint ptr %first2 to i32
-  %last.int = ptrtoint ptr %last2 to i32
-  %cmp = icmp eq i32 %last.int, %first.int
-  ret i1 %cmp
-}
-
-define i1 @gep11(ptr %ptr) {
-; CHECK-LABEL: @gep11(
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    ret i1 true
-;
-entry:
-  %first1 = getelementptr inbounds i8, ptr %ptr, i32 -2
-  %last1 = getelementptr inbounds i8, ptr %ptr, i32 48
-  %last2 = getelementptr inbounds i8, ptr %last1, i32 -6
-  %cmp = icmp ult ptr %first1, %last2
-  ret i1 %cmp
-}
-
-define i1 @gep12(ptr %ptr) {
-; CHECK-LABEL: @gep12(
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[FIRST1:%.*]] = getelementptr inbounds i8, ptr [[PTR:%.*]], i32 -2
-; CHECK-NEXT:    [[LAST1:%.*]] = getelementptr inbounds i8, ptr [[PTR]], i32 48
-; CHECK-NEXT:    [[LAST2:%.*]] = getelementptr inbounds i8, ptr [[LAST1]], i32 -6
-; CHECK-NEXT:    [[CMP:%.*]] = icmp slt ptr [[FIRST1]], [[LAST2]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-entry:
-  %first1 = getelementptr inbounds i8, ptr %ptr, i32 -2
-  %last1 = getelementptr inbounds i8, ptr %ptr, i32 48
-  %last2 = getelementptr inbounds i8, ptr %last1, i32 -6
-  %cmp = icmp slt ptr %first1, %last2
-  ret i1 %cmp
-}
-
-define i1 @gep13(ptr %ptr) {
-; CHECK-LABEL: @gep13(
-; CHECK-NEXT:    ret i1 false
-;
-; We can prove this GEP is non-null because it is inbounds.
-  %x = getelementptr inbounds i8, ptr %ptr, i32 1
-  %cmp = icmp eq ptr %x, null
-  ret i1 %cmp
-}
-
-define i1 @gep13_no_null_opt(ptr %ptr) #0 {
-; We can't prove this GEP is non-null.
-; CHECK-LABEL: @gep13_no_null_opt(
-; CHECK-NEXT:    ret i1 false
-;
-  %x = getelementptr inbounds i8, ptr %ptr, i32 1
-  %cmp = icmp eq ptr %x, null
-  ret i1 %cmp
-}
-
-define i1 @gep14(ptr %ptr) {
-; CHECK-LABEL: @gep14(
-; CHECK-NEXT:    ret i1 false
-;
-; We can't simplify this because the offset of one in the GEP actually doesn't
-; move the pointer.
-  %x = getelementptr inbounds { {}, i8 }, ptr %ptr, i32 0, i32 1
-  %cmp = icmp eq ptr %x, null
-  ret i1 %cmp
-}
-
-define i1 @gep15(ptr %ptr, i32 %y) {
-; CHECK-LABEL: @gep15(
-; CHECK-NEXT:    ret i1 false
-;
-; We can prove this GEP is non-null even though there is a user value, as we
-; would necessarily violate inbounds on one side or the other.
-  %x = getelementptr inbounds { {}, [4 x {i8, i8}]}, ptr %ptr, i32 0, i32 1, i32 %y, i32 1
-  %cmp = icmp eq ptr %x, null
-  ret i1 %cmp
-}
-
-define i1 @gep15_no_null_opt(ptr %ptr, i32 %y) #0 {
-; We can't prove this GEP is non-null.
-; CHECK-LABEL: @gep15_no_null_opt(
-; CHECK-NEXT:    ret i1 false
-;
-  %x = getelementptr inbounds { {}, [4 x {i8, i8}]}, ptr %ptr, i32 0, i32 1, i32 %y, i32 1
-  %cmp = icmp eq ptr %x, null
-  ret i1 %cmp
-}
-
-define i1 @gep16(ptr %ptr, i32 %a) {
-; CHECK-LABEL: @gep16(
-; CHECK-NEXT:    ret i1 false
-;
-; We can prove this GEP is non-null because it is inbounds and because we know
-; %b is non-zero even though we don't know its value.
-  %b = or i32 %a, 1
-  %x = getelementptr inbounds i8, ptr %ptr, i32 %b
-  %cmp = icmp eq ptr %x, null
-  ret i1 %cmp
-}
-
-define i1 @gep16_no_null_opt(ptr %ptr, i32 %a) #0 {
-; We can't prove this GEP is non-null.
-; CHECK-LABEL: @gep16_no_null_opt(
-; CHECK-NEXT:    ret i1 false
-;
-  %b = or i32 %a, 1
-  %x = getelementptr inbounds i8, ptr %ptr, i32 %b
-  %cmp = icmp eq ptr %x, null
-  ret i1 %cmp
-}
-
-define i1 @gep17() {
-; CHECK-LABEL: @gep17(
-; CHECK-NEXT:    ret i1 true
-;
-  %alloca = alloca i32, align 4
-  %gep1 = getelementptr inbounds i32, ptr %alloca, i32 1
-  %pti1 = ptrtoint ptr %gep1 to i32
-  %gep2 = getelementptr inbounds [4 x i8], ptr %alloca, i32 0, i32 1
-  %pti2 = ptrtoint ptr %gep2 to i32
-  %cmp = icmp ugt i32 %pti1, %pti2
-  ret i1 %cmp
-}
-
-; Negative test: GEP inbounds may cross sign boundary.
-define i1 @gep_same_base_constant_indices(ptr %a) {
-; CHECK-LABEL: @gep_same_base_constant_indices(
-; CHECK-NEXT:    [[ARRAYIDX1:%.*]] = getelementptr inbounds i8, ptr [[A:%.*]], i64 1
-; CHECK-NEXT:    [[ARRAYIDX2:%.*]] = getelementptr inbounds i8, ptr [[A]], i64 10
-; CHECK-NEXT:    [[CMP:%.*]] = icmp slt ptr [[ARRAYIDX1]], [[ARRAYIDX2]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %arrayidx1 = getelementptr inbounds i8, ptr %a, i64 1
-  %arrayidx2 = getelementptr inbounds i8, ptr %a, i64 10
-  %cmp = icmp slt ptr %arrayidx1, %arrayidx2
-  ret i1 %cmp
-}
-
-define i1 @zext(i32 %x) {
-; CHECK-LABEL: @zext(
-; CHECK-NEXT:    ret i1 true
-;
-  %e1 = zext i32 %x to i64
-  %e2 = zext i32 %x to i64
-  %r = icmp eq i64 %e1, %e2
-  ret i1 %r
-}
-
-define i1 @zext2(i1 %x) {
-; CHECK-LABEL: @zext2(
-; CHECK-NEXT:    ret i1 [[X:%.*]]
-;
-  %e = zext i1 %x to i32
-  %c = icmp ne i32 %e, 0
-  ret i1 %c
-}
-
-define i1 @zext3() {
-; CHECK-LABEL: @zext3(
-; CHECK-NEXT:    ret i1 true
-;
-  %e = zext i1 1 to i32
-  %c = icmp ne i32 %e, 0
-  ret i1 %c
-}
-
-define i1 @sext(i32 %x) {
-; CHECK-LABEL: @sext(
-; CHECK-NEXT:    ret i1 true
-;
-  %e1 = sext i32 %x to i64
-  %e2 = sext i32 %x to i64
-  %r = icmp eq i64 %e1, %e2
-  ret i1 %r
-}
-
-define i1 @sext2(i1 %x) {
-; CHECK-LABEL: @sext2(
-; CHECK-NEXT:    ret i1 [[X:%.*]]
-;
-  %e = sext i1 %x to i32
-  %c = icmp ne i32 %e, 0
-  ret i1 %c
-}
-
-define i1 @sext3() {
-; CHECK-LABEL: @sext3(
-; CHECK-NEXT:    ret i1 true
-;
-  %e = sext i1 1 to i32
-  %c = icmp ne i32 %e, 0
-  ret i1 %c
-}
-
-define i1 @add(i32 %x, i32 %y) {
-; CHECK-LABEL: @add(
-; CHECK-NEXT:    ret i1 false
-;
-  %l = lshr i32 %x, 1
-  %q = lshr i32 %y, 1
-  %r = or i32 %q, 1
-  %s = add i32 %l, %r
-  %c = icmp eq i32 %s, 0
-  ret i1 %c
-}
-
-define i1 @addv(<2 x i32> %x, <2 x i32> %y) {
-; CHECK-LABEL: @addv(
-; CHECK-NEXT:    ret i1 false
-;
-  %l = lshr <2 x i32> %x, <i32 1, i32 0>
-  %q = lshr <2 x i32> %y, <i32 1, i32 0>
-  %r = or <2 x i32> %q, <i32 1, i32 0>
-  %s = add <2 x i32> %l, %r
-  %e = extractelement <2 x i32> %s, i32 0
-  %c = icmp eq i32 %e, 0
-  ret i1 %c
-}
-
-define i1 @add2(i8 %x, i8 %y) {
-; CHECK-LABEL: @add2(
-; CHECK-NEXT:    ret i1 false
-;
-  %l = or i8 %x, 128
-  %r = or i8 %y, 129
-  %s = add i8 %l, %r
-  %c = icmp eq i8 %s, 0
-  ret i1 %c
-}
-
-define i1 @add2v(<2 x i8> %x, <2 x i8> %y) {
-; CHECK-LABEL: @add2v(
-; CHECK-NEXT:    ret i1 false
-;
-  %l = or <2 x i8> %x, <i8 0, i8 128>
-  %r = or <2 x i8> %y, <i8 0, i8 129>
-  %s = add <2 x i8> %l, %r
-  %e = extractelement <2 x i8> %s, i32 1
-  %c = icmp eq i8 %e, 0
-  ret i1 %c
-}
-
-define i1 @add3(i8 %x, i8 %y) {
-; CHECK-LABEL: @add3(
-; CHECK-NEXT:    [[L:%.*]] = zext i8 [[X:%.*]] to i32
-; CHECK-NEXT:    [[R:%.*]] = zext i8 [[Y:%.*]] to i32
-; CHECK-NEXT:    [[S:%.*]] = add i32 [[L]], [[R]]
-; CHECK-NEXT:    [[C:%.*]] = icmp eq i32 [[S]], 0
-; CHECK-NEXT:    ret i1 [[C]]
-;
-  %l = zext i8 %x to i32
-  %r = zext i8 %y to i32
-  %s = add i32 %l, %r
-  %c = icmp eq i32 %s, 0
-  ret i1 %c
-}
-
-define i1 @add4(i32 %x, i32 %y) {
-; CHECK-LABEL: @add4(
-; CHECK-NEXT:    ret i1 true
-;
-  %z = add nsw i32 %y, 1
-  %s1 = add nsw i32 %x, %y
-  %s2 = add nsw i32 %x, %z
-  %c = icmp slt i32 %s1, %s2
-  ret i1 %c
-}
-
-define i1 @add5(i32 %x, i32 %y) {
-; CHECK-LABEL: @add5(
-; CHECK-NEXT:    ret i1 true
-;
-  %z = add nuw i32 %y, 1
-  %s1 = add nuw i32 %x, %z
-  %s2 = add nuw i32 %x, %y
-  %c = icmp ugt i32 %s1, %s2
-  ret i1 %c
-}
-
-define i1 @add6(i64 %A, i64 %B) {
-; CHECK-LABEL: @add6(
-; CHECK-NEXT:    ret i1 true
-;
-  %s1 = add i64 %A, %B
-  %s2 = add i64 %B, %A
-  %cmp = icmp eq i64 %s1, %s2
-  ret i1 %cmp
-}
-
-define i1 @addpowtwo(i32 %x, i32 %y) {
-; CHECK-LABEL: @addpowtwo(
-; CHECK-NEXT:    ret i1 false
-;
-  %l = lshr i32 %x, 1
-  %r = shl i32 1, %y
-  %s = add i32 %l, %r
-  %c = icmp eq i32 %s, 0
-  ret i1 %c
-}
-
-define i1 @addpowtwov(<2 x i32> %x, <2 x i32> %y) {
-; CHECK-LABEL: @addpowtwov(
-; CHECK-NEXT:    [[L:%.*]] = lshr <2 x i32> [[X:%.*]], <i32 1, i32 0>
-; CHECK-NEXT:    [[R:%.*]] = shl <2 x i32> <i32 1, i32 0>, [[Y:%.*]]
-; CHECK-NEXT:    [[S:%.*]] = add <2 x i32> [[L]], [[R]]
-; CHECK-NEXT:    [[E:%.*]] = extractelement <2 x i32> [[S]], i32 0
-; CHECK-NEXT:    [[C:%.*]] = icmp eq i32 [[E]], 0
-; CHECK-NEXT:    ret i1 [[C]]
-;
-  %l = lshr <2 x i32> %x, <i32 1, i32 0>
-  %r = shl <2 x i32> <i32 1, i32 0>, %y
-  %s = add <2 x i32> %l, %r
-  %e = extractelement <2 x i32> %s, i32 0
-  %c = icmp eq i32 %e, 0
-  ret i1 %c
-}
-
-define i1 @or(i32 %x) {
-; CHECK-LABEL: @or(
-; CHECK-NEXT:    ret i1 false
-;
-  %o = or i32 %x, 1
-  %c = icmp eq i32 %o, 0
-  ret i1 %c
-}
-
-; Do not simplify if we cannot guarantee that the ConstantExpr is a non-zero
-; constant.
- at GV = common global ptr null
-define i1 @or_constexp(i32 %x) {
-; CHECK-LABEL: @or_constexp(
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[TMP0:%.*]] = and i32 ptrtoint (ptr @GV to i32), 32
-; CHECK-NEXT:    [[O:%.*]] = or i32 [[X:%.*]], [[TMP0]]
-; CHECK-NEXT:    [[C:%.*]] = icmp eq i32 [[O]], 0
-; CHECK-NEXT:    ret i1 [[C]]
-;
-entry:
-  %0 = and i32 ptrtoint (ptr @GV to i32), 32
-  %o = or i32 %x, %0
-  %c = icmp eq i32 %o, 0
-  ret i1 %c
-}
-
-define i1 @shl1(i32 %x) {
-; CHECK-LABEL: @shl1(
-; CHECK-NEXT:    ret i1 false
-;
-  %s = shl i32 1, %x
-  %c = icmp eq i32 %s, 0
-  ret i1 %c
-}
-
-define i1 @lshr1(i32 %x) {
-; CHECK-LABEL: @lshr1(
-; CHECK-NEXT:    ret i1 false
-;
-  %s = lshr i32 -1, %x
-  %c = icmp eq i32 %s, 0
-  ret i1 %c
-}
-
-define i1 @lshr3(i32 %x) {
-; CHECK-LABEL: @lshr3(
-; CHECK-NEXT:    ret i1 true
-;
-  %s = lshr i32 %x, %x
-  %c = icmp eq i32 %s, 0
-  ret i1 %c
-}
-
-define i1 @lshr4(i32 %X, i32 %Y) {
-; CHECK-LABEL: @lshr4(
-; CHECK-NEXT:    ret i1 true
-;
-  %A = lshr i32 %X, %Y
-  %C = icmp ule i32 %A, %X
-  ret i1 %C
-}
-
-define i1 @lshr5(i32 %X, i32 %Y) {
-; CHECK-LABEL: @lshr5(
-; CHECK-NEXT:    ret i1 false
-;
-  %A = lshr i32 %X, %Y
-  %C = icmp ugt i32 %A, %X
-  ret i1 %C
-}
-
-define i1 @lshr6(i32 %X, i32 %Y) {
-; CHECK-LABEL: @lshr6(
-; CHECK-NEXT:    ret i1 false
-;
-  %A = lshr i32 %X, %Y
-  %C = icmp ult i32 %X, %A
-  ret i1 %C
-}
-
-define i1 @lshr7(i32 %X, i32 %Y) {
-; CHECK-LABEL: @lshr7(
-; CHECK-NEXT:    ret i1 true
-;
-  %A = lshr i32 %X, %Y
-  %C = icmp uge i32 %X, %A
-  ret i1 %C
-}
-
-define i1 @lshr_nonzero_eq(i32 %x) {
-; CHECK-LABEL: @lshr_nonzero_eq(
-; CHECK-NEXT:    [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0
-; CHECK-NEXT:    call void @llvm.assume(i1 [[X_NE_0]])
-; CHECK-NEXT:    ret i1 false
-;
-  %x_ne_0 = icmp ne i32 %x, 0
-  call void @llvm.assume(i1 %x_ne_0)
-  %lhs = lshr i32 %x, 1
-  %cmp = icmp eq i32 %lhs, %x
-  ret i1 %cmp
-}
-
-define i1 @lshr_nonzero_uge(i32 %x) {
-; CHECK-LABEL: @lshr_nonzero_uge(
-; CHECK-NEXT:    [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0
-; CHECK-NEXT:    call void @llvm.assume(i1 [[X_NE_0]])
-; CHECK-NEXT:    ret i1 false
-;
-  %x_ne_0 = icmp ne i32 %x, 0
-  call void @llvm.assume(i1 %x_ne_0)
-  %lhs = lshr i32 %x, 1
-  %cmp = icmp uge i32 %lhs, %x
-  ret i1 %cmp
-}
-
-define i1 @lshr_nonzero_ne(i32 %x) {
-; CHECK-LABEL: @lshr_nonzero_ne(
-; CHECK-NEXT:    [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0
-; CHECK-NEXT:    call void @llvm.assume(i1 [[X_NE_0]])
-; CHECK-NEXT:    ret i1 true
-;
-  %x_ne_0 = icmp ne i32 %x, 0
-  call void @llvm.assume(i1 %x_ne_0)
-  %lhs = lshr i32 %x, 1
-  %cmp = icmp ne i32 %lhs, %x
-  ret i1 %cmp
-}
-
-define i1 @lshr_nonzero_ult(i32 %x) {
-; CHECK-LABEL: @lshr_nonzero_ult(
-; CHECK-NEXT:    [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0
-; CHECK-NEXT:    call void @llvm.assume(i1 [[X_NE_0]])
-; CHECK-NEXT:    ret i1 true
-;
-  %x_ne_0 = icmp ne i32 %x, 0
-  call void @llvm.assume(i1 %x_ne_0)
-  %lhs = lshr i32 %x, 1
-  %cmp = icmp ult i32 %lhs, %x
-  ret i1 %cmp
-}
-
-; Negative test - unknown shift amount
-define i1 @lshr_nonzero_neg_unknown(i32 %x, i32 %c) {
-; CHECK-LABEL: @lshr_nonzero_neg_unknown(
-; CHECK-NEXT:    [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0
-; CHECK-NEXT:    call void @llvm.assume(i1 [[X_NE_0]])
-; CHECK-NEXT:    [[LHS:%.*]] = lshr i32 [[X]], [[C:%.*]]
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[LHS]], [[X]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %x_ne_0 = icmp ne i32 %x, 0
-  call void @llvm.assume(i1 %x_ne_0)
-  %lhs = lshr i32 %x, %c
-  %cmp = icmp ult i32 %lhs, %x
-  ret i1 %cmp
-}
-
-; Negative test - x may be zero
-define i1 @lshr_nonzero_neg_maybe_zero(i32 %x) {
-; CHECK-LABEL: @lshr_nonzero_neg_maybe_zero(
-; CHECK-NEXT:    [[LHS:%.*]] = lshr i32 [[X:%.*]], 1
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[LHS]], [[X]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %lhs = lshr i32 %x, 1
-  %cmp = icmp ult i32 %lhs, %x
-  ret i1 %cmp
-}
-
-; Negative test - signed pred
-define i1 @lshr_nonzero_neg_signed(i32 %x, i32 %c) {
-; CHECK-LABEL: @lshr_nonzero_neg_signed(
-; CHECK-NEXT:    [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0
-; CHECK-NEXT:    call void @llvm.assume(i1 [[X_NE_0]])
-; CHECK-NEXT:    [[LHS:%.*]] = lshr i32 [[X]], 1
-; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[LHS]], [[X]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %x_ne_0 = icmp ne i32 %x, 0
-  call void @llvm.assume(i1 %x_ne_0)
-  %lhs = lshr i32 %x, 1
-  %cmp = icmp slt i32 %lhs, %x
-  ret i1 %cmp
-}
-
-define i1 @ashr1(i32 %x) {
-; CHECK-LABEL: @ashr1(
-; CHECK-NEXT:    ret i1 false
-;
-  %s = ashr i32 -1, %x
-  %c = icmp eq i32 %s, 0
-  ret i1 %c
-}
-
-define i1 @ashr3(i32 %x) {
-; CHECK-LABEL: @ashr3(
-; CHECK-NEXT:    ret i1 true
-;
-  %s = ashr i32 %x, %x
-  %c = icmp eq i32 %s, 0
-  ret i1 %c
-}
-
-define i1 @select1(i1 %cond) {
-; CHECK-LABEL: @select1(
-; CHECK-NEXT:    ret i1 [[COND:%.*]]
-;
-  %s = select i1 %cond, i32 1, i32 0
-  %c = icmp eq i32 %s, 1
-  ret i1 %c
-}
-
-define i1 @select2(i1 %cond) {
-; CHECK-LABEL: @select2(
-; CHECK-NEXT:    ret i1 [[COND:%.*]]
-;
-  %x = zext i1 %cond to i32
-  %s = select i1 %cond, i32 %x, i32 0
-  %c = icmp ne i32 %s, 0
-  ret i1 %c
-}
-
-define i1 @select3(i1 %cond) {
-; CHECK-LABEL: @select3(
-; CHECK-NEXT:    ret i1 [[COND:%.*]]
-;
-  %x = zext i1 %cond to i32
-  %s = select i1 %cond, i32 1, i32 %x
-  %c = icmp ne i32 %s, 0
-  ret i1 %c
-}
-
-define i1 @select4(i1 %cond) {
-; CHECK-LABEL: @select4(
-; CHECK-NEXT:    ret i1 [[COND:%.*]]
-;
-  %invert = xor i1 %cond, 1
-  %s = select i1 %invert, i32 0, i32 1
-  %c = icmp ne i32 %s, 0
-  ret i1 %c
-}
-
-define i1 @select5(i32 %x) {
-; CHECK-LABEL: @select5(
-; CHECK-NEXT:    ret i1 false
-;
-  %c = icmp eq i32 %x, 0
-  %s = select i1 %c, i32 1, i32 %x
-  %c2 = icmp eq i32 %s, 0
-  ret i1 %c2
-}
-
-define i1 @select6(i32 %x) {
-; CHECK-LABEL: @select6(
-; CHECK-NEXT:    ret i1 false
-;
-  %c = icmp sgt i32 %x, 0
-  %s = select i1 %c, i32 %x, i32 4
-  %c2 = icmp eq i32 %s, 0
-  ret i1 %c2
-}
-
-define i1 @urem1(i32 %X, i32 %Y) {
-; CHECK-LABEL: @urem1(
-; CHECK-NEXT:    ret i1 true
-;
-  %A = urem i32 %X, %Y
-  %B = icmp ult i32 %A, %Y
-  ret i1 %B
-}
-
-define i1 @urem2(i32 %X, i32 %Y) {
-; CHECK-LABEL: @urem2(
-; CHECK-NEXT:    ret i1 false
-;
-  %A = urem i32 %X, %Y
-  %B = icmp eq i32 %A, %Y
-  ret i1 %B
-}
-
-define i1 @urem4(i32 %X) {
-; CHECK-LABEL: @urem4(
-; CHECK-NEXT:    [[A:%.*]] = urem i32 [[X:%.*]], 15
-; CHECK-NEXT:    [[B:%.*]] = icmp ult i32 [[A]], 10
-; CHECK-NEXT:    ret i1 [[B]]
-;
-  %A = urem i32 %X, 15
-  %B = icmp ult i32 %A, 10
-  ret i1 %B
-}
-
-define i1 @urem5(i16 %X, i32 %Y) {
-; CHECK-LABEL: @urem5(
-; CHECK-NEXT:    [[A:%.*]] = zext i16 [[X:%.*]] to i32
-; CHECK-NEXT:    [[B:%.*]] = urem i32 [[A]], [[Y:%.*]]
-; CHECK-NEXT:    [[C:%.*]] = icmp slt i32 [[B]], [[Y]]
-; CHECK-NEXT:    ret i1 [[C]]
-;
-  %A = zext i16 %X to i32
-  %B = urem i32 %A, %Y
-  %C = icmp slt i32 %B, %Y
-  ret i1 %C
-}
-
-define i1 @urem6(i32 %X, i32 %Y) {
-; CHECK-LABEL: @urem6(
-; CHECK-NEXT:    ret i1 true
-;
-  %A = urem i32 %X, %Y
-  %B = icmp ugt i32 %Y, %A
-  ret i1 %B
-}
-
-define i1 @urem7(i32 %X) {
-; CHECK-LABEL: @urem7(
-; CHECK-NEXT:    [[A:%.*]] = urem i32 1, [[X:%.*]]
-; CHECK-NEXT:    [[B:%.*]] = icmp sgt i32 [[A]], [[X]]
-; CHECK-NEXT:    ret i1 [[B]]
-;
-  %A = urem i32 1, %X
-  %B = icmp sgt i32 %A, %X
-  ret i1 %B
-}
-
-define i1 @urem8(i8 %X, i8 %Y) {
-; CHECK-LABEL: @urem8(
-; CHECK-NEXT:    ret i1 true
-;
-  %A = urem i8 %X, %Y
-  %B = icmp ule i8 %A, %X
-  ret i1 %B
-}
-
-define i1 @urem9(i8 %X, i8 %Y) {
-; CHECK-LABEL: @urem9(
-; CHECK-NEXT:    ret i1 false
-;
-  %A = urem i8 %X, %Y
-  %B = icmp ugt i8 %A, %X
-  ret i1 %B
-}
-
-define i1 @urem10(i8 %X, i8 %Y) {
-; CHECK-LABEL: @urem10(
-; CHECK-NEXT:    ret i1 true
-;
-  %A = urem i8 %X, %Y
-  %B = icmp uge i8 %X, %A
-  ret i1 %B
-}
-
-define i1 @urem11(i8 %X, i8 %Y) {
-; CHECK-LABEL: @urem11(
-; CHECK-NEXT:    ret i1 false
-;
-  %A = urem i8 %X, %Y
-  %B = icmp ult i8 %X, %A
-  ret i1 %B
-}
-
-; PR9343 #15
-define i1 @srem2(i16 %X, i32 %Y) {
-; CHECK-LABEL: @srem2(
-; CHECK-NEXT:    ret i1 false
-;
-  %A = zext i16 %X to i32
-  %B = add nsw i32 %A, 1
-  %C = srem i32 %B, %Y
-  %D = icmp slt i32 %C, 0
-  ret i1 %D
-}
-
-define i1 @srem2v(<2 x i16> %X, <2 x i32> %Y) {
-; CHECK-LABEL: @srem2v(
-; CHECK-NEXT:    ret i1 false
-;
-  %A = zext <2 x i16> %X to <2 x i32>
-  %B = add nsw <2 x i32> %A, <i32 1, i32 0>
-  %C = srem <2 x i32> %B, %Y
-  %D = extractelement <2 x i32> %C, i32 0
-  %E = icmp slt i32 %D, 0
-  ret i1 %E
-}
-
-define i1 @srem3(i16 %X, i32 %Y) {
-; CHECK-LABEL: @srem3(
-; CHECK-NEXT:    ret i1 false
-;
-  %A = zext i16 %X to i32
-  %B = or i32 2147483648, %A
-  %C = sub nsw i32 1, %B
-  %D = srem i32 %C, %Y
-  %E = icmp slt i32 %D, 0
-  ret i1 %E
-}
-
-define i1 @srem3v(<2 x i16> %X, <2 x i32> %Y) {
-; CHECK-LABEL: @srem3v(
-; CHECK-NEXT:    ret i1 false
-;
-  %A = zext <2 x i16> %X to <2 x i32>
-  %B = or <2 x i32> <i32 1, i32 2147483648>, %A
-  %C = sub nsw <2 x i32> <i32 0, i32 1>, %B
-  %D = srem <2 x i32> %C, %Y
-  %E = extractelement <2 x i32> %C, i32 1
-  %F = icmp slt i32 %E, 0
-  ret i1 %F
-}
-
-define i1 @udiv2(i32 %Z) {
-; CHECK-LABEL: @udiv2(
-; CHECK-NEXT:    ret i1 true
-;
-  %A = udiv exact i32 10, %Z
-  %B = udiv exact i32 20, %Z
-  %C = icmp ult i32 %A, %B
-  ret i1 %C
-}
-
-; Exact sdiv and equality preds can simplify.
-
-define i1 @sdiv_exact_equality(i32 %Z) {
-; CHECK-LABEL: @sdiv_exact_equality(
-; CHECK-NEXT:    ret i1 false
-;
-  %A = sdiv exact i32 10, %Z
-  %B = sdiv exact i32 20, %Z
-  %C = icmp eq i32 %A, %B
-  ret i1 %C
-}
-
-; But not other preds: PR32949 - https://bugs.llvm.org/show_bug.cgi?id=32949
-
-define i1 @sdiv_exact_not_equality(i32 %Z) {
-; CHECK-LABEL: @sdiv_exact_not_equality(
-; CHECK-NEXT:    [[A:%.*]] = sdiv exact i32 10, [[Z:%.*]]
-; CHECK-NEXT:    [[B:%.*]] = sdiv exact i32 20, [[Z]]
-; CHECK-NEXT:    [[C:%.*]] = icmp ult i32 [[A]], [[B]]
-; CHECK-NEXT:    ret i1 [[C]]
-;
-  %A = sdiv exact i32 10, %Z
-  %B = sdiv exact i32 20, %Z
-  %C = icmp ult i32 %A, %B
-  ret i1 %C
-}
-
-define i1 @udiv3(i32 %X, i32 %Y) {
-; CHECK-LABEL: @udiv3(
-; CHECK-NEXT:    ret i1 false
-;
-  %A = udiv i32 %X, %Y
-  %C = icmp ugt i32 %A, %X
-  ret i1 %C
-}
-
-define i1 @udiv4(i32 %X, i32 %Y) {
-; CHECK-LABEL: @udiv4(
-; CHECK-NEXT:    ret i1 true
-;
-  %A = udiv i32 %X, %Y
-  %C = icmp ule i32 %A, %X
-  ret i1 %C
-}
-
-; PR11340
-define i1 @udiv6(i32 %X) nounwind {
-; CHECK-LABEL: @udiv6(
-; CHECK-NEXT:    [[A:%.*]] = udiv i32 1, [[X:%.*]]
-; CHECK-NEXT:    [[C:%.*]] = icmp eq i32 [[A]], 0
-; CHECK-NEXT:    ret i1 [[C]]
-;
-  %A = udiv i32 1, %X
-  %C = icmp eq i32 %A, 0
-  ret i1 %C
-}
-
-define i1 @udiv7(i32 %X, i32 %Y) {
-; CHECK-LABEL: @udiv7(
-; CHECK-NEXT:    ret i1 false
-;
-  %A = udiv i32 %X, %Y
-  %C = icmp ult i32 %X, %A
-  ret i1 %C
-}
-
-define i1 @udiv8(i32 %X, i32 %Y) {
-; CHECK-LABEL: @udiv8(
-; CHECK-NEXT:    ret i1 true
-;
-  %A = udiv i32 %X, %Y
-  %C = icmp uge i32 %X, %A
-  ret i1 %C
-}
-
-define i1 @udiv_nonzero_eq(i32 %x) {
-; CHECK-LABEL: @udiv_nonzero_eq(
-; CHECK-NEXT:    [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0
-; CHECK-NEXT:    call void @llvm.assume(i1 [[X_NE_0]])
-; CHECK-NEXT:    ret i1 false
-;
-  %x_ne_0 = icmp ne i32 %x, 0
-  call void @llvm.assume(i1 %x_ne_0)
-  %lhs = udiv i32 %x, 3
-  %cmp = icmp eq i32 %lhs, %x
-  ret i1 %cmp
-}
-
-define i1 @udiv_nonzero_uge(i32 %x) {
-; CHECK-LABEL: @udiv_nonzero_uge(
-; CHECK-NEXT:    [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0
-; CHECK-NEXT:    call void @llvm.assume(i1 [[X_NE_0]])
-; CHECK-NEXT:    ret i1 false
-;
-  %x_ne_0 = icmp ne i32 %x, 0
-  call void @llvm.assume(i1 %x_ne_0)
-  %lhs = udiv i32 %x, 3
-  %cmp = icmp uge i32 %lhs, %x
-  ret i1 %cmp
-}
-
-define i1 @udiv_nonzero_ne(i32 %x) {
-; CHECK-LABEL: @udiv_nonzero_ne(
-; CHECK-NEXT:    [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0
-; CHECK-NEXT:    call void @llvm.assume(i1 [[X_NE_0]])
-; CHECK-NEXT:    ret i1 true
-;
-  %x_ne_0 = icmp ne i32 %x, 0
-  call void @llvm.assume(i1 %x_ne_0)
-  %lhs = udiv i32 %x, 3
-  %cmp = icmp ne i32 %lhs, %x
-  ret i1 %cmp
-}
-
-define i1 @udiv_nonzero_ult(i32 %x) {
-; CHECK-LABEL: @udiv_nonzero_ult(
-; CHECK-NEXT:    [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0
-; CHECK-NEXT:    call void @llvm.assume(i1 [[X_NE_0]])
-; CHECK-NEXT:    ret i1 true
-;
-  %x_ne_0 = icmp ne i32 %x, 0
-  call void @llvm.assume(i1 %x_ne_0)
-  %lhs = udiv i32 %x, 3
-  %cmp = icmp ult i32 %lhs, %x
-  ret i1 %cmp
-}
-
-; Negative test - unknown divisor
-define i1 @udiv_nonzero_neg_unknown(i32 %x, i32 %c) {
-; CHECK-LABEL: @udiv_nonzero_neg_unknown(
-; CHECK-NEXT:    [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0
-; CHECK-NEXT:    call void @llvm.assume(i1 [[X_NE_0]])
-; CHECK-NEXT:    [[LHS:%.*]] = udiv i32 [[X]], [[C:%.*]]
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[LHS]], [[X]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %x_ne_0 = icmp ne i32 %x, 0
-  call void @llvm.assume(i1 %x_ne_0)
-  %lhs = udiv i32 %x, %c
-  %cmp = icmp ult i32 %lhs, %x
-  ret i1 %cmp
-}
-
-; Negative test - x may be zero
-define i1 @udiv_nonzero_neg_maybe_zero(i32 %x) {
-; CHECK-LABEL: @udiv_nonzero_neg_maybe_zero(
-; CHECK-NEXT:    [[LHS:%.*]] = udiv i32 [[X:%.*]], 3
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[LHS]], [[X]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %lhs = udiv i32 %x, 3
-  %cmp = icmp ult i32 %lhs, %x
-  ret i1 %cmp
-}
-
-; Negative test - signed pred
-define i1 @udiv_nonzero_neg_signed(i32 %x) {
-; CHECK-LABEL: @udiv_nonzero_neg_signed(
-; CHECK-NEXT:    [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0
-; CHECK-NEXT:    call void @llvm.assume(i1 [[X_NE_0]])
-; CHECK-NEXT:    [[LHS:%.*]] = udiv i32 [[X]], 3
-; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[LHS]], [[X]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %x_ne_0 = icmp ne i32 %x, 0
-  call void @llvm.assume(i1 %x_ne_0)
-  %lhs = udiv i32 %x, 3
-  %cmp = icmp slt i32 %lhs, %x
-  ret i1 %cmp
-}
-
-; Square of a non-zero number is non-zero if there is no overflow.
-define i1 @mul1(i32 %X) {
-; CHECK-LABEL: @mul1(
-; CHECK-NEXT:    ret i1 false
-;
-  %Y = or i32 %X, 1
-  %M = mul nuw i32 %Y, %Y
-  %C = icmp eq i32 %M, 0
-  ret i1 %C
-}
-
-define i1 @mul1v(<2 x i32> %X) {
-; CHECK-LABEL: @mul1v(
-; CHECK-NEXT:    ret i1 false
-;
-  %Y = or <2 x i32> %X, <i32 1, i32 0>
-  %M = mul nuw <2 x i32> %Y, %Y
-  %E = extractelement <2 x i32> %M, i32 0
-  %C = icmp eq i32 %E, 0
-  ret i1 %C
-}
-
-; Square of a non-zero number is positive if there is no signed overflow.
-define i1 @mul2(i32 %X) {
-; CHECK-LABEL: @mul2(
-; CHECK-NEXT:    ret i1 true
-;
-  %Y = or i32 %X, 1
-  %M = mul nsw i32 %Y, %Y
-  %C = icmp sgt i32 %M, 0
-  ret i1 %C
-}
-
-define i1 @mul2v(<2 x i32> %X) {
-; CHECK-LABEL: @mul2v(
-; CHECK-NEXT:    ret i1 true
-;
-  %Y = or <2 x i32> %X, <i32 0, i32 1>
-  %M = mul nsw <2 x i32> %Y, %Y
-  %E = extractelement <2 x i32> %M, i32 1
-  %C = icmp sgt i32 %E, 0
-  ret i1 %C
-}
-
-; Product of non-negative numbers is non-negative if there is no signed overflow.
-define i1 @mul3(i32 %X, i32 %Y) {
-; CHECK-LABEL: @mul3(
-; CHECK-NEXT:    ret i1 true
-;
-  %XX = mul nsw i32 %X, %X
-  %YY = mul nsw i32 %Y, %Y
-  %M = mul nsw i32 %XX, %YY
-  %C = icmp sge i32 %M, 0
-  ret i1 %C
-}
-
-define <2 x i1> @mul3v(<2 x i32> %X, <2 x i32> %Y) {
-; CHECK-LABEL: @mul3v(
-; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
-;
-  %XX = mul nsw <2 x i32> %X, %X
-  %YY = mul nsw <2 x i32> %Y, %Y
-  %M = mul nsw <2 x i32> %XX, %YY
-  %C = icmp sge <2 x i32> %M, zeroinitializer
-  ret <2 x i1> %C
-}
-
-define <2 x i1> @vectorselect1(<2 x i1> %cond) {
-; CHECK-LABEL: @vectorselect1(
-; CHECK-NEXT:    ret <2 x i1> [[COND:%.*]]
-;
-  %invert = xor <2 x i1> %cond, <i1 1, i1 1>
-  %s = select <2 x i1> %invert, <2 x i32> <i32 0, i32 0>, <2 x i32> <i32 1, i32 1>
-  %c = icmp ne <2 x i32> %s, <i32 0, i32 0>
-  ret <2 x i1> %c
-}
-
-; PR11948
-define <2 x i1> @vectorselectcrash(i32 %arg1) {
-; CHECK-LABEL: @vectorselectcrash(
-; CHECK-NEXT:    [[TOBOOL40:%.*]] = icmp ne i32 [[ARG1:%.*]], 0
-; CHECK-NEXT:    [[COND43:%.*]] = select i1 [[TOBOOL40]], <2 x i16> <i16 -5, i16 66>, <2 x i16> <i16 46, i16 1>
-; CHECK-NEXT:    [[CMP45:%.*]] = icmp ugt <2 x i16> [[COND43]], <i16 73, i16 21>
-; CHECK-NEXT:    ret <2 x i1> [[CMP45]]
-;
-  %tobool40 = icmp ne i32 %arg1, 0
-  %cond43 = select i1 %tobool40, <2 x i16> <i16 -5, i16 66>, <2 x i16> <i16 46, i16 1>
-  %cmp45 = icmp ugt <2 x i16> %cond43, <i16 73, i16 21>
-  ret <2 x i1> %cmp45
-}
-
-; PR12013
-define i1 @alloca_compare(i64 %idx) {
-; CHECK-LABEL: @alloca_compare(
-; CHECK-NEXT:    ret i1 false
-;
-  %sv = alloca { i32, i32, [124 x i32] }
-  %1 = getelementptr inbounds { i32, i32, [124 x i32] }, ptr %sv, i32 0, i32 2, i64 %idx
-  %2 = icmp eq ptr %1, null
-  ret i1 %2
-}
-
-define i1 @alloca_compare_no_null_opt(i64 %idx) #0 {
-; CHECK-LABEL: @alloca_compare_no_null_opt(
-; CHECK-NEXT:    ret i1 false
-;
-  %sv = alloca { i32, i32, [124 x i32] }
-  %cmp = getelementptr inbounds { i32, i32, [124 x i32] }, ptr %sv, i32 0, i32 2, i64 %idx
-  %X = icmp eq ptr %cmp, null
-  ret i1 %X
-}
-; PR12075
-define i1 @infinite_gep() {
-; CHECK-LABEL: @infinite_gep(
-; CHECK-NEXT:    ret i1 true
-; CHECK:       unreachableblock:
-; CHECK-NEXT:    [[X:%.*]] = getelementptr i32, ptr [[X]], i32 1
-; CHECK-NEXT:    [[Y:%.*]] = icmp eq ptr [[X]], null
-; CHECK-NEXT:    ret i1 [[Y]]
-;
-  ret i1 1
-
-unreachableblock:
-  %X = getelementptr i32, ptr%X, i32 1
-  %Y = icmp eq ptr %X, null
-  ret i1 %Y
-}
-
-; It's not valid to fold a comparison of an argument with an alloca, even though
-; that's tempting. An argument can't *alias* an alloca, however the aliasing rule
-; relies on restrictions against guessing an object's address and dereferencing.
-; There are no restrictions against guessing an object's address and comparing.
-
-define i1 @alloca_argument_compare(ptr %arg) {
-; CHECK-LABEL: @alloca_argument_compare(
-; CHECK-NEXT:    [[ALLOC:%.*]] = alloca i64, align 8
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[ARG:%.*]], [[ALLOC]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %alloc = alloca i64
-  %cmp = icmp eq ptr %arg, %alloc
-  ret i1 %cmp
-}
-
-; As above, but with the operands reversed.
-
-define i1 @alloca_argument_compare_swapped(ptr %arg) {
-; CHECK-LABEL: @alloca_argument_compare_swapped(
-; CHECK-NEXT:    [[ALLOC:%.*]] = alloca i64, align 8
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[ALLOC]], [[ARG:%.*]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %alloc = alloca i64
-  %cmp = icmp eq ptr %alloc, %arg
-  ret i1 %cmp
-}
-
-; Don't assume that a noalias argument isn't equal to a global variable's
-; address. This is an example where AliasAnalysis' NoAlias concept is
-; different from actual pointer inequality.
-
- at y = external global i32
-define zeroext i1 @external_compare(ptr noalias %x) {
-; CHECK-LABEL: @external_compare(
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[X:%.*]], @y
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %cmp = icmp eq ptr %x, @y
-  ret i1 %cmp
-}
-
-define i1 @alloca_gep(i64 %a, i64 %b) {
-; CHECK-LABEL: @alloca_gep(
-; CHECK-NEXT:    ret i1 false
-;
-; We can prove this GEP is non-null because it is inbounds and the pointer
-; is non-null.
-  %strs = alloca [1000 x [1001 x i8]], align 16
-  %x = getelementptr inbounds [1000 x [1001 x i8]], ptr %strs, i64 0, i64 %a, i64 %b
-  %cmp = icmp eq ptr %x, null
-  ret i1 %cmp
-}
-
-define i1 @alloca_gep_no_null_opt(i64 %a, i64 %b) #0 {
-; CHECK-LABEL: @alloca_gep_no_null_opt(
-; CHECK-NEXT:    ret i1 false
-;
-; We can't prove this GEP is non-null.
-  %strs = alloca [1000 x [1001 x i8]], align 16
-  %x = getelementptr inbounds [1000 x [1001 x i8]], ptr %strs, i64 0, i64 %a, i64 %b
-  %cmp = icmp eq ptr %x, null
-  ret i1 %cmp
-}
-
-define i1 @non_inbounds_gep_compare(ptr %a) {
-; CHECK-LABEL: @non_inbounds_gep_compare(
-; CHECK-NEXT:    ret i1 true
-;
-; Equality compares with non-inbounds GEPs can be folded.
-  %x = getelementptr i64, ptr %a, i64 42
-  %y = getelementptr inbounds i64, ptr %x, i64 -42
-  %z = getelementptr i64, ptr %a, i64 -42
-  %w = getelementptr inbounds i64, ptr %z, i64 42
-  %cmp = icmp eq ptr %y, %w
-  ret i1 %cmp
-}
-
-define i1 @non_inbounds_gep_compare2(ptr %a) {
-; CHECK-LABEL: @non_inbounds_gep_compare2(
-; CHECK-NEXT:    ret i1 true
-;
-; Equality compares with non-inbounds GEPs can be folded.
-  %x = getelementptr i64, ptr %a, i64 4294967297
-  %y = getelementptr i64, ptr %a, i64 1
-  %cmp = icmp eq ptr %y, %y
-  ret i1 %cmp
-}
-
-define i1 @compare_always_true_slt(i16 %a) {
-; CHECK-LABEL: @compare_always_true_slt(
-; CHECK-NEXT:    ret i1 true
-;
-  %t1 = zext i16 %a to i32
-  %t2 = sub i32 0, %t1
-  %t3 = icmp slt i32 %t2, 1
-  ret i1 %t3
-}
-
-define <2 x i1> @compare_always_true_slt_splat(<2 x i16> %a) {
-; CHECK-LABEL: @compare_always_true_slt_splat(
-; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
-;
-  %t1 = zext <2 x i16> %a to <2 x i32>
-  %t2 = sub <2 x i32> zeroinitializer, %t1
-  %t3 = icmp slt <2 x i32> %t2, <i32 1, i32 1>
-  ret <2 x i1> %t3
-}
-
-define i1 @compare_always_true_sle(i16 %a) {
-; CHECK-LABEL: @compare_always_true_sle(
-; CHECK-NEXT:    ret i1 true
-;
-  %t1 = zext i16 %a to i32
-  %t2 = sub i32 0, %t1
-  %t3 = icmp sle i32 %t2, 0
-  ret i1 %t3
-}
-
-define <2 x i1> @compare_always_true_sle_splat(<2 x i16> %a) {
-; CHECK-LABEL: @compare_always_true_sle_splat(
-; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
-;
-  %t1 = zext <2 x i16> %a to <2 x i32>
-  %t2 = sub <2 x i32> zeroinitializer, %t1
-  %t3 = icmp sle <2 x i32> %t2, zeroinitializer
-  ret <2 x i1> %t3
-}
-
-define i1 @compare_always_false_sgt(i16 %a) {
-; CHECK-LABEL: @compare_always_false_sgt(
-; CHECK-NEXT:    ret i1 false
-;
-  %t1 = zext i16 %a to i32
-  %t2 = sub i32 0, %t1
-  %t3 = icmp sgt i32 %t2, 0
-  ret i1 %t3
-}
-
-define <2 x i1> @compare_always_false_sgt_splat(<2 x i16> %a) {
-; CHECK-LABEL: @compare_always_false_sgt_splat(
-; CHECK-NEXT:    ret <2 x i1> zeroinitializer
-;
-  %t1 = zext <2 x i16> %a to <2 x i32>
-  %t2 = sub <2 x i32> zeroinitializer, %t1
-  %t3 = icmp sgt <2 x i32> %t2, zeroinitializer
-  ret <2 x i1> %t3
-}
-
-define i1 @compare_always_false_sge(i16 %a) {
-; CHECK-LABEL: @compare_always_false_sge(
-; CHECK-NEXT:    ret i1 false
-;
-  %t1 = zext i16 %a to i32
-  %t2 = sub i32 0, %t1
-  %t3 = icmp sge i32 %t2, 1
-  ret i1 %t3
-}
-
-define <2 x i1> @compare_always_false_sge_splat(<2 x i16> %a) {
-; CHECK-LABEL: @compare_always_false_sge_splat(
-; CHECK-NEXT:    ret <2 x i1> zeroinitializer
-;
-  %t1 = zext <2 x i16> %a to <2 x i32>
-  %t2 = sub <2 x i32> zeroinitializer, %t1
-  %t3 = icmp sge <2 x i32> %t2, <i32 1, i32 1>
-  ret <2 x i1> %t3
-}
-
-define i1 @compare_always_false_eq(i16 %a) {
-; CHECK-LABEL: @compare_always_false_eq(
-; CHECK-NEXT:    ret i1 false
-;
-  %t1 = zext i16 %a to i32
-  %t2 = sub i32 0, %t1
-  %t3 = icmp eq i32 %t2, 1
-  ret i1 %t3
-}
-
-define <2 x i1> @compare_always_false_eq_splat(<2 x i16> %a) {
-; CHECK-LABEL: @compare_always_false_eq_splat(
-; CHECK-NEXT:    ret <2 x i1> zeroinitializer
-;
-  %t1 = zext <2 x i16> %a to <2 x i32>
-  %t2 = sub <2 x i32> zeroinitializer, %t1
-  %t3 = icmp eq <2 x i32> %t2, <i32 1, i32 1>
-  ret <2 x i1> %t3
-}
-
-define i1 @compare_always_true_ne(i16 %a) {
-; CHECK-LABEL: @compare_always_true_ne(
-; CHECK-NEXT:    ret i1 true
-;
-  %t1 = zext i16 %a to i32
-  %t2 = sub i32 0, %t1
-  %t3 = icmp ne i32 %t2, 1
-  ret i1 %t3
-}
-
-define <2 x i1> @compare_always_true_ne_splat(<2 x i16> %a) {
-; CHECK-LABEL: @compare_always_true_ne_splat(
-; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
-;
-  %t1 = zext <2 x i16> %a to <2 x i32>
-  %t2 = sub <2 x i32> zeroinitializer, %t1
-  %t3 = icmp ne <2 x i32> %t2, <i32 1, i32 1>
-  ret <2 x i1> %t3
-}
-
-define i1 @lshr_ugt_false(i32 %a) {
-; CHECK-LABEL: @lshr_ugt_false(
-; CHECK-NEXT:    ret i1 false
-;
-  %shr = lshr i32 1, %a
-  %cmp = icmp ugt i32 %shr, 1
-  ret i1 %cmp
-}
-
-define i1 @nonnull_arg(ptr nonnull %i) {
-; CHECK-LABEL: @nonnull_arg(
-; CHECK-NEXT:    ret i1 false
-;
-  %cmp = icmp eq ptr %i, null
-  ret i1 %cmp
-}
-
-define i1 @nonnull_arg_no_null_opt(ptr nonnull %i) #0 {
-; CHECK-LABEL: @nonnull_arg_no_null_opt(
-; CHECK-NEXT:    ret i1 false
-;
-  %cmp = icmp eq ptr %i, null
-  ret i1 %cmp
-}
-
-define i1 @nonnull_deref_arg(ptr dereferenceable(4) %i) {
-; CHECK-LABEL: @nonnull_deref_arg(
-; CHECK-NEXT:    ret i1 false
-;
-  %cmp = icmp eq ptr %i, null
-  ret i1 %cmp
-}
-
-define i1 @nonnull_deref_arg_no_null_opt(ptr dereferenceable(4) %i) #0 {
-; CHECK-LABEL: @nonnull_deref_arg_no_null_opt(
-; CHECK-NEXT:    ret i1 false
-;
-  %cmp = icmp eq ptr %i, null
-  ret i1 %cmp
-}
-define i1 @nonnull_deref_as_arg(ptr addrspace(1) dereferenceable(4) %i) {
-; CHECK-LABEL: @nonnull_deref_as_arg(
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr addrspace(1) [[I:%.*]], null
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %cmp = icmp eq ptr addrspace(1) %i, null
-  ret i1 %cmp
-}
-
-declare nonnull ptr @returns_nonnull_helper()
-define i1 @returns_nonnull() {
-; CHECK-LABEL: @returns_nonnull(
-; CHECK-NEXT:    [[CALL:%.*]] = call nonnull ptr @returns_nonnull_helper()
-; CHECK-NEXT:    ret i1 false
-;
-  %call = call nonnull ptr @returns_nonnull_helper()
-  %cmp = icmp eq ptr %call, null
-  ret i1 %cmp
-}
-
-declare dereferenceable(4) ptr @returns_nonnull_deref_helper()
-define i1 @returns_nonnull_deref() {
-; CHECK-LABEL: @returns_nonnull_deref(
-; CHECK-NEXT:    [[CALL:%.*]] = call dereferenceable(4) ptr @returns_nonnull_deref_helper()
-; CHECK-NEXT:    ret i1 false
-;
-  %call = call dereferenceable(4) ptr @returns_nonnull_deref_helper()
-  %cmp = icmp eq ptr %call, null
-  ret i1 %cmp
-}
-
-define i1 @returns_nonnull_deref_no_null_opt () #0 {
-; CHECK-LABEL: @returns_nonnull_deref_no_null_opt(
-; CHECK-NEXT:    [[CALL:%.*]] = call dereferenceable(4) ptr @returns_nonnull_deref_helper()
-; CHECK-NEXT:    ret i1 false
-;
-  %call = call dereferenceable(4) ptr @returns_nonnull_deref_helper()
-  %cmp = icmp eq ptr %call, null
-  ret i1 %cmp
-}
-
-declare dereferenceable(4) ptr addrspace(1) @returns_nonnull_deref_as_helper()
-define i1 @returns_nonnull_as_deref() {
-; CHECK-LABEL: @returns_nonnull_as_deref(
-; CHECK-NEXT:    [[CALL:%.*]] = call dereferenceable(4) ptr addrspace(1) @returns_nonnull_deref_as_helper()
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr addrspace(1) [[CALL]], null
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %call = call dereferenceable(4) ptr addrspace(1) @returns_nonnull_deref_as_helper()
-  %cmp = icmp eq ptr addrspace(1) %call, null
-  ret i1 %cmp
-}
-
-define i1 @nonnull_load(ptr %addr) {
-; CHECK-LABEL: @nonnull_load(
-; CHECK-NEXT:    ret i1 false
-;
-  %ptr = load ptr, ptr %addr, !nonnull !{}
-  %cmp = icmp eq ptr %ptr, null
-  ret i1 %cmp
-}
-
-define i1 @nonnull_load_as_outer(ptr addrspace(1) %addr) {
-; CHECK-LABEL: @nonnull_load_as_outer(
-; CHECK-NEXT:    ret i1 false
-;
-  %ptr = load ptr, ptr addrspace(1) %addr, !nonnull !{}
-  %cmp = icmp eq ptr %ptr, null
-  ret i1 %cmp
-}
-define i1 @nonnull_load_as_inner(ptr %addr) {
-; CHECK-LABEL: @nonnull_load_as_inner(
-; CHECK-NEXT:    [[PTR:%.*]] = load ptr addrspace(1), ptr [[ADDR:%.*]], align 8, !nonnull [[META0:![0-9]+]]
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr addrspace(1) [[PTR]], null
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %ptr = load ptr addrspace(1), ptr %addr, !nonnull !{}
-  %cmp = icmp eq ptr addrspace(1) %ptr, null
-  ret i1 %cmp
-}
-
-; If a bit is known to be zero for A and known to be one for B,
-; then A and B cannot be equal.
-define i1 @icmp_eq_const(i32 %a) {
-; CHECK-LABEL: @icmp_eq_const(
-; CHECK-NEXT:    ret i1 false
-;
-  %b = mul nsw i32 %a, -2
-  %c = icmp eq i32 %b, 1
-  ret i1 %c
-}
-
-define <2 x i1> @icmp_eq_const_vec(<2 x i32> %a) {
-; CHECK-LABEL: @icmp_eq_const_vec(
-; CHECK-NEXT:    ret <2 x i1> zeroinitializer
-;
-  %b = mul nsw <2 x i32> %a, <i32 -2, i32 -2>
-  %c = icmp eq <2 x i32> %b, <i32 1, i32 1>
-  ret <2 x i1> %c
-}
-
-define i1 @icmp_ne_const(i32 %a) {
-; CHECK-LABEL: @icmp_ne_const(
-; CHECK-NEXT:    ret i1 true
-;
-  %b = mul nsw i32 %a, -2
-  %c = icmp ne i32 %b, 1
-  ret i1 %c
-}
-
-define <2 x i1> @icmp_ne_const_vec(<2 x i32> %a) {
-; CHECK-LABEL: @icmp_ne_const_vec(
-; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
-;
-  %b = mul nsw <2 x i32> %a, <i32 -2, i32 -2>
-  %c = icmp ne <2 x i32> %b, <i32 1, i32 1>
-  ret <2 x i1> %c
-}
-
-define i1 @icmp_sdiv_int_min(i32 %a) {
-; CHECK-LABEL: @icmp_sdiv_int_min(
-; CHECK-NEXT:    [[DIV:%.*]] = sdiv i32 -2147483648, [[A:%.*]]
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[DIV]], -1073741824
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %div = sdiv i32 -2147483648, %a
-  %cmp = icmp ne i32 %div, -1073741824
-  ret i1 %cmp
-
-}
-
-define i1 @icmp_sdiv_pr20288(i64 %a) {
-; CHECK-LABEL: @icmp_sdiv_pr20288(
-; CHECK-NEXT:    [[DIV:%.*]] = sdiv i64 [[A:%.*]], -8589934592
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i64 [[DIV]], 1073741824
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %div = sdiv i64 %a, -8589934592
-  %cmp = icmp ne i64 %div, 1073741824
-  ret i1 %cmp
-
-}
-
-define i1 @icmp_sdiv_neg1(i64 %a) {
-; CHECK-LABEL: @icmp_sdiv_neg1(
-; CHECK-NEXT:    [[DIV:%.*]] = sdiv i64 [[A:%.*]], -1
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i64 [[DIV]], 1073741824
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %div = sdiv i64 %a, -1
-  %cmp = icmp ne i64 %div, 1073741824
-  ret i1 %cmp
-
-}
-
-define i1 @icmp_known_bits(i4 %x, i4 %y) {
-; CHECK-LABEL: @icmp_known_bits(
-; CHECK-NEXT:    ret i1 false
-;
-  %and1 = and i4 %y, -7
-  %and2 = and i4 %x, -7
-  %or1 = or i4 %and1, 2
-  %or2 = or i4 %and2, 2
-  %add = add i4 %or1, %or2
-  %cmp = icmp eq i4 %add, 0
-  ret i1 %cmp
-}
-
-define i1 @icmp_known_bits_vec(<2 x i4> %x, <2 x i4> %y) {
-; CHECK-LABEL: @icmp_known_bits_vec(
-; CHECK-NEXT:    ret i1 false
-;
-  %and1 = and <2 x i4> %y, <i4 -7, i4 -1>
-  %and2 = and <2 x i4> %x, <i4 -7, i4 -1>
-  %or1 = or <2 x i4> %and1, <i4 2, i4 2>
-  %or2 = or <2 x i4> %and2, <i4 2, i4 2>
-  %add = add <2 x i4> %or1, %or2
-  %ext = extractelement <2 x i4> %add,i32 0
-  %cmp = icmp eq i4 %ext, 0
-  ret i1 %cmp
-}
-
-define i1 @icmp_shl_nuw_1(i64 %a) {
-; CHECK-LABEL: @icmp_shl_nuw_1(
-; CHECK-NEXT:    ret i1 true
-;
-  %shl = shl nuw i64 1, %a
-  %cmp = icmp ne i64 %shl, 0
-  ret i1 %cmp
-}
-
-define i1 @icmp_shl_1_V_ugt_2147483648(i32 %V) {
-; CHECK-LABEL: @icmp_shl_1_V_ugt_2147483648(
-; CHECK-NEXT:    ret i1 false
-;
-  %shl = shl i32 1, %V
-  %cmp = icmp ugt i32 %shl, 2147483648
-  ret i1 %cmp
-}
-
-define <2 x i1> @icmp_shl_1_ugt_signmask(<2 x i8> %V) {
-; CHECK-LABEL: @icmp_shl_1_ugt_signmask(
-; CHECK-NEXT:    ret <2 x i1> zeroinitializer
-;
-  %shl = shl <2 x i8> <i8 1, i8 1>, %V
-  %cmp = icmp ugt <2 x i8> %shl, <i8 128, i8 128>
-  ret <2 x i1> %cmp
-}
-
-define <2 x i1> @icmp_shl_1_ugt_signmask_undef(<2 x i8> %V) {
-; CHECK-LABEL: @icmp_shl_1_ugt_signmask_undef(
-; CHECK-NEXT:    [[SHL:%.*]] = shl <2 x i8> <i8 1, i8 1>, [[V:%.*]]
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt <2 x i8> [[SHL]], <i8 -128, i8 undef>
-; CHECK-NEXT:    ret <2 x i1> [[CMP]]
-;
-  %shl = shl <2 x i8> <i8 1, i8 1>, %V
-  %cmp = icmp ugt <2 x i8> %shl, <i8 128, i8 undef>
-  ret <2 x i1> %cmp
-}
-
-define <2 x i1> @icmp_shl_1_ugt_signmask_undef2(<2 x i8> %V) {
-; CHECK-LABEL: @icmp_shl_1_ugt_signmask_undef2(
-; CHECK-NEXT:    [[SHL:%.*]] = shl <2 x i8> <i8 1, i8 undef>, [[V:%.*]]
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt <2 x i8> [[SHL]], <i8 undef, i8 -128>
-; CHECK-NEXT:    ret <2 x i1> [[CMP]]
-;
-  %shl = shl <2 x i8> <i8 1, i8 undef>, %V
-  %cmp = icmp ugt <2 x i8> %shl, <i8 undef, i8 128>
-  ret <2 x i1> %cmp
-}
-
-define i1 @icmp_shl_1_V_ule_2147483648(i32 %V) {
-; CHECK-LABEL: @icmp_shl_1_V_ule_2147483648(
-; CHECK-NEXT:    ret i1 true
-;
-  %shl = shl i32 1, %V
-  %cmp = icmp ule i32 %shl, 2147483648
-  ret i1 %cmp
-}
-
-define <2 x i1> @icmp_shl_1_ule_signmask(<2 x i8> %V) {
-; CHECK-LABEL: @icmp_shl_1_ule_signmask(
-; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
-;
-  %shl = shl <2 x i8> <i8 1, i8 1>, %V
-  %cmp = icmp ule <2 x i8> %shl, <i8 128, i8 128>
-  ret <2 x i1> %cmp
-}
-
-define <2 x i1> @icmp_shl_1_ule_signmask_undef(<2 x i8> %V) {
-; CHECK-LABEL: @icmp_shl_1_ule_signmask_undef(
-; CHECK-NEXT:    [[SHL:%.*]] = shl <2 x i8> <i8 1, i8 1>, [[V:%.*]]
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ule <2 x i8> [[SHL]], <i8 -128, i8 undef>
-; CHECK-NEXT:    ret <2 x i1> [[CMP]]
-;
-  %shl = shl <2 x i8> <i8 1, i8 1>, %V
-  %cmp = icmp ule <2 x i8> %shl, <i8 128, i8 undef>
-  ret <2 x i1> %cmp
-}
-
-define <2 x i1> @icmp_shl_1_ule_signmask_undef2(<2 x i8> %V) {
-; CHECK-LABEL: @icmp_shl_1_ule_signmask_undef2(
-; CHECK-NEXT:    [[SHL:%.*]] = shl <2 x i8> <i8 1, i8 undef>, [[V:%.*]]
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ule <2 x i8> [[SHL]], <i8 undef, i8 -128>
-; CHECK-NEXT:    ret <2 x i1> [[CMP]]
-;
-  %shl = shl <2 x i8> <i8 1, i8 undef>, %V
-  %cmp = icmp ule <2 x i8> %shl, <i8 undef, i8 128>
-  ret <2 x i1> %cmp
-}
-
-define i1 @shl_1_cmp_eq_nonpow2(i32 %x) {
-; CHECK-LABEL: @shl_1_cmp_eq_nonpow2(
-; CHECK-NEXT:    ret i1 false
-;
-  %s = shl i32 1, %x
-  %c = icmp eq i32 %s, 31
-  ret i1 %c
-}
-
-define <2 x i1> @shl_1_cmp_eq_nonpow2_splat(<2 x i32> %x) {
-; CHECK-LABEL: @shl_1_cmp_eq_nonpow2_splat(
-; CHECK-NEXT:    ret <2 x i1> zeroinitializer
-;
-  %s = shl <2 x i32> <i32 1, i32 1>, %x
-  %c = icmp eq <2 x i32> %s, <i32 31, i32 31>
-  ret <2 x i1> %c
-}
-
-define <2 x i1> @shl_1_cmp_eq_nonpow2_splat_undef(<2 x i32> %x) {
-; CHECK-LABEL: @shl_1_cmp_eq_nonpow2_splat_undef(
-; CHECK-NEXT:    [[S:%.*]] = shl <2 x i32> <i32 1, i32 1>, [[X:%.*]]
-; CHECK-NEXT:    [[C:%.*]] = icmp eq <2 x i32> [[S]], <i32 31, i32 undef>
-; CHECK-NEXT:    ret <2 x i1> [[C]]
-;
-  %s = shl <2 x i32> <i32 1, i32 1>, %x
-  %c = icmp eq <2 x i32> %s, <i32 31, i32 undef>
-  ret <2 x i1> %c
-}
-
-define i1 @shl_1_cmp_ne_nonpow2(i32 %x) {
-; CHECK-LABEL: @shl_1_cmp_ne_nonpow2(
-; CHECK-NEXT:    ret i1 true
-;
-  %s = shl i32 1, %x
-  %c = icmp ne i32 %s, 42
-  ret i1 %c
-}
-
-define <2 x i1> @shl_1_cmp_ne_nonpow2_splat(<2 x i32> %x) {
-; CHECK-LABEL: @shl_1_cmp_ne_nonpow2_splat(
-; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
-;
-  %s = shl <2 x i32> <i32 1, i32 1>, %x
-  %c = icmp ne <2 x i32> %s, <i32 42, i32 42>
-  ret <2 x i1> %c
-}
-
-define <2 x i1> @shl_1_cmp_ne_nonpow2_splat_undef(<2 x i32> %x) {
-; CHECK-LABEL: @shl_1_cmp_ne_nonpow2_splat_undef(
-; CHECK-NEXT:    [[S:%.*]] = shl <2 x i32> <i32 undef, i32 1>, [[X:%.*]]
-; CHECK-NEXT:    [[C:%.*]] = icmp ne <2 x i32> [[S]], <i32 42, i32 undef>
-; CHECK-NEXT:    ret <2 x i1> [[C]]
-;
-  %s = shl <2 x i32> <i32 undef, i32 1>, %x
-  %c = icmp ne <2 x i32> %s, <i32 42, i32 undef>
-  ret <2 x i1> %c
-}
-
-define i1 @shl_pow2_cmp_eq_nonpow2(i32 %x) {
-; CHECK-LABEL: @shl_pow2_cmp_eq_nonpow2(
-; CHECK-NEXT:    ret i1 false
-;
-  %s = shl i32 4, %x
-  %c = icmp eq i32 %s, 31
-  ret i1 %c
-}
-
-define <2 x i1> @shl_pow21_cmp_ne_nonpow2_splat_undef(<2 x i32> %x) {
-; CHECK-LABEL: @shl_pow21_cmp_ne_nonpow2_splat_undef(
-; CHECK-NEXT:    [[S:%.*]] = shl <2 x i32> <i32 undef, i32 4>, [[X:%.*]]
-; CHECK-NEXT:    [[C:%.*]] = icmp ne <2 x i32> [[S]], <i32 31, i32 undef>
-; CHECK-NEXT:    ret <2 x i1> [[C]]
-;
-  %s = shl <2 x i32> <i32 undef, i32 4>, %x
-  %c = icmp ne <2 x i32> %s, <i32 31, i32 undef>
-  ret <2 x i1> %c
-}
-
-; Negative test - overflowing shift could be zero.
-
-define i1 @shl_pow2_cmp_ne_zero(i32 %x) {
-; CHECK-LABEL: @shl_pow2_cmp_ne_zero(
-; CHECK-NEXT:    [[S:%.*]] = shl i32 16, [[X:%.*]]
-; CHECK-NEXT:    [[C:%.*]] = icmp ne i32 [[S]], 0
-; CHECK-NEXT:    ret i1 [[C]]
-;
-  %s = shl i32 16, %x
-  %c = icmp ne i32 %s, 0
-  ret i1 %c
-}
-
-; Negative test - overflowing shift could be zero.
-
-define <2 x i1> @shl_pow2_cmp_ne_zero_splat(<2 x i32> %x) {
-; CHECK-LABEL: @shl_pow2_cmp_ne_zero_splat(
-; CHECK-NEXT:    [[S:%.*]] = shl <2 x i32> <i32 16, i32 16>, [[X:%.*]]
-; CHECK-NEXT:    [[C:%.*]] = icmp ne <2 x i32> [[S]], zeroinitializer
-; CHECK-NEXT:    ret <2 x i1> [[C]]
-;
-  %s = shl <2 x i32> <i32 16, i32 16>, %x
-  %c = icmp ne <2 x i32> %s, zeroinitializer
-  ret <2 x i1> %c
-}
-
-define i1 @shl_pow2_cmp_eq_zero_nuw(i32 %x) {
-; CHECK-LABEL: @shl_pow2_cmp_eq_zero_nuw(
-; CHECK-NEXT:    ret i1 false
-;
-  %s = shl nuw i32 16, %x
-  %c = icmp eq i32 %s, 0
-  ret i1 %c
-}
-
-define <2 x i1> @shl_pow2_cmp_ne_zero_nuw_splat_undef(<2 x i32> %x) {
-; CHECK-LABEL: @shl_pow2_cmp_ne_zero_nuw_splat_undef(
-; CHECK-NEXT:    [[S:%.*]] = shl nuw <2 x i32> <i32 16, i32 undef>, [[X:%.*]]
-; CHECK-NEXT:    [[C:%.*]] = icmp ne <2 x i32> [[S]], <i32 undef, i32 0>
-; CHECK-NEXT:    ret <2 x i1> [[C]]
-;
-  %s = shl nuw <2 x i32> <i32 16, i32 undef>, %x
-  %c = icmp ne <2 x i32> %s, <i32 undef, i32 0>
-  ret <2 x i1> %c
-}
-
-define i1 @shl_pow2_cmp_ne_zero_nsw(i32 %x) {
-; CHECK-LABEL: @shl_pow2_cmp_ne_zero_nsw(
-; CHECK-NEXT:    ret i1 true
-;
-  %s = shl nsw i32 16, %x
-  %c = icmp ne i32 %s, 0
-  ret i1 %c
-}
-
-define <2 x i1> @shl_pow2_cmp_eq_zero_nsw_splat_undef(<2 x i32> %x) {
-; CHECK-LABEL: @shl_pow2_cmp_eq_zero_nsw_splat_undef(
-; CHECK-NEXT:    [[S:%.*]] = shl nsw <2 x i32> <i32 undef, i32 16>, [[X:%.*]]
-; CHECK-NEXT:    [[C:%.*]] = icmp eq <2 x i32> [[S]], <i32 0, i32 undef>
-; CHECK-NEXT:    ret <2 x i1> [[C]]
-;
-  %s = shl nsw <2 x i32> <i32 undef, i32 16>, %x
-  %c = icmp eq <2 x i32> %s, <i32 0, i32 undef>
-  ret <2 x i1> %c
-}
-
-define i1 @tautological1(i32 %A, i32 %B) {
-; CHECK-LABEL: @tautological1(
-; CHECK-NEXT:    ret i1 false
-;
-  %C = and i32 %A, %B
-  %D = icmp ugt i32 %C, %A
-  ret i1 %D
-}
-
-define i1 @tautological2(i32 %A, i32 %B) {
-; CHECK-LABEL: @tautological2(
-; CHECK-NEXT:    ret i1 true
-;
-  %C = and i32 %A, %B
-  %D = icmp ule i32 %C, %A
-  ret i1 %D
-}
-
-define i1 @tautological3(i32 %A, i32 %B) {
-; CHECK-LABEL: @tautological3(
-; CHECK-NEXT:    ret i1 true
-;
-  %C = or i32 %A, %B
-  %D = icmp ule i32 %A, %C
-  ret i1 %D
-}
-
-define i1 @tautological4(i32 %A, i32 %B) {
-; CHECK-LABEL: @tautological4(
-; CHECK-NEXT:    ret i1 false
-;
-  %C = or i32 %A, %B
-  %D = icmp ugt i32 %A, %C
-  ret i1 %D
-}
-
-define i1 @tautological5(i32 %A, i32 %B) {
-; CHECK-LABEL: @tautological5(
-; CHECK-NEXT:    ret i1 false
-;
-  %C = or i32 %A, %B
-  %D = icmp ult i32 %C, %A
-  ret i1 %D
-}
-
-define i1 @tautological6(i32 %A, i32 %B) {
-; CHECK-LABEL: @tautological6(
-; CHECK-NEXT:    ret i1 true
-;
-  %C = or i32 %A, %B
-  %D = icmp uge i32 %C, %A
-  ret i1 %D
-}
-
-define i1 @tautological7(i32 %A, i32 %B) {
-; CHECK-LABEL: @tautological7(
-; CHECK-NEXT:    ret i1 true
-;
-  %C = and i32 %A, %B
-  %D = icmp uge i32 %A, %C
-  ret i1 %D
-}
-
-define i1 @tautological8(i32 %A, i32 %B) {
-; CHECK-LABEL: @tautological8(
-; CHECK-NEXT:    ret i1 false
-;
-  %C = and i32 %A, %B
-  %D = icmp ult i32 %A, %C
-  ret i1 %D
-}
-
-define i1 @tautological9(i32 %A) {
-; CHECK-LABEL: @tautological9(
-; CHECK-NEXT:    ret i1 false
-;
-  %C1 = and i32 %A, 1
-  %C2 = and i32 %A, 3
-  %D = icmp ugt i32 %C1, %C2
-  ret i1 %D
-}
-
-define <2 x i1> @tautological9_vec(<2 x i32> %A) {
-; CHECK-LABEL: @tautological9_vec(
-; CHECK-NEXT:    ret <2 x i1> zeroinitializer
-;
-  %C1 = and <2 x i32> %A, <i32 1, i32 1>
-  %C2 = and <2 x i32> %A, <i32 3, i32 3>
-  %D = icmp ugt <2 x i32> %C1, %C2
-  ret <2 x i1> %D
-}
-
-define i1 @tautological10(i32 %A) {
-; CHECK-LABEL: @tautological10(
-; CHECK-NEXT:    ret i1 true
-;
-  %C1 = and i32 %A, 1
-  %C2 = and i32 %A, 3
-  %D = icmp ule i32 %C1, %C2
-  ret i1 %D
-}
-
-define i1 @tautological11(i32 %A) {
-; CHECK-LABEL: @tautological11(
-; CHECK-NEXT:    ret i1 true
-;
-  %C1 = or i32 %A, 1
-  %C2 = or i32 %A, 3
-  %D = icmp ule i32 %C1, %C2
-  ret i1 %D
-}
-
-define i1 @tautological12(i32 %A) {
-; CHECK-LABEL: @tautological12(
-; CHECK-NEXT:    ret i1 false
-;
-  %C1 = or i32 %A, 1
-  %C2 = or i32 %A, 3
-  %D = icmp ugt i32 %C1, %C2
-  ret i1 %D
-}
-
-define i1 @tautological13(i32 %A) {
-; CHECK-LABEL: @tautological13(
-; CHECK-NEXT:    ret i1 false
-;
-  %C1 = or i32 %A, 1
-  %C2 = or i32 %A, 3
-  %D = icmp ult i32 %C2, %C1
-  ret i1 %D
-}
-
-define i1 @tautological14(i32 %A) {
-; CHECK-LABEL: @tautological14(
-; CHECK-NEXT:    ret i1 true
-;
-  %C1 = or i32 %A, 1
-  %C2 = or i32 %A, 3
-  %D = icmp uge i32 %C2, %C1
-  ret i1 %D
-}
-
-define i1 @tautological15(i32 %A) {
-; CHECK-LABEL: @tautological15(
-; CHECK-NEXT:    ret i1 true
-;
-  %C1 = and i32 %A, 1
-  %C2 = and i32 %A, 3
-  %D = icmp uge i32 %C2, %C1
-  ret i1 %D
-}
-
-define i1 @tautological16(i32 %A) {
-; CHECK-LABEL: @tautological16(
-; CHECK-NEXT:    ret i1 false
-;
-  %C1 = and i32 %A, 1
-  %C2 = and i32 %A, 3
-  %D = icmp ult i32 %C2, %C1
-  ret i1 %D
-}
-
-define i1 @tautological9_negative(i32 %A) {
-; CHECK-LABEL: @tautological9_negative(
-; CHECK-NEXT:    [[C1:%.*]] = and i32 [[A:%.*]], 1
-; CHECK-NEXT:    [[C2:%.*]] = and i32 [[A]], 2
-; CHECK-NEXT:    [[D:%.*]] = icmp ugt i32 [[C1]], [[C2]]
-; CHECK-NEXT:    ret i1 [[D]]
-;
-  %C1 = and i32 %A, 1
-  %C2 = and i32 %A, 2
-  %D = icmp ugt i32 %C1, %C2
-  ret i1 %D
-}
-
-define i1 @tautological10_negative(i32 %A) {
-; CHECK-LABEL: @tautological10_negative(
-; CHECK-NEXT:    [[C1:%.*]] = and i32 [[A:%.*]], 1
-; CHECK-NEXT:    [[C2:%.*]] = and i32 [[A]], 2
-; CHECK-NEXT:    [[D:%.*]] = icmp ule i32 [[C1]], [[C2]]
-; CHECK-NEXT:    ret i1 [[D]]
-;
-  %C1 = and i32 %A, 1
-  %C2 = and i32 %A, 2
-  %D = icmp ule i32 %C1, %C2
-  ret i1 %D
-}
-
-define i1 @tautological11_negative(i32 %A) {
-; CHECK-LABEL: @tautological11_negative(
-; CHECK-NEXT:    [[C1:%.*]] = or i32 [[A:%.*]], 1
-; CHECK-NEXT:    [[C2:%.*]] = or i32 [[A]], 2
-; CHECK-NEXT:    [[D:%.*]] = icmp ule i32 [[C1]], [[C2]]
-; CHECK-NEXT:    ret i1 [[D]]
-;
-  %C1 = or i32 %A, 1
-  %C2 = or i32 %A, 2
-  %D = icmp ule i32 %C1, %C2
-  ret i1 %D
-}
-
-define i1 @tautological12_negative(i32 %A) {
-; CHECK-LABEL: @tautological12_negative(
-; CHECK-NEXT:    [[C1:%.*]] = or i32 [[A:%.*]], 1
-; CHECK-NEXT:    [[C2:%.*]] = or i32 [[A]], 2
-; CHECK-NEXT:    [[D:%.*]] = icmp ugt i32 [[C1]], [[C2]]
-; CHECK-NEXT:    ret i1 [[D]]
-;
-  %C1 = or i32 %A, 1
-  %C2 = or i32 %A, 2
-  %D = icmp ugt i32 %C1, %C2
-  ret i1 %D
-}
-
-define i1 @tautological13_negative(i32 %A) {
-; CHECK-LABEL: @tautological13_negative(
-; CHECK-NEXT:    [[C1:%.*]] = or i32 [[A:%.*]], 1
-; CHECK-NEXT:    [[C2:%.*]] = or i32 [[A]], 2
-; CHECK-NEXT:    [[D:%.*]] = icmp ult i32 [[C2]], [[C1]]
-; CHECK-NEXT:    ret i1 [[D]]
-;
-  %C1 = or i32 %A, 1
-  %C2 = or i32 %A, 2
-  %D = icmp ult i32 %C2, %C1
-  ret i1 %D
-}
-
-define i1 @tautological14_negative(i32 %A) {
-; CHECK-LABEL: @tautological14_negative(
-; CHECK-NEXT:    [[C1:%.*]] = or i32 [[A:%.*]], 1
-; CHECK-NEXT:    [[C2:%.*]] = or i32 [[A]], 2
-; CHECK-NEXT:    [[D:%.*]] = icmp uge i32 [[C2]], [[C1]]
-; CHECK-NEXT:    ret i1 [[D]]
-;
-  %C1 = or i32 %A, 1
-  %C2 = or i32 %A, 2
-  %D = icmp uge i32 %C2, %C1
-  ret i1 %D
-}
-
-define i1 @tautological15_negative(i32 %A) {
-; CHECK-LABEL: @tautological15_negative(
-; CHECK-NEXT:    [[C1:%.*]] = and i32 [[A:%.*]], 1
-; CHECK-NEXT:    [[C2:%.*]] = and i32 [[A]], 2
-; CHECK-NEXT:    [[D:%.*]] = icmp uge i32 [[C2]], [[C1]]
-; CHECK-NEXT:    ret i1 [[D]]
-;
-  %C1 = and i32 %A, 1
-  %C2 = and i32 %A, 2
-  %D = icmp uge i32 %C2, %C1
-  ret i1 %D
-}
-
-define i1 @tautological16_negative(i32 %A) {
-; CHECK-LABEL: @tautological16_negative(
-; CHECK-NEXT:    [[C1:%.*]] = and i32 [[A:%.*]], 1
-; CHECK-NEXT:    [[C2:%.*]] = and i32 [[A]], 2
-; CHECK-NEXT:    [[D:%.*]] = icmp ult i32 [[C2]], [[C1]]
-; CHECK-NEXT:    ret i1 [[D]]
-;
-  %C1 = and i32 %A, 1
-  %C2 = and i32 %A, 2
-  %D = icmp ult i32 %C2, %C1
-  ret i1 %D
-}
-
-define i1 @tautological17_subset1(i32 %A) {
-; CHECK-LABEL: @tautological17_subset1(
-; CHECK-NEXT:    ret i1 false
-;
-  %C1 = and i32 %A, 1
-  %C2 = and i32 %A, 3
-  %D = icmp sgt i32 %C1, %C2
-  ret i1 %D
-}
-
-define i1 @tautological17_subset2(i32 %A) {
-; CHECK-LABEL: @tautological17_subset2(
-; CHECK-NEXT:    ret i1 false
-;
-  %C1 = and i32 %A, -4
-  %C2 = and i32 %A, -3
-  %D = icmp sgt i32 %C1, %C2
-  ret i1 %D
-}
-
-define i1 @tautological17_negative(i32 %A) {
-; CHECK-LABEL: @tautological17_negative(
-; CHECK-NEXT:    [[C1:%.*]] = and i32 [[A:%.*]], 1
-; CHECK-NEXT:    [[C2:%.*]] = and i32 [[A]], -3
-; CHECK-NEXT:    [[D:%.*]] = icmp sgt i32 [[C1]], [[C2]]
-; CHECK-NEXT:    ret i1 [[D]]
-;
-  %C1 = and i32 %A, 1
-  %C2 = and i32 %A, -3
-  %D = icmp sgt i32 %C1, %C2
-  ret i1 %D
-}
-
-define i1 @tautological18_subset1(i32 %A) {
-; CHECK-LABEL: @tautological18_subset1(
-; CHECK-NEXT:    ret i1 true
-;
-  %C1 = and i32 %A, 1
-  %C2 = and i32 %A, 3
-  %D = icmp sle i32 %C1, %C2
-  ret i1 %D
-}
-
-define i1 @tautological18_subset2(i32 %A) {
-; CHECK-LABEL: @tautological18_subset2(
-; CHECK-NEXT:    ret i1 true
-;
-  %C1 = and i32 %A, -4
-  %C2 = and i32 %A, -3
-  %D = icmp sle i32 %C1, %C2
-  ret i1 %D
-}
-
-define i1 @tautological18_negative(i32 %A) {
-; CHECK-LABEL: @tautological18_negative(
-; CHECK-NEXT:    [[C1:%.*]] = and i32 [[A:%.*]], 1
-; CHECK-NEXT:    [[C2:%.*]] = and i32 [[A]], -3
-; CHECK-NEXT:    [[D:%.*]] = icmp sle i32 [[C1]], [[C2]]
-; CHECK-NEXT:    ret i1 [[D]]
-;
-  %C1 = and i32 %A, 1
-  %C2 = and i32 %A, -3
-  %D = icmp sle i32 %C1, %C2
-  ret i1 %D
-}
-
-define i1 @tautological19_subset1(i32 %A) {
-; CHECK-LABEL: @tautological19_subset1(
-; CHECK-NEXT:    ret i1 false
-;
-  %C1 = or i32 %A, 1
-  %C2 = or i32 %A, 3
-  %D = icmp sgt i32 %C1, %C2
-  ret i1 %D
-}
-
-define i1 @tautological19_subset2(i32 %A) {
-; CHECK-LABEL: @tautological19_subset2(
-; CHECK-NEXT:    ret i1 false
-;
-  %C1 = and i32 %A, -4
-  %C2 = and i32 %A, -3
-  %D = icmp sgt i32 %C1, %C2
-  ret i1 %D
-}
-
-define i1 @tautological19_negative(i32 %A) {
-; CHECK-LABEL: @tautological19_negative(
-; CHECK-NEXT:    [[C1:%.*]] = and i32 [[A:%.*]], 1
-; CHECK-NEXT:    [[C2:%.*]] = and i32 [[A]], -3
-; CHECK-NEXT:    [[D:%.*]] = icmp sgt i32 [[C1]], [[C2]]
-; CHECK-NEXT:    ret i1 [[D]]
-;
-  %C1 = and i32 %A, 1
-  %C2 = and i32 %A, -3
-  %D = icmp sgt i32 %C1, %C2
-  ret i1 %D
-}
-
-define i1 @tautological20_subset1(i32 %A) {
-; CHECK-LABEL: @tautological20_subset1(
-; CHECK-NEXT:    ret i1 true
-;
-  %C1 = and i32 %A, 1
-  %C2 = and i32 %A, 3
-  %D = icmp sle i32 %C1, %C2
-  ret i1 %D
-}
-
-define i1 @tautological20_subset2(i32 %A) {
-; CHECK-LABEL: @tautological20_subset2(
-; CHECK-NEXT:    ret i1 true
-;
-  %C1 = and i32 %A, -4
-  %C2 = and i32 %A, -3
-  %D = icmp sle i32 %C1, %C2
-  ret i1 %D
-}
-
-define i1 @tautological20_negative(i32 %A) {
-; CHECK-LABEL: @tautological20_negative(
-; CHECK-NEXT:    [[C1:%.*]] = and i32 [[A:%.*]], 1
-; CHECK-NEXT:    [[C2:%.*]] = and i32 [[A]], -3
-; CHECK-NEXT:    [[D:%.*]] = icmp sle i32 [[C1]], [[C2]]
-; CHECK-NEXT:    ret i1 [[D]]
-;
-  %C1 = and i32 %A, 1
-  %C2 = and i32 %A, -3
-  %D = icmp sle i32 %C1, %C2
-  ret i1 %D
-}
-
-declare void @helper_i1(i1)
-; Series of tests for icmp s[lt|ge] (or A, B), A and icmp s[gt|le] A, (or A, B)
-define void @icmp_slt_sge_or(i32 %Ax, i32 %Bx) {
-; 'p' for positive, 'n' for negative, 'x' for potentially either.
-; %D is 'icmp slt (or A, B), A'
-; %E is 'icmp sge (or A, B), A' making it the not of %D
-; %F is 'icmp sgt A, (or A, B)' making it the same as %D
-; %G is 'icmp sle A, (or A, B)' making it the not of %D
-; CHECK-LABEL: @icmp_slt_sge_or(
-; CHECK-NEXT:    [[APOS:%.*]] = and i32 [[AX:%.*]], 2147483647
-; CHECK-NEXT:    [[BNEG:%.*]] = or i32 [[BX:%.*]], -2147483648
-; CHECK-NEXT:    [[CPX:%.*]] = or i32 [[APOS]], [[BX]]
-; CHECK-NEXT:    [[DPX:%.*]] = icmp slt i32 [[CPX]], [[APOS]]
-; CHECK-NEXT:    [[EPX:%.*]] = icmp sge i32 [[CPX]], [[APOS]]
-; CHECK-NEXT:    [[FPX:%.*]] = icmp sgt i32 [[APOS]], [[CPX]]
-; CHECK-NEXT:    [[GPX:%.*]] = icmp sle i32 [[APOS]], [[CPX]]
-; CHECK-NEXT:    [[CXX:%.*]] = or i32 [[AX]], [[BX]]
-; CHECK-NEXT:    [[DXX:%.*]] = icmp slt i32 [[CXX]], [[AX]]
-; CHECK-NEXT:    [[EXX:%.*]] = icmp sge i32 [[CXX]], [[AX]]
-; CHECK-NEXT:    [[FXX:%.*]] = icmp sgt i32 [[AX]], [[CXX]]
-; CHECK-NEXT:    [[GXX:%.*]] = icmp sle i32 [[AX]], [[CXX]]
-; CHECK-NEXT:    [[CXN:%.*]] = or i32 [[AX]], [[BNEG]]
-; CHECK-NEXT:    [[DXN:%.*]] = icmp slt i32 [[CXN]], [[AX]]
-; CHECK-NEXT:    [[EXN:%.*]] = icmp sge i32 [[CXN]], [[AX]]
-; CHECK-NEXT:    [[FXN:%.*]] = icmp sgt i32 [[AX]], [[CXN]]
-; CHECK-NEXT:    [[GXN:%.*]] = icmp sle i32 [[AX]], [[CXN]]
-; CHECK-NEXT:    call void @helper_i1(i1 false)
-; CHECK-NEXT:    call void @helper_i1(i1 true)
-; CHECK-NEXT:    call void @helper_i1(i1 false)
-; CHECK-NEXT:    call void @helper_i1(i1 true)
-; CHECK-NEXT:    call void @helper_i1(i1 [[DPX]])
-; CHECK-NEXT:    call void @helper_i1(i1 [[EPX]])
-; CHECK-NEXT:    call void @helper_i1(i1 [[FPX]])
-; CHECK-NEXT:    call void @helper_i1(i1 [[GPX]])
-; CHECK-NEXT:    call void @helper_i1(i1 true)
-; CHECK-NEXT:    call void @helper_i1(i1 false)
-; CHECK-NEXT:    call void @helper_i1(i1 true)
-; CHECK-NEXT:    call void @helper_i1(i1 false)
-; CHECK-NEXT:    call void @helper_i1(i1 false)
-; CHECK-NEXT:    call void @helper_i1(i1 true)
-; CHECK-NEXT:    call void @helper_i1(i1 false)
-; CHECK-NEXT:    call void @helper_i1(i1 true)
-; CHECK-NEXT:    call void @helper_i1(i1 [[DXX]])
-; CHECK-NEXT:    call void @helper_i1(i1 [[EXX]])
-; CHECK-NEXT:    call void @helper_i1(i1 [[FXX]])
-; CHECK-NEXT:    call void @helper_i1(i1 [[GXX]])
-; CHECK-NEXT:    call void @helper_i1(i1 [[DXN]])
-; CHECK-NEXT:    call void @helper_i1(i1 [[EXN]])
-; CHECK-NEXT:    call void @helper_i1(i1 [[FXN]])
-; CHECK-NEXT:    call void @helper_i1(i1 [[GXN]])
-; CHECK-NEXT:    call void @helper_i1(i1 false)
-; CHECK-NEXT:    call void @helper_i1(i1 true)
-; CHECK-NEXT:    call void @helper_i1(i1 false)
-; CHECK-NEXT:    call void @helper_i1(i1 true)
-; CHECK-NEXT:    call void @helper_i1(i1 false)
-; CHECK-NEXT:    call void @helper_i1(i1 true)
-; CHECK-NEXT:    call void @helper_i1(i1 false)
-; CHECK-NEXT:    call void @helper_i1(i1 true)
-; CHECK-NEXT:    call void @helper_i1(i1 false)
-; CHECK-NEXT:    call void @helper_i1(i1 true)
-; CHECK-NEXT:    call void @helper_i1(i1 false)
-; CHECK-NEXT:    call void @helper_i1(i1 true)
-; CHECK-NEXT:    ret void
-;
-  %Aneg = or i32 %Ax, 2147483648
-  %Apos = and i32 %Ax, 2147483647
-  %Bneg = or i32 %Bx, 2147483648
-  %Bpos = and i32 %Bx, 2147483647
-
-  %Cpp = or i32 %Apos, %Bpos
-  %Dpp = icmp slt i32 %Cpp, %Apos
-  %Epp = icmp sge i32 %Cpp, %Apos
-  %Fpp = icmp sgt i32 %Apos, %Cpp
-  %Gpp = icmp sle i32 %Apos, %Cpp
-  %Cpx = or i32 %Apos, %Bx
-  %Dpx = icmp slt i32 %Cpx, %Apos
-  %Epx = icmp sge i32 %Cpx, %Apos
-  %Fpx = icmp sgt i32 %Apos, %Cpx
-  %Gpx = icmp sle i32 %Apos, %Cpx
-  %Cpn = or i32 %Apos, %Bneg
-  %Dpn = icmp slt i32 %Cpn, %Apos
-  %Epn = icmp sge i32 %Cpn, %Apos
-  %Fpn = icmp sgt i32 %Apos, %Cpn
-  %Gpn = icmp sle i32 %Apos, %Cpn
-
-  %Cxp = or i32 %Ax, %Bpos
-  %Dxp = icmp slt i32 %Cxp, %Ax
-  %Exp = icmp sge i32 %Cxp, %Ax
-  %Fxp = icmp sgt i32 %Ax, %Cxp
-  %Gxp = icmp sle i32 %Ax, %Cxp
-  %Cxx = or i32 %Ax, %Bx
-  %Dxx = icmp slt i32 %Cxx, %Ax
-  %Exx = icmp sge i32 %Cxx, %Ax
-  %Fxx = icmp sgt i32 %Ax, %Cxx
-  %Gxx = icmp sle i32 %Ax, %Cxx
-  %Cxn = or i32 %Ax, %Bneg
-  %Dxn = icmp slt i32 %Cxn, %Ax
-  %Exn = icmp sge i32 %Cxn, %Ax
-  %Fxn = icmp sgt i32 %Ax, %Cxn
-  %Gxn = icmp sle i32 %Ax, %Cxn
-
-  %Cnp = or i32 %Aneg, %Bpos
-  %Dnp = icmp slt i32 %Cnp, %Aneg
-  %Enp = icmp sge i32 %Cnp, %Aneg
-  %Fnp = icmp sgt i32 %Aneg, %Cnp
-  %Gnp = icmp sle i32 %Aneg, %Cnp
-  %Cnx = or i32 %Aneg, %Bx
-  %Dnx = icmp slt i32 %Cnx, %Aneg
-  %Enx = icmp sge i32 %Cnx, %Aneg
-  %Fnx = icmp sgt i32 %Aneg, %Cnx
-  %Gnx = icmp sle i32 %Aneg, %Cnx
-  %Cnn = or i32 %Aneg, %Bneg
-  %Dnn = icmp slt i32 %Cnn, %Aneg
-  %Enn = icmp sge i32 %Cnn, %Aneg
-  %Fnn = icmp sgt i32 %Aneg, %Cnn
-  %Gnn = icmp sle i32 %Aneg, %Cnn
-
-  call void @helper_i1(i1 %Dpp)
-  call void @helper_i1(i1 %Epp)
-  call void @helper_i1(i1 %Fpp)
-  call void @helper_i1(i1 %Gpp)
-  call void @helper_i1(i1 %Dpx)
-  call void @helper_i1(i1 %Epx)
-  call void @helper_i1(i1 %Fpx)
-  call void @helper_i1(i1 %Gpx)
-  call void @helper_i1(i1 %Dpn)
-  call void @helper_i1(i1 %Epn)
-  call void @helper_i1(i1 %Fpn)
-  call void @helper_i1(i1 %Gpn)
-  call void @helper_i1(i1 %Dxp)
-  call void @helper_i1(i1 %Exp)
-  call void @helper_i1(i1 %Fxp)
-  call void @helper_i1(i1 %Gxp)
-  call void @helper_i1(i1 %Dxx)
-  call void @helper_i1(i1 %Exx)
-  call void @helper_i1(i1 %Fxx)
-  call void @helper_i1(i1 %Gxx)
-  call void @helper_i1(i1 %Dxn)
-  call void @helper_i1(i1 %Exn)
-  call void @helper_i1(i1 %Fxn)
-  call void @helper_i1(i1 %Gxn)
-  call void @helper_i1(i1 %Dnp)
-  call void @helper_i1(i1 %Enp)
-  call void @helper_i1(i1 %Fnp)
-  call void @helper_i1(i1 %Gnp)
-  call void @helper_i1(i1 %Dnx)
-  call void @helper_i1(i1 %Enx)
-  call void @helper_i1(i1 %Fnx)
-  call void @helper_i1(i1 %Gnx)
-  call void @helper_i1(i1 %Dnn)
-  call void @helper_i1(i1 %Enn)
-  call void @helper_i1(i1 %Fnn)
-  call void @helper_i1(i1 %Gnn)
-  ret void
-}
-
-define i1 @constant_fold_inttoptr_null() {
-; CHECK-LABEL: @constant_fold_inttoptr_null(
-; CHECK-NEXT:    ret i1 false
-;
-  %x = icmp eq ptr inttoptr (i64 32 to ptr), null
-  ret i1 %x
-}
-
-define i1 @constant_fold_null_inttoptr() {
-; CHECK-LABEL: @constant_fold_null_inttoptr(
-; CHECK-NEXT:    ret i1 false
-;
-  %x = icmp eq ptr null, inttoptr (i64 32 to ptr)
-  ret i1 %x
-}
-
-define i1 @cmp_through_addrspacecast(ptr addrspace(1) %p1) {
-; CHECK-LABEL: @cmp_through_addrspacecast(
-; CHECK-NEXT:    ret i1 true
-;
-  %p0 = addrspacecast ptr addrspace(1) %p1 to ptr
-  %p0.1 = getelementptr inbounds i32, ptr %p0, i64 1
-  %cmp = icmp ne ptr %p0, %p0.1
-  ret i1 %cmp
-}
-
-; Test simplifications for: icmp (X+Y), (X+Z) -> icmp Y,Z
-; Test the overflow check when the RHS has NSW set and constant Z is greater
-; than Y, then we know X+Y also can't overflow.
-
-define i1 @icmp_nsw_1(i32 %V) {
-; CHECK-LABEL: @icmp_nsw_1(
-; CHECK-NEXT:    ret i1 true
-;
-  %add5 = add i32 %V, 5
-  %add6 = add nsw i32 %V, 6
-  %s1 = sext i32 %add5 to i64
-  %s2 = sext i32 %add6 to i64
-  %cmp = icmp slt i64 %s1, %s2
-  ret i1 %cmp
-}
-
-define i1 @icmp_nsw_2(i32 %V) {
-; CHECK-LABEL: @icmp_nsw_2(
-; CHECK-NEXT:    ret i1 true
-;
-  %add5 = add i32 %V, 5
-  %add6 = add nsw i32 %V, 6
-  %cmp = icmp slt i32 %add5, %add6
-  ret i1 %cmp
-}
-
-define i1 @icmp_nsw_22(i32 %V) {
-; CHECK-LABEL: @icmp_nsw_22(
-; CHECK-NEXT:    ret i1 true
-;
-  %add5 = add nsw i32 %V, 5
-  %add6 = add nsw i32 %V, 6
-  %cmp = icmp slt i32 %add5, %add6
-  ret i1 %cmp
-}
-
-define i1 @icmp_nsw_23(i32 %V) {
-; CHECK-LABEL: @icmp_nsw_23(
-; CHECK-NEXT:    [[ADD5:%.*]] = add nsw i32 [[V:%.*]], 5
-; CHECK-NEXT:    [[ADD6:%.*]] = add i32 [[V]], 6
-; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[ADD5]], [[ADD6]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %add5 = add nsw i32 %V, 5
-  %add6 = add i32 %V, 6
-  %cmp = icmp slt i32 %add5, %add6
-  ret i1 %cmp
-}
-
-define i1 @icmp_nsw_false(i32 %V) {
-; CHECK-LABEL: @icmp_nsw_false(
-; CHECK-NEXT:    ret i1 false
-;
-  %add5 = add nsw i32 %V, 6
-  %add6 = add i32 %V, 5
-  %cmp = icmp slt i32 %add5, %add6
-  ret i1 %cmp
-}
-
-define i1 @icmp_nsw_false_2(i32 %V) {
-; CHECK-LABEL: @icmp_nsw_false_2(
-; CHECK-NEXT:    ret i1 false
-;
-  %add5 = add nsw i32 %V, 6
-  %add6 = add nsw i32 %V, 5
-  %cmp = icmp slt i32 %add5, %add6
-  ret i1 %cmp
-}
-
-define i1 @icmp_nsw_false_3(i32 %V) {
-; CHECK-LABEL: @icmp_nsw_false_3(
-; CHECK-NEXT:    [[ADD5:%.*]] = add nsw i32 [[V:%.*]], 5
-; CHECK-NEXT:    [[ADD6:%.*]] = add i32 [[V]], 5
-; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[ADD5]], [[ADD6]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %add5 = add nsw i32 %V, 5
-  %add6 = add i32 %V, 5
-  %cmp = icmp slt i32 %add5, %add6
-  ret i1 %cmp
-}
-
-define i1 @icmp_nsw_false_4(i32 %V) {
-; CHECK-LABEL: @icmp_nsw_false_4(
-; CHECK-NEXT:    [[ADD5:%.*]] = add i32 [[V:%.*]], 6
-; CHECK-NEXT:    [[ADD6:%.*]] = add nsw i32 [[V]], 5
-; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[ADD5]], [[ADD6]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %add5 = add i32 %V, 6
-  %add6 = add nsw i32 %V, 5
-  %cmp = icmp slt i32 %add5, %add6
-  ret i1 %cmp
-}
-
-define i1 @icmp_nsw_false_5(i8 %V) {
-; CHECK-LABEL: @icmp_nsw_false_5(
-; CHECK-NEXT:    [[ADD:%.*]] = add i8 [[V:%.*]], 121
-; CHECK-NEXT:    [[ADDNSW:%.*]] = add nsw i8 [[V]], -104
-; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[ADD]], [[ADDNSW]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %add = add i8 %V, 121
-  %addnsw = add nsw i8 %V, -104
-  %cmp = icmp slt i8 %add, %addnsw
-  ret i1 %cmp
-}
-
-define i1 @icmp_nsw_i8(i8 %V) {
-; CHECK-LABEL: @icmp_nsw_i8(
-; CHECK-NEXT:    ret i1 true
-;
-  %add5 = add i8 %V, 5
-  %add6 = add nsw i8 %V, 6
-  %cmp = icmp slt i8 %add5, %add6
-  ret i1 %cmp
-}
-
-define i1 @icmp_nsw_i16(i16 %V) {
-; CHECK-LABEL: @icmp_nsw_i16(
-; CHECK-NEXT:    ret i1 true
-;
-  %add5 = add i16 %V, 0
-  %add6 = add nsw i16 %V, 1
-  %cmp = icmp slt i16 %add5, %add6
-  ret i1 %cmp
-}
-
-define i1 @icmp_nsw_i64(i64 %V) {
-; CHECK-LABEL: @icmp_nsw_i64(
-; CHECK-NEXT:    ret i1 true
-;
-  %add5 = add i64 %V, 5
-  %add6 = add nsw i64 %V, 6
-  %cmp = icmp slt i64 %add5, %add6
-  ret i1 %cmp
-}
-
-define <4 x i1> @icmp_nsw_vec(<4 x i32> %V) {
-; CHECK-LABEL: @icmp_nsw_vec(
-; CHECK-NEXT:    ret <4 x i1> <i1 true, i1 true, i1 true, i1 true>
-;
-  %add5 = add <4 x i32> %V, <i32 5, i32 5, i32 5, i32 5>
-  %add6 = add nsw <4 x i32> %V, <i32 6, i32 6, i32 6, i32 6>
-  %cmp = icmp slt <4 x i32> %add5, %add6
-  ret <4 x i1> %cmp
-}
-
-define i1 @icmp_nsw_3(i32 %V) {
-; CHECK-LABEL: @icmp_nsw_3(
-; CHECK-NEXT:    [[ADD5:%.*]] = add i32 [[V:%.*]], 5
-; CHECK-NEXT:    [[ADD5_2:%.*]] = add nsw i32 [[V]], 5
-; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[ADD5]], [[ADD5_2]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %add5 = add i32 %V, 5
-  %add5_2 = add nsw i32 %V, 5
-  %cmp = icmp slt i32 %add5, %add5_2
-  ret i1 %cmp
-}
-
-define i1 @icmp_nsw_4(i32 %V) {
-; CHECK-LABEL: @icmp_nsw_4(
-; CHECK-NEXT:    [[ADD5:%.*]] = add i32 [[V:%.*]], 5
-; CHECK-NEXT:    [[ADD4:%.*]] = add nsw i32 [[V]], 4
-; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[ADD5]], [[ADD4]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %add5 = add i32 %V, 5
-  %add4 = add nsw i32 %V, 4
-  %cmp = icmp slt i32 %add5, %add4
-  ret i1 %cmp
-}
-
-define i1 @icmp_nsw_5(i32 %V) {
-; CHECK-LABEL: @icmp_nsw_5(
-; CHECK-NEXT:    [[ADD5:%.*]] = add nsw i32 [[V:%.*]], 5
-; CHECK-NEXT:    [[ADD6:%.*]] = add i32 [[V]], 6
-; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[ADD5]], [[ADD6]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %add5 = add nsw i32 %V, 5
-  %add6 = add i32 %V, 6
-  %cmp = icmp slt i32 %add5, %add6
-  ret i1 %cmp
-}
-
-define i1 @icmp_nsw_7(i32 %V, i32 %arg) {
-; CHECK-LABEL: @icmp_nsw_7(
-; CHECK-NEXT:    [[ADD5:%.*]] = add i32 [[V:%.*]], 5
-; CHECK-NEXT:    [[ADDARG:%.*]] = add nsw i32 [[V]], [[ARG:%.*]]
-; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[ADD5]], [[ADDARG]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %add5 = add i32 %V, 5
-  %addarg = add nsw i32 %V, %arg
-  %cmp = icmp slt i32 %add5, %addarg
-  ret i1 %cmp
-}
-
-define i1 @icmp_nsw_8(i32 %V, i32 %arg) {
-; CHECK-LABEL: @icmp_nsw_8(
-; CHECK-NEXT:    [[ADDARG:%.*]] = add i32 [[V:%.*]], [[ARG:%.*]]
-; CHECK-NEXT:    [[ADD6:%.*]] = add nsw i32 [[V]], 5
-; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[ADDARG]], [[ADD6]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %addarg = add i32 %V, %arg
-  %add6 = add nsw i32 %V, 5
-  %cmp = icmp slt i32 %addarg, %add6
-  ret i1 %cmp
-}
-
-define i1 @icmp_nsw_9(i32 %V1, i32 %V2) {
-; CHECK-LABEL: @icmp_nsw_9(
-; CHECK-NEXT:    [[ADD_V1:%.*]] = add i32 [[V1:%.*]], 5
-; CHECK-NEXT:    [[ADD_V2:%.*]] = add nsw i32 [[V2:%.*]], 6
-; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[ADD_V1]], [[ADD_V2]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %add_V1 = add i32 %V1, 5
-  %add_V2 = add nsw i32 %V2, 6
-  %cmp = icmp slt i32 %add_V1, %add_V2
-  ret i1 %cmp
-}
-
-define i1 @icmp_nsw_10(i32 %V) {
-; CHECK-LABEL: @icmp_nsw_10(
-; CHECK-NEXT:    [[ADD5:%.*]] = add i32 [[V:%.*]], 5
-; CHECK-NEXT:    [[ADD6:%.*]] = add nsw i32 [[V]], 6
-; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[ADD6]], [[ADD5]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %add5 = add i32 %V, 5
-  %add6 = add nsw i32 %V, 6
-  %cmp = icmp sgt i32 %add6, %add5
-  ret i1 %cmp
-}
-
-define i1 @icmp_nsw_11(i32 %V) {
-; CHECK-LABEL: @icmp_nsw_11(
-; CHECK-NEXT:    [[ADD5:%.*]] = add i32 [[V:%.*]], -125
-; CHECK-NEXT:    [[ADD6:%.*]] = add nsw i32 [[V]], -99
-; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[ADD5]], [[ADD6]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %add5 = add i32 %V, -125
-  %add6 = add nsw i32 %V, -99
-  %cmp = icmp slt i32 %add5, %add6
-  ret i1 %cmp
-}
-
-define i1 @icmp_nsw_nonpos(i32 %V) {
-; CHECK-LABEL: @icmp_nsw_nonpos(
-; CHECK-NEXT:    ret i1 false
-;
-  %add5 = add i32 %V, 0
-  %add6 = add nsw i32 %V, -1
-  %cmp = icmp slt i32 %add5, %add6
-  ret i1 %cmp
-}
-
-define i1 @icmp_nsw_nonpos2(i32 %V) {
-; CHECK-LABEL: @icmp_nsw_nonpos2(
-; CHECK-NEXT:    [[ADD5:%.*]] = add i32 [[V:%.*]], 1
-; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[ADD5]], [[V]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %add5 = add i32 %V, 1
-  %add6 = add nsw i32 %V, 0
-  %cmp = icmp slt i32 %add5, %add6
-  ret i1 %cmp
-}
-
-declare i11 @llvm.ctpop.i11(i11)
-declare i73 @llvm.ctpop.i73(i73)
-declare <2 x i13> @llvm.ctpop.v2i13(<2 x i13>)
-
-define i1 @ctpop_sgt_bitwidth(i11 %x) {
-; CHECK-LABEL: @ctpop_sgt_bitwidth(
-; CHECK-NEXT:    ret i1 false
-;
-  %pop = call i11 @llvm.ctpop.i11(i11 %x)
-  %cmp = icmp sgt i11 %pop, 11
-  ret i1 %cmp
-}
-
-define i1 @ctpop_sle_minus1(i11 %x) {
-; CHECK-LABEL: @ctpop_sle_minus1(
-; CHECK-NEXT:    ret i1 false
-;
-  %pop = call i11 @llvm.ctpop.i11(i11 %x)
-  %cmp = icmp sle i11 %pop, -1
-  ret i1 %cmp
-}
-
-define i1 @ctpop_ugt_bitwidth(i73 %x) {
-; CHECK-LABEL: @ctpop_ugt_bitwidth(
-; CHECK-NEXT:    ret i1 false
-;
-  %pop = call i73 @llvm.ctpop.i73(i73 %x)
-  %cmp = icmp ugt i73 %pop, 73
-  ret i1 %cmp
-}
-
-; Negative test - does not simplify, but instcombine could reduce this.
-
-define i1 @ctpop_ugt_bitwidth_minus1(i73 %x) {
-; CHECK-LABEL: @ctpop_ugt_bitwidth_minus1(
-; CHECK-NEXT:    [[POP:%.*]] = call i73 @llvm.ctpop.i73(i73 [[X:%.*]])
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i73 [[POP]], 72
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %pop = call i73 @llvm.ctpop.i73(i73 %x)
-  %cmp = icmp ugt i73 %pop, 72
-  ret i1 %cmp
-}
-
-define <2 x i1> @ctpop_sgt_bitwidth_splat(<2 x i13> %x) {
-; CHECK-LABEL: @ctpop_sgt_bitwidth_splat(
-; CHECK-NEXT:    ret <2 x i1> zeroinitializer
-;
-  %pop = call <2 x i13> @llvm.ctpop.v2i13(<2 x i13> %x)
-  %cmp = icmp sgt <2 x i13> %pop, <i13 13, i13 13>
-  ret <2 x i1> %cmp
-}
-
-define i1 @ctpop_ult_plus1_bitwidth(i11 %x) {
-; CHECK-LABEL: @ctpop_ult_plus1_bitwidth(
-; CHECK-NEXT:    ret i1 true
-;
-  %pop = call i11 @llvm.ctpop.i11(i11 %x)
-  %cmp = icmp ult i11 %pop, 12
-  ret i1 %cmp
-}
-
-define i1 @ctpop_ne_big_bitwidth(i73 %x) {
-; CHECK-LABEL: @ctpop_ne_big_bitwidth(
-; CHECK-NEXT:    ret i1 true
-;
-  %pop = call i73 @llvm.ctpop.i73(i73 %x)
-  %cmp = icmp ne i73 %pop, 75
-  ret i1 %cmp
-}
-
-define <2 x i1> @ctpop_slt_bitwidth_plus1_splat(<2 x i13> %x) {
-; CHECK-LABEL: @ctpop_slt_bitwidth_plus1_splat(
-; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
-;
-  %pop = call <2 x i13> @llvm.ctpop.v2i13(<2 x i13> %x)
-  %cmp = icmp slt <2 x i13> %pop, <i13 14, i13 14>
-  ret <2 x i1> %cmp
-}
-
-; Negative test - does not simplify, but instcombine could reduce this.
-
-define <2 x i1> @ctpop_slt_bitwidth_splat(<2 x i13> %x) {
-; CHECK-LABEL: @ctpop_slt_bitwidth_splat(
-; CHECK-NEXT:    [[POP:%.*]] = call <2 x i13> @llvm.ctpop.v2i13(<2 x i13> [[X:%.*]])
-; CHECK-NEXT:    [[CMP:%.*]] = icmp slt <2 x i13> [[POP]], <i13 13, i13 13>
-; CHECK-NEXT:    ret <2 x i1> [[CMP]]
-;
-  %pop = call <2 x i13> @llvm.ctpop.v2i13(<2 x i13> %x)
-  %cmp = icmp slt <2 x i13> %pop, <i13 13, i13 13>
-  ret <2 x i1> %cmp
-}
-
-declare i11 @llvm.ctlz.i11(i11)
-declare i73 @llvm.ctlz.i73(i73)
-declare <2 x i13> @llvm.ctlz.v2i13(<2 x i13>)
-
-define i1 @ctlz_sgt_bitwidth(i11 %x) {
-; CHECK-LABEL: @ctlz_sgt_bitwidth(
-; CHECK-NEXT:    ret i1 false
-;
-  %pop = call i11 @llvm.ctlz.i11(i11 %x)
-  %cmp = icmp sgt i11 %pop, 11
-  ret i1 %cmp
-}
-
-define i1 @ctlz_sle_minus1(i11 %x) {
-; CHECK-LABEL: @ctlz_sle_minus1(
-; CHECK-NEXT:    ret i1 false
-;
-  %pop = call i11 @llvm.ctlz.i11(i11 %x)
-  %cmp = icmp sle i11 %pop, -1
-  ret i1 %cmp
-}
-
-define i1 @ctlz_ugt_bitwidth(i73 %x) {
-; CHECK-LABEL: @ctlz_ugt_bitwidth(
-; CHECK-NEXT:    ret i1 false
-;
-  %pop = call i73 @llvm.ctlz.i73(i73 %x)
-  %cmp = icmp ugt i73 %pop, 73
-  ret i1 %cmp
-}
-
-; Negative test - does not simplify, but instcombine could reduce this.
-
-define i1 @ctlz_ugt_bitwidth_minus1(i73 %x) {
-; CHECK-LABEL: @ctlz_ugt_bitwidth_minus1(
-; CHECK-NEXT:    [[POP:%.*]] = call i73 @llvm.ctlz.i73(i73 [[X:%.*]], i1 false)
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i73 [[POP]], 72
+define i1 @gep14(ptr %ptr) {
+; CHECK-LABEL: @gep14(
+; CHECK-NEXT:    [[X:%.*]] = getelementptr inbounds { {}, i8 }, ptr [[PTR:%.*]], i32 0, i32 1
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[X]], null
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
-  %pop = call i73 @llvm.ctlz.i73(i73 %x)
-  %cmp = icmp ugt i73 %pop, 72
-  ret i1 %cmp
-}
-
-define <2 x i1> @ctlz_sgt_bitwidth_splat(<2 x i13> %x) {
-; CHECK-LABEL: @ctlz_sgt_bitwidth_splat(
-; CHECK-NEXT:    ret <2 x i1> zeroinitializer
-;
-  %pop = call <2 x i13> @llvm.ctlz.v2i13(<2 x i13> %x)
-  %cmp = icmp sgt <2 x i13> %pop, <i13 13, i13 13>
-  ret <2 x i1> %cmp
-}
-
-define i1 @ctlz_ult_plus1_bitwidth(i11 %x) {
-; CHECK-LABEL: @ctlz_ult_plus1_bitwidth(
-; CHECK-NEXT:    ret i1 true
-;
-  %pop = call i11 @llvm.ctlz.i11(i11 %x)
-  %cmp = icmp ult i11 %pop, 12
-  ret i1 %cmp
-}
-
-define i1 @ctlz_ne_big_bitwidth(i73 %x) {
-; CHECK-LABEL: @ctlz_ne_big_bitwidth(
-; CHECK-NEXT:    ret i1 true
-;
-  %pop = call i73 @llvm.ctlz.i73(i73 %x)
-  %cmp = icmp ne i73 %pop, 75
-  ret i1 %cmp
-}
-
-define <2 x i1> @ctlz_slt_bitwidth_plus1_splat(<2 x i13> %x) {
-; CHECK-LABEL: @ctlz_slt_bitwidth_plus1_splat(
-; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
-;
-  %pop = call <2 x i13> @llvm.ctlz.v2i13(<2 x i13> %x)
-  %cmp = icmp slt <2 x i13> %pop, <i13 14, i13 14>
-  ret <2 x i1> %cmp
-}
-
-; Negative test - does not simplify, but instcombine could reduce this.
-
-define <2 x i1> @ctlz_slt_bitwidth_splat(<2 x i13> %x) {
-; CHECK-LABEL: @ctlz_slt_bitwidth_splat(
-; CHECK-NEXT:    [[POP:%.*]] = call <2 x i13> @llvm.ctlz.v2i13(<2 x i13> [[X:%.*]], i1 false)
-; CHECK-NEXT:    [[CMP:%.*]] = icmp slt <2 x i13> [[POP]], <i13 13, i13 13>
-; CHECK-NEXT:    ret <2 x i1> [[CMP]]
-;
-  %pop = call <2 x i13> @llvm.ctlz.v2i13(<2 x i13> %x)
-  %cmp = icmp slt <2 x i13> %pop, <i13 13, i13 13>
-  ret <2 x i1> %cmp
-}
-
-declare i11 @llvm.cttz.i11(i11)
-declare i73 @llvm.cttz.i73(i73)
-declare <2 x i13> @llvm.cttz.v2i13(<2 x i13>)
-
-define i1 @cttz_sgt_bitwidth(i11 %x) {
-; CHECK-LABEL: @cttz_sgt_bitwidth(
-; CHECK-NEXT:    ret i1 false
-;
-  %pop = call i11 @llvm.cttz.i11(i11 %x)
-  %cmp = icmp sgt i11 %pop, 11
-  ret i1 %cmp
-}
-
-define i1 @cttz_sle_minus1(i11 %x) {
-; CHECK-LABEL: @cttz_sle_minus1(
-; CHECK-NEXT:    ret i1 false
+; CHECK-DL-LABEL: @gep14(
+; CHECK-DL-NEXT:    ret i1 false
 ;
-  %pop = call i11 @llvm.cttz.i11(i11 %x)
-  %cmp = icmp sle i11 %pop, -1
+; We can't simplify this because the offset of one in the GEP actually doesn't
+; move the pointer.
+  %x = getelementptr inbounds { {}, i8 }, ptr %ptr, i32 0, i32 1
+  %cmp = icmp eq ptr %x, null
   ret i1 %cmp
 }
 
-define i1 @cttz_ugt_bitwidth(i73 %x) {
-; CHECK-LABEL: @cttz_ugt_bitwidth(
+declare dereferenceable(4) ptr addrspace(1) @returns_nonnull_deref_as_helper()
+define i1 @nonnull_load_as_inner(ptr %addr) {
+; CHECK-LABEL: @nonnull_load_as_inner(
 ; CHECK-NEXT:    ret i1 false
 ;
-  %pop = call i73 @llvm.cttz.i73(i73 %x)
-  %cmp = icmp ugt i73 %pop, 73
-  ret i1 %cmp
-}
-
-; Negative test - does not simplify, but instcombine could reduce this.
-
-define i1 @cttz_ugt_bitwidth_minus1(i73 %x) {
-; CHECK-LABEL: @cttz_ugt_bitwidth_minus1(
-; CHECK-NEXT:    [[POP:%.*]] = call i73 @llvm.cttz.i73(i73 [[X:%.*]], i1 false)
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i73 [[POP]], 72
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %pop = call i73 @llvm.cttz.i73(i73 %x)
-  %cmp = icmp ugt i73 %pop, 72
-  ret i1 %cmp
-}
-
-define <2 x i1> @cttz_sgt_bitwidth_splat(<2 x i13> %x) {
-; CHECK-LABEL: @cttz_sgt_bitwidth_splat(
-; CHECK-NEXT:    ret <2 x i1> zeroinitializer
-;
-  %pop = call <2 x i13> @llvm.cttz.v2i13(<2 x i13> %x)
-  %cmp = icmp sgt <2 x i13> %pop, <i13 13, i13 13>
-  ret <2 x i1> %cmp
-}
-
-define i1 @cttz_ult_plus1_bitwidth(i11 %x) {
-; CHECK-LABEL: @cttz_ult_plus1_bitwidth(
-; CHECK-NEXT:    ret i1 true
-;
-  %pop = call i11 @llvm.cttz.i11(i11 %x)
-  %cmp = icmp ult i11 %pop, 12
-  ret i1 %cmp
-}
-
-define i1 @cttz_ne_big_bitwidth(i73 %x) {
-; CHECK-LABEL: @cttz_ne_big_bitwidth(
-; CHECK-NEXT:    ret i1 true
+; CHECK-DL-LABEL: @nonnull_load_as_inner(
+; CHECK-DL-NEXT:    [[PTR:%.*]] = load ptr addrspace(1), ptr [[ADDR:%.*]], align 8, !nonnull [[META0:![0-9]+]]
+; CHECK-DL-NEXT:    [[CMP:%.*]] = icmp eq ptr addrspace(1) [[PTR]], null
+; CHECK-DL-NEXT:    ret i1 [[CMP]]
 ;
-  %pop = call i73 @llvm.cttz.i73(i73 %x)
-  %cmp = icmp ne i73 %pop, 75
+  %ptr = load ptr addrspace(1), ptr %addr, !nonnull !{}
+  %cmp = icmp eq ptr addrspace(1) %ptr, null
   ret i1 %cmp
 }
 
-define <2 x i1> @cttz_slt_bitwidth_plus1_splat(<2 x i13> %x) {
-; CHECK-LABEL: @cttz_slt_bitwidth_plus1_splat(
-; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
-;
-  %pop = call <2 x i13> @llvm.cttz.v2i13(<2 x i13> %x)
-  %cmp = icmp slt <2 x i13> %pop, <i13 14, i13 14>
-  ret <2 x i1> %cmp
-}
-
-; Negative test - does not simplify, but instcombine could reduce this.
-
-define <2 x i1> @cttz_slt_bitwidth_splat(<2 x i13> %x) {
-; CHECK-LABEL: @cttz_slt_bitwidth_splat(
-; CHECK-NEXT:    [[POP:%.*]] = call <2 x i13> @llvm.cttz.v2i13(<2 x i13> [[X:%.*]], i1 false)
-; CHECK-NEXT:    [[CMP:%.*]] = icmp slt <2 x i13> [[POP]], <i13 13, i13 13>
-; CHECK-NEXT:    ret <2 x i1> [[CMP]]
-;
-  %pop = call <2 x i13> @llvm.cttz.v2i13(<2 x i13> %x)
-  %cmp = icmp slt <2 x i13> %pop, <i13 13, i13 13>
-  ret <2 x i1> %cmp
-}
-
-; A zero sized alloca *can* be equal to another alloca
-define i1 @zero_sized_alloca1() {
-; CHECK-LABEL: @zero_sized_alloca1(
-; CHECK-NEXT:    [[A:%.*]] = alloca i32, i32 0, align 4
-; CHECK-NEXT:    [[B:%.*]] = alloca i32, i32 0, align 4
-; CHECK-NEXT:    [[RES:%.*]] = icmp ne ptr [[A]], [[B]]
-; CHECK-NEXT:    ret i1 [[RES]]
-;
-  %a = alloca i32, i32 0
-  %b = alloca i32, i32 0
-  %res = icmp ne ptr %a, %b
-  ret i1 %res
-}
-
-define i1 @zero_sized_alloca2() {
-; CHECK-LABEL: @zero_sized_alloca2(
-; CHECK-NEXT:    [[A:%.*]] = alloca i32, i32 0, align 4
-; CHECK-NEXT:    [[B:%.*]] = alloca i32, align 4
-; CHECK-NEXT:    [[RES:%.*]] = icmp ne ptr [[A]], [[B]]
-; CHECK-NEXT:    ret i1 [[RES]]
-;
-  %a = alloca i32, i32 0
-  %b = alloca i32
-  %res = icmp ne ptr %a, %b
-  ret i1 %res
-}
-
-define i1 @scalar_vectors_are_non_empty() {
-; CHECK-LABEL: @scalar_vectors_are_non_empty(
-; CHECK-NEXT:    ret i1 true
-;
-  %a = alloca <vscale x 2 x i32>
-  %b = alloca <vscale x 2 x i32>
-  %res = icmp ne ptr %a, %b
-  ret i1 %res
-}
-
-; Never equal
-define i1 @byval_args_inequal(ptr byval(i32) %a, ptr byval(i32) %b) {
-; CHECK-LABEL: @byval_args_inequal(
-; CHECK-NEXT:    ret i1 true
-;
-  %res = icmp ne ptr %a, %b
-  ret i1 %res
-}
-
-; Arguments can be adjacent on the stack
-define i1 @neg_args_adjacent(ptr byval(i32) %a, ptr byval(i32) %b) {
-; CHECK-LABEL: @neg_args_adjacent(
-; CHECK-NEXT:    [[A_OFF:%.*]] = getelementptr i32, ptr [[A:%.*]], i32 1
-; CHECK-NEXT:    [[RES:%.*]] = icmp ne ptr [[A_OFF]], [[B:%.*]]
-; CHECK-NEXT:    ret i1 [[RES]]
-;
-  %a.off = getelementptr i32, ptr %a, i32 1
-  %res = icmp ne ptr %a.off, %b
-  ret i1 %res
-}
-
-; Never equal
-define i1 @test_byval_alloca_inequal(ptr byval(i32) %a) {
-; CHECK-LABEL: @test_byval_alloca_inequal(
-; CHECK-NEXT:    ret i1 true
-;
-  %b = alloca i32
-  %res = icmp ne ptr %a, %b
-  ret i1 %res
-}
-
-; Byval argument can be immediately before alloca, and crossing
-; over is allowed.
-define i1 @neg_byval_alloca_adjacent(ptr byval(i32) %a) {
-; CHECK-LABEL: @neg_byval_alloca_adjacent(
-; CHECK-NEXT:    [[B:%.*]] = alloca i32, align 4
-; CHECK-NEXT:    [[A_OFF:%.*]] = getelementptr i32, ptr [[A:%.*]], i32 1
-; CHECK-NEXT:    [[RES:%.*]] = icmp ne ptr [[A_OFF]], [[B]]
-; CHECK-NEXT:    ret i1 [[RES]]
-;
-  %b = alloca i32
-  %a.off = getelementptr i32, ptr %a, i32 1
-  %res = icmp ne ptr %a.off, %b
-  ret i1 %res
-}
-
 @A = global i32 0
 @B = global i32 0
 @A.alias = alias i32, ptr @A
@@ -3073,6 +43,9 @@ define i1 @neg_byval_alloca_adjacent(ptr byval(i32) %a) {
 define i1 @globals_inequal() {
 ; CHECK-LABEL: @globals_inequal(
 ; CHECK-NEXT:    ret i1 true
+;
+; CHECK-DL-LABEL: @globals_inequal(
+; CHECK-DL-NEXT:    ret i1 true
 ;
   %res = icmp ne ptr @A, @B
   ret i1 %res
@@ -3081,190 +54,13 @@ define i1 @globals_inequal() {
 ; TODO: Never equal
 define i1 @globals_offset_inequal() {
 ; CHECK-LABEL: @globals_offset_inequal(
-; CHECK-NEXT:    ret i1 icmp ne (ptr getelementptr (i8, ptr @A, i32 1), ptr getelementptr (i8, ptr @B, i32 1))
+; CHECK-NEXT:    ret i1 icmp ne (ptr getelementptr (i8, ptr @A, i64 1), ptr getelementptr (i8, ptr @B, i64 1))
+;
+; CHECK-DL-LABEL: @globals_offset_inequal(
+; CHECK-DL-NEXT:    ret i1 icmp ne (ptr getelementptr (i8, ptr @A, i32 1), ptr getelementptr (i8, ptr @B, i32 1))
 ;
   %a.off = getelementptr i8, ptr @A, i32 1
   %b.off = getelementptr i8, ptr @B, i32 1
   %res = icmp ne ptr %a.off, %b.off
   ret i1 %res
 }
-
-
-; Never equal
-define i1 @test_byval_global_inequal(ptr byval(i32) %a) {
-; CHECK-LABEL: @test_byval_global_inequal(
-; CHECK-NEXT:    ret i1 true
-;
-  %b = alloca i32
-  %res = icmp ne ptr %a, @B
-  ret i1 %res
-}
-
-
-define i1 @neg_global_alias() {
-; CHECK-LABEL: @neg_global_alias(
-; CHECK-NEXT:    ret i1 icmp ne (ptr @A, ptr @A.alias)
-;
-  %res = icmp ne ptr @A, @A.alias
-  ret i1 %res
-}
-
-
-define i1 @icmp_lshr_known_non_zero_ult_true(i8 %x) {
-; CHECK-LABEL: @icmp_lshr_known_non_zero_ult_true(
-; CHECK-NEXT:    ret i1 true
-;
-  %or = or i8 %x, 1
-  %x1 = shl nuw i8 %or, 1
-  %x2 = shl nuw i8 %or, 2
-  %cmp = icmp ult i8 %x1, %x2
-  ret i1 %cmp
-}
-
-define i1 @icmp_lshr_known_non_zero_ult_false(i8 %x) {
-; CHECK-LABEL: @icmp_lshr_known_non_zero_ult_false(
-; CHECK-NEXT:    ret i1 false
-;
-  %or = or i8 %x, 1
-  %x1 = shl nuw i8 %or, 1
-  %x2 = shl nuw i8 %or, 2
-  %cmp = icmp ugt i8 %x1, %x2
-  ret i1 %cmp
-}
-
-define i1 @icmp_lshr_known_non_zero_slt_true(i8 %x) {
-; CHECK-LABEL: @icmp_lshr_known_non_zero_slt_true(
-; CHECK-NEXT:    ret i1 true
-;
-  %or = or i8 %x, 1
-  %x1 = shl nuw nsw i8 %or, 1
-  %x2 = shl nuw nsw i8 %or, 2
-  %cmp = icmp slt i8 %x1, %x2
-  ret i1 %cmp
-}
-
-define i1 @icmp_lshr_known_non_zero_slt_false(i8 %x) {
-; CHECK-LABEL: @icmp_lshr_known_non_zero_slt_false(
-; CHECK-NEXT:    ret i1 false
-;
-  %or = or i8 %x, 1
-  %x1 = shl nuw nsw i8 %or, 2
-  %x2 = shl nuw nsw i8 %or, 1
-  %cmp = icmp slt i8 %x1, %x2
-  ret i1 %cmp
-}
-
-define i1 @neg_icmp_lshr_known_non_zero_slt_no_nsw(i8 %x) {
-; CHECK-LABEL: @neg_icmp_lshr_known_non_zero_slt_no_nsw(
-; CHECK-NEXT:    [[OR:%.*]] = or i8 [[X:%.*]], 1
-; CHECK-NEXT:    [[X1:%.*]] = shl nuw i8 [[OR]], 1
-; CHECK-NEXT:    [[X2:%.*]] = shl nuw i8 [[OR]], 2
-; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[X1]], [[X2]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %or = or i8 %x, 1
-  %x1 = shl nuw i8 %or, 1
-  %x2 = shl nuw i8 %or, 2
-  %cmp = icmp slt i8 %x1, %x2
-  ret i1 %cmp
-}
-
-define i1 @neg_icmp_lshr_known_non_zero_ult_no_nuw(i8 %x) {
-; CHECK-LABEL: @neg_icmp_lshr_known_non_zero_ult_no_nuw(
-; CHECK-NEXT:    [[OR:%.*]] = or i8 [[X:%.*]], 1
-; CHECK-NEXT:    [[X1:%.*]] = shl i8 [[OR]], 1
-; CHECK-NEXT:    [[X2:%.*]] = shl i8 [[OR]], 2
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i8 [[X1]], [[X2]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %or = or i8 %x, 1
-  %x1 = shl i8 %or, 1
-  %x2 = shl i8 %or, 2
-  %cmp = icmp ult i8 %x1, %x2
-  ret i1 %cmp
-}
-
-define i1 @neg_icmp_lshr_known_non_zero_slt_no_nuw(i8 %x) {
-; CHECK-LABEL: @neg_icmp_lshr_known_non_zero_slt_no_nuw(
-; CHECK-NEXT:    [[OR:%.*]] = or i8 [[X:%.*]], 1
-; CHECK-NEXT:    [[X1:%.*]] = shl nsw i8 [[OR]], 1
-; CHECK-NEXT:    [[X2:%.*]] = shl nsw i8 [[OR]], 2
-; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[X1]], [[X2]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %or = or i8 %x, 1
-  %x1 = shl nsw i8 %or, 1
-  %x2 = shl nsw i8 %or, 2
-  %cmp = icmp slt i8 %x1, %x2
-  ret i1 %cmp
-}
-
-define i1 @neg_icmp_lshr_unknown_value(i8 %x) {
-; CHECK-LABEL: @neg_icmp_lshr_unknown_value(
-; CHECK-NEXT:    [[X1:%.*]] = shl nuw i8 [[X:%.*]], 2
-; CHECK-NEXT:    [[X2:%.*]] = shl nuw i8 [[X]], 1
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i8 [[X1]], [[X2]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %x1 = shl nuw i8 %x, 2
-  %x2 = shl nuw i8 %x, 1
-  %cmp = icmp ugt i8 %x1, %x2
-  ret i1 %cmp
-}
-
-define i1 @neg_icmp_lshr_unknown_shift(i8 %x, i8 %C1) {
-; CHECK-LABEL: @neg_icmp_lshr_unknown_shift(
-; CHECK-NEXT:    [[OR:%.*]] = or i8 [[X:%.*]], 1
-; CHECK-NEXT:    [[X1:%.*]] = shl nuw i8 [[OR]], 2
-; CHECK-NEXT:    [[X2:%.*]] = shl nuw i8 [[OR]], [[C1:%.*]]
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i8 [[X1]], [[X2]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %or = or i8 %x, 1
-  %x1 = shl nuw i8 %or, 2
-  %x2 = shl nuw i8 %or, %C1
-  %cmp = icmp ugt i8 %x1, %x2
-  ret i1 %cmp
-}
-
-define i1 @neg_icmp_lshr_different_shift_values(i8 %x, i8 %y) {
-; CHECK-LABEL: @neg_icmp_lshr_different_shift_values(
-; CHECK-NEXT:    [[X1:%.*]] = shl nuw nsw i8 [[X:%.*]], 1
-; CHECK-NEXT:    [[X2:%.*]] = shl nuw nsw i8 [[Y:%.*]], 2
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i8 [[X1]], [[X2]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %x1 = shl nuw nsw i8 %x, 1
-  %x2 = shl nuw nsw i8 %y, 2
-  %cmp = icmp ult i8 %x1, %x2
-  ret i1 %cmp
-}
-
-define i1 @icmp_ult_vscale_true(i8 %x, i8 %y) {
-; CHECK-LABEL: @icmp_ult_vscale_true(
-; CHECK-NEXT:    ret i1 true
-;
-  %vscale = call i64 @llvm.vscale.i64()
-  %x1 = shl nuw nsw i64 %vscale, 1
-  %x2 = shl nuw nsw i64 %vscale, 2
-  %cmp = icmp ult i64 %x1, %x2
-  ret i1 %cmp
-}
-
-define i1 @icmp_ult_vscale_false(i8 %x, i8 %y) {
-; CHECK-LABEL: @icmp_ult_vscale_false(
-; CHECK-NEXT:    ret i1 false
-;
-  %vscale = call i64 @llvm.vscale.i64()
-  %x1 = shl nuw nsw i64 %vscale, 1
-  %x2 = shl nuw nsw i64 %vscale, 2
-  %cmp = icmp ugt i64 %x1, %x2
-  ret i1 %cmp
-}
-
-declare i64 @llvm.vscale.i64()
-
-; TODO: Add coverage for global aliases, link once, etc..
-
-
-attributes #0 = { null_pointer_is_valid }
diff --git a/llvm/test/Transforms/InstSimplify/icmp-dl-sentinel.ll b/llvm/test/Transforms/InstSimplify/icmp-dl-sentinel.ll
index a9d1fd546869f..c8fd6646d3b7b 100755
--- a/llvm/test/Transforms/InstSimplify/icmp-dl-sentinel.ll
+++ b/llvm/test/Transforms/InstSimplify/icmp-dl-sentinel.ll
@@ -1,414 +1,23 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
 ; RUN: opt < %s -passes=instsimplify -S | FileCheck %s
-
-target datalayout = "e-p:64:64:64-p1:16:16:16-p2:32:32:32-p3:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-z0:1-z2:neg1-z3:neg1-z5:neg1"
+; RUN: opt < %s -passes=instsimplify -data-layout=z0:1-z2:neg1-z3:neg1-z5:neg1 -S | FileCheck -check-prefixes=CHECK-DL %s
 
 declare void @usei8ptr(ptr %ptr)
 
-; Ensure that we do not crash when looking at such a weird bitcast.
-define i1 @bitcast_from_single_element_pointer_vector_to_pointer(<1 x ptr> %ptr1vec, ptr %ptr2) {
-; CHECK-LABEL: @bitcast_from_single_element_pointer_vector_to_pointer(
-; CHECK-NEXT:    [[PTR1:%.*]] = bitcast <1 x ptr> [[PTR1VEC:%.*]] to ptr
-; CHECK-NEXT:    call void @usei8ptr(ptr [[PTR1]])
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[PTR1]], [[PTR2:%.*]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %ptr1 = bitcast <1 x ptr> %ptr1vec to ptr
-  call void @usei8ptr(ptr %ptr1)
-  %cmp = icmp eq ptr %ptr1, %ptr2
-  ret i1 %cmp
-}
-
-define i1 @poison(i32 %x) {
-; CHECK-LABEL: @poison(
-; CHECK-NEXT:    ret i1 poison
-;
-  %v = icmp eq i32 %x, poison
-  ret i1 %v
-}
-
-define i1 @poison2(i32 %x) {
-; CHECK-LABEL: @poison2(
-; CHECK-NEXT:    ret i1 poison
-;
-  %v = icmp slt i32 %x, poison
-  ret i1 %v
-}
-
-define i1 @mul_div_cmp_smaller(i8 %x) {
-; CHECK-LABEL: @mul_div_cmp_smaller(
-; CHECK-NEXT:    ret i1 true
-;
-  %mul = mul i8 %x, 3
-  %div = udiv i8 %mul, 4
-  %cmp = icmp ule i8 %div, %x
-  ret i1 %cmp
-}
-
-define i1 @mul_div_cmp_equal(i8 %x) {
-; CHECK-LABEL: @mul_div_cmp_equal(
-; CHECK-NEXT:    ret i1 true
-;
-  %mul = mul i8 %x, 3
-  %div = udiv i8 %mul, 3
-  %cmp = icmp ule i8 %div, %x
-  ret i1 %cmp
-}
-
-; Negative test: 3>2
-define i1 @mul_div_cmp_greater(i8 %x) {
-; CHECK-LABEL: @mul_div_cmp_greater(
-; CHECK-NEXT:    [[MUL:%.*]] = mul i8 [[X:%.*]], 3
-; CHECK-NEXT:    [[DIV:%.*]] = udiv i8 [[MUL]], 2
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ule i8 [[DIV]], [[X]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %mul = mul i8 %x, 3
-  %div = udiv i8 %mul, 2
-  %cmp = icmp ule i8 %div, %x
-  ret i1 %cmp
-}
-define i1 @mul_div_cmp_ugt(i8 %x) {
-; CHECK-LABEL: @mul_div_cmp_ugt(
-; CHECK-NEXT:    ret i1 false
-;
-  %mul = mul i8 %x, 3
-  %div = udiv i8 %mul, 4
-  %cmp = icmp ugt i8 %div, %x
-  ret i1 %cmp
-}
-
-; Negative test: Wrong predicate
-define i1 @mul_div_cmp_uge(i8 %x) {
-; CHECK-LABEL: @mul_div_cmp_uge(
-; CHECK-NEXT:    [[MUL:%.*]] = mul i8 [[X:%.*]], 3
-; CHECK-NEXT:    [[DIV:%.*]] = udiv i8 [[MUL]], 4
-; CHECK-NEXT:    [[CMP:%.*]] = icmp uge i8 [[DIV]], [[X]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %mul = mul i8 %x, 3
-  %div = udiv i8 %mul, 4
-  %cmp = icmp uge i8 %div, %x
-  ret i1 %cmp
-}
-
-; Negative test: Wrong predicate
-define i1 @mul_div_cmp_ult(i8 %x) {
-; CHECK-LABEL: @mul_div_cmp_ult(
-; CHECK-NEXT:    [[MUL:%.*]] = mul i8 [[X:%.*]], 3
-; CHECK-NEXT:    [[DIV:%.*]] = udiv i8 [[MUL]], 4
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i8 [[DIV]], [[X]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %mul = mul i8 %x, 3
-  %div = udiv i8 %mul, 4
-  %cmp = icmp ult i8 %div, %x
-  ret i1 %cmp
-}
-
-; Negative test: Wrong icmp operand
-define i1 @mul_div_cmp_wrong_operand(i8 %x, i8 %y) {
-; CHECK-LABEL: @mul_div_cmp_wrong_operand(
-; CHECK-NEXT:    [[MUL:%.*]] = mul i8 [[X:%.*]], 3
-; CHECK-NEXT:    [[DIV:%.*]] = udiv i8 [[MUL]], 4
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ule i8 [[DIV]], [[Y:%.*]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %mul = mul i8 %x, 3
-  %div = udiv i8 %mul, 4
-  %cmp = icmp ule i8 %div, %y
-  ret i1 %cmp
-}
-
-define i1 @mul_lshr_cmp_smaller(i8 %x) {
-; CHECK-LABEL: @mul_lshr_cmp_smaller(
-; CHECK-NEXT:    ret i1 true
-;
-  %mul = mul i8 %x, 3
-  %div = lshr i8 %mul, 2
-  %cmp = icmp ule i8 %div, %x
-  ret i1 %cmp
-}
-
-define i1 @mul_lshr_cmp_equal(i8 %x) {
-; CHECK-LABEL: @mul_lshr_cmp_equal(
-; CHECK-NEXT:    ret i1 true
-;
-  %mul = mul i8 %x, 4
-  %div = lshr i8 %mul, 2
-  %cmp = icmp ule i8 %div, %x
-  ret i1 %cmp
-}
-
-define i1 @mul_lshr_cmp_greater(i8 %x) {
-; CHECK-LABEL: @mul_lshr_cmp_greater(
-; CHECK-NEXT:    [[MUL:%.*]] = mul i8 [[X:%.*]], 5
-; CHECK-NEXT:    [[DIV:%.*]] = lshr i8 [[MUL]], 2
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ule i8 [[DIV]], [[X]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %mul = mul i8 %x, 5
-  %div = lshr i8 %mul, 2
-  %cmp = icmp ule i8 %div, %x
-  ret i1 %cmp
-}
-
-define i1 @shl_div_cmp_smaller(i8 %x) {
-; CHECK-LABEL: @shl_div_cmp_smaller(
-; CHECK-NEXT:    ret i1 true
-;
-  %mul = shl i8 %x, 2
-  %div = udiv i8 %mul, 5
-  %cmp = icmp ule i8 %div, %x
-  ret i1 %cmp
-}
-
-define i1 @shl_div_cmp_equal(i8 %x) {
-; CHECK-LABEL: @shl_div_cmp_equal(
-; CHECK-NEXT:    ret i1 true
-;
-  %mul = shl i8 %x, 2
-  %div = udiv i8 %mul, 4
-  %cmp = icmp ule i8 %div, %x
-  ret i1 %cmp
-}
-
-define i1 @shl_div_cmp_greater(i8 %x) {
-; CHECK-LABEL: @shl_div_cmp_greater(
-; CHECK-NEXT:    [[MUL:%.*]] = shl i8 [[X:%.*]], 2
-; CHECK-NEXT:    [[DIV:%.*]] = udiv i8 [[MUL]], 3
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ule i8 [[DIV]], [[X]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %mul = shl i8 %x, 2
-  %div = udiv i8 %mul, 3
-  %cmp = icmp ule i8 %div, %x
-  ret i1 %cmp
-}
-
-; Don't crash matching recurrences/invertible ops.
-
-define void @PR50191(i32 %x) {
-; CHECK-LABEL: @PR50191(
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    br label [[LOOP:%.*]]
-; CHECK:       loop:
-; CHECK-NEXT:    [[P1:%.*]] = phi i32 [ [[X:%.*]], [[ENTRY:%.*]] ], [ [[SUB1:%.*]], [[LOOP]] ]
-; CHECK-NEXT:    [[P2:%.*]] = phi i32 [ [[X]], [[ENTRY]] ], [ [[SUB2:%.*]], [[LOOP]] ]
-; CHECK-NEXT:    [[SUB1]] = sub i32 [[P1]], [[P2]]
-; CHECK-NEXT:    [[SUB2]] = sub i32 42, [[P2]]
-; CHECK-NEXT:    br label [[LOOP]]
-;
-entry:
-  br label %loop
-
-loop:
-  %p1 = phi i32 [ %x, %entry ], [ %sub1, %loop ]
-  %p2 = phi i32 [ %x, %entry ], [ %sub2, %loop ]
-  %cmp = icmp eq i32 %p1, %p2
-  %user = zext i1 %cmp to i32
-  %sub1 = sub i32 %p1, %p2
-  %sub2 = sub i32 42, %p2
-  br label %loop
-}
-
-define i1 @sub_false(i32 %x) {
-; CHECK-LABEL: @sub_false(
-; CHECK-NEXT:    ret i1 false
-;
-  %sub = sub i32 1, %x
-  %cmp = icmp eq i32 %sub, %x
-  ret i1 %cmp
-}
-
-define i1 @sub_swap(i8 %x) {
-; CHECK-LABEL: @sub_swap(
-; CHECK-NEXT:    ret i1 true
-;
-  %sub = sub i8 3, %x
-  %cmp = icmp ne i8 %x, %sub
-  ret i1 %cmp
-}
-
-define <2 x i1> @sub_odd(<2 x i8> %x) {
-; CHECK-LABEL: @sub_odd(
-; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
-;
-  %sub = sub <2 x i8> <i8 3, i8 3>, %x
-  %cmp = icmp ne <2 x i8> %sub, %x
-  ret <2 x i1> %cmp
-}
-
-define <2 x i1> @sub_odd_poison(<2 x i8> %x) {
-; CHECK-LABEL: @sub_odd_poison(
-; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
-;
-  %sub = sub <2 x i8> <i8 poison, i8 1>, %x
-  %cmp = icmp ne <2 x i8> %sub, %x
-  ret <2 x i1> %cmp
-}
-
-define i1 @sub_even(i8 %x) {
-; CHECK-LABEL: @sub_even(
-; CHECK-NEXT:    [[SUB:%.*]] = sub i8 2, [[X:%.*]]
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i8 [[SUB]], [[X]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %sub = sub i8 2, %x
-  %cmp = icmp ne i8 %sub, %x
-  ret i1 %cmp
-}
-
-define i1 @load_ptr(ptr %p) {
-; CHECK-LABEL: @load_ptr(
-; CHECK-NEXT:    ret i1 true
-;
-  %load_p = load ptr, ptr %p, !dereferenceable !{i64 8}
-  %r = icmp ne ptr %load_p, null
-  ret i1 %r
-}
-
 define i1 @load_ptr_null_valid(ptr %p) null_pointer_is_valid {
 ; CHECK-LABEL: @load_ptr_null_valid(
-; CHECK-NEXT:    ret i1 true
-;
-  %load_p = load ptr, ptr %p, !dereferenceable !{i64 8}
-  %r = icmp ne ptr %load_p, null
-  ret i1 %r
-}
-
-define i1 @non_eq_disjoint_or_common_op(i8 %x, i8 %y, i8 %ww, i8 %a) {
-; CHECK-LABEL: @non_eq_disjoint_or_common_op(
-; CHECK-NEXT:    ret i1 false
-;
-  %w = add nuw i8 %ww, 1
-  %z = add i8 %y, %w
-
-  %xy = or disjoint i8 %x, %y
-  %xz = or disjoint i8 %x, %z
-
-  %axy = add i8 %a, %xy
-  %axz = add i8 %a, %xz
-  %r = icmp eq i8 %axy, %axz
-  ret i1 %r
-}
-
-define i1 @non_eq_disjoint_or_common_op_fail(i8 %x, i8 %y, i8 %ww, i8 %a) {
-; CHECK-LABEL: @non_eq_disjoint_or_common_op_fail(
-; CHECK-NEXT:    [[W:%.*]] = add nuw i8 [[WW:%.*]], 1
-; CHECK-NEXT:    [[Z:%.*]] = add i8 [[Y:%.*]], [[W]]
-; CHECK-NEXT:    [[XY:%.*]] = or i8 [[X:%.*]], [[Y]]
-; CHECK-NEXT:    [[XZ:%.*]] = or disjoint i8 [[X]], [[Z]]
-; CHECK-NEXT:    [[AXY:%.*]] = add i8 [[A:%.*]], [[XY]]
-; CHECK-NEXT:    [[AXZ:%.*]] = add i8 [[A]], [[XZ]]
-; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[AXY]], [[AXZ]]
-; CHECK-NEXT:    ret i1 [[R]]
-;
-  %w = add nuw i8 %ww, 1
-  %z = add i8 %y, %w
-
-  %xy = or i8 %x, %y
-  %xz = or disjoint i8 %x, %z
-
-  %axy = add i8 %a, %xy
-  %axz = add i8 %a, %xz
-  %r = icmp eq i8 %axy, %axz
-  ret i1 %r
-}
-
-define i1 @non_eq_xor_common_op(i8 %x, i8 %y, i8 %ww, i8 %a) {
-; CHECK-LABEL: @non_eq_xor_common_op(
-; CHECK-NEXT:    ret i1 false
-;
-  %w = add nuw i8 %ww, 1
-  %z = add i8 %y, %w
-
-  %xy = xor i8 %y, %x
-  %xz = xor i8 %x, %z
-
-  %axy = add i8 %a, %xy
-  %axz = add i8 %a, %xz
-  %r = icmp eq i8 %axy, %axz
-  ret i1 %r
-}
-
-define i1 @non_eq_xor_common_op_fail(i8 %x, i8 %y, i8 %ww, i8 %a) {
-; CHECK-LABEL: @non_eq_xor_common_op_fail(
-; CHECK-NEXT:    [[W:%.*]] = add nsw i8 [[WW:%.*]], 1
-; CHECK-NEXT:    [[Z:%.*]] = add i8 [[Y:%.*]], [[W]]
-; CHECK-NEXT:    [[XY:%.*]] = xor i8 [[Y]], [[X:%.*]]
-; CHECK-NEXT:    [[XZ:%.*]] = xor i8 [[X]], [[Z]]
-; CHECK-NEXT:    [[AXY:%.*]] = add i8 [[A:%.*]], [[XY]]
-; CHECK-NEXT:    [[AXZ:%.*]] = add i8 [[A]], [[XZ]]
-; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[AXY]], [[AXZ]]
-; CHECK-NEXT:    ret i1 [[R]]
-;
-  %w = add nsw i8 %ww, 1
-  %z = add i8 %y, %w
-
-  %xy = xor i8 %y, %x
-  %xz = xor i8 %x, %z
-
-  %axy = add i8 %a, %xy
-  %axz = add i8 %a, %xz
-  %r = icmp eq i8 %axy, %axz
-  ret i1 %r
-}
-
-define i1 @non_eq_disjoint_or(i8 %x, i8 %yy, i8 %w) {
-; CHECK-LABEL: @non_eq_disjoint_or(
-; CHECK-NEXT:    ret i1 false
-;
-  %y = add nuw i8 %yy, 1
-  %lhs = add i8 %x, %w
-  %val = or disjoint i8 %y, %w
-  %rhs = add i8 %x, %val
-  %r = icmp eq i8 %lhs, %rhs
-  ret i1 %r
-}
-
-define i1 @non_eq_or_fail(i8 %x, i8 %yy, i8 %w) {
-; CHECK-LABEL: @non_eq_or_fail(
-; CHECK-NEXT:    [[Y:%.*]] = add nuw i8 [[YY:%.*]], 1
-; CHECK-NEXT:    [[LHS:%.*]] = add i8 [[X:%.*]], [[W:%.*]]
-; CHECK-NEXT:    [[VAL:%.*]] = or i8 [[Y]], [[W]]
-; CHECK-NEXT:    [[RHS:%.*]] = add i8 [[X]], [[VAL]]
-; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[LHS]], [[RHS]]
+; CHECK-NEXT:    [[LOAD_P:%.*]] = load ptr, ptr [[P:%.*]], align 8, !dereferenceable [[META0:![0-9]+]]
+; CHECK-NEXT:    [[R:%.*]] = icmp ne ptr [[LOAD_P]], null
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
-  %y = add nuw i8 %yy, 1
-  %lhs = add i8 %x, %w
-  %val = or i8 %y, %w
-  %rhs = add i8 %x, %val
-  %r = icmp eq i8 %lhs, %rhs
-  ret i1 %r
-}
-
-define i1 @non_eq_xor(i8 %x, i8 %yy, i8 %w) {
-; CHECK-LABEL: @non_eq_xor(
-; CHECK-NEXT:    ret i1 false
+; CHECK-DL-LABEL: @load_ptr_null_valid(
+; CHECK-DL-NEXT:    ret i1 true
 ;
-  %y = add nuw i8 %yy, 1
-  %lhs = add i8 %x, %w
-  %val = xor i8 %y, %w
-  %rhs = add i8 %x, %val
-  %r = icmp eq i8 %lhs, %rhs
-  ret i1 %r
-}
-
-define i1 @non_eq_xor_fail(i8 %x, i8 %yy, i8 %w) {
-; CHECK-LABEL: @non_eq_xor_fail(
-; CHECK-NEXT:    [[Y:%.*]] = add nsw i8 [[YY:%.*]], 1
-; CHECK-NEXT:    [[LHS:%.*]] = add i8 [[X:%.*]], [[W:%.*]]
-; CHECK-NEXT:    [[VAL:%.*]] = xor i8 [[Y]], [[W]]
-; CHECK-NEXT:    [[RHS:%.*]] = add i8 [[X]], [[VAL]]
-; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[LHS]], [[RHS]]
-; CHECK-NEXT:    ret i1 [[R]]
-;
-  %y = add nsw i8 %yy, 1
-  %lhs = add i8 %x, %w
-  %val = xor i8 %y, %w
-  %rhs = add i8 %x, %val
-  %r = icmp eq i8 %lhs, %rhs
+; ASM-LABEL: @load_ptr_null_valid(
+; ASM-NEXT:    [[LOAD_P:%.*]] = load ptr, ptr [[P:%.*]], align 8, !dereferenceable [[META0:![0-9]+]]
+; ASM-NEXT:    [[R:%.*]] = icmp ne ptr [[LOAD_P]], null
+; ASM-NEXT:    ret i1 [[R]]
+  %load_p = load ptr, ptr %p, !dereferenceable !{i64 8}
+  %r = icmp ne ptr %load_p, null
   ret i1 %r
 }
diff --git a/llvm/test/Transforms/InstSimplify/null-ptr-is-valid-dl-sentinel.ll b/llvm/test/Transforms/InstSimplify/null-ptr-is-valid-dl-sentinel.ll
index e66ea08eaca36..0f6a3af63a189 100755
--- a/llvm/test/Transforms/InstSimplify/null-ptr-is-valid-dl-sentinel.ll
+++ b/llvm/test/Transforms/InstSimplify/null-ptr-is-valid-dl-sentinel.ll
@@ -1,23 +1,80 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
 ; RUN: opt -S -passes=instsimplify < %s | FileCheck %s
-
-target datalayout = "A5-z0:1-z2:neg1-z3:neg1-z5:neg1"
-
+; RUN: opt -S -passes=instsimplify -data-layout=z0:1-z2:neg1-z3:neg1-z5:neg1 -S < %s | FileCheck %s --check-prefixes=CHECK-DL
 ; A 0 valued byval pointer may be valid
 define i1 @byval_may_be_zero(ptr addrspace(5) byval(i32) %ptr) {
 ; CHECK-LABEL: @byval_may_be_zero(
-; CHECK-NEXT:    ret i1 false
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr addrspace(5) [[PTR:%.*]], null
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+; CHECK-DL-LABEL: @byval_may_be_zero(
+; CHECK-DL-NEXT:    ret i1 false
 ;
   %cmp = icmp eq ptr addrspace(5) %ptr, null
   ret i1 %cmp
 }
 
-; FIXME: The interpretation of nonnull assumes a 0 pointer value, so
-; this really is an incorrect fold.
-define i1 @nonnull_may_be_zero(ptr addrspace(5) nonnull %ptr) {
-; CHECK-LABEL: @nonnull_may_be_zero(
-; CHECK-NEXT:    ret i1 false
+define i1 @non-byval_may_be_zero(ptr addrspace(5) %ptr) {
+; CHECK-LABEL: @non-byval_may_be_zero(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr addrspace(5) [[PTR:%.*]], null
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+; CHECK-DL-LABEL: @non-byval_may_be_zero(
+; CHECK-DL-NEXT:    ret i1 false
 ;
   %cmp = icmp eq ptr addrspace(5) %ptr, null
   ret i1 %cmp
 }
+
+define i1 @ptr_may_be_zero(ptr addrspace(5) %ptr) {
+; CHECK-LABEL: @ptr_may_be_zero(
+; CHECK-NEXT:    [[LOAD:%.*]] = load ptr addrspace(5), ptr addrspace(5) [[PTR:%.*]], align 8
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr addrspace(5) [[LOAD]], null
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+; CHECK-DL-LABEL: @ptr_may_be_zero(
+; CHECK-DL-NEXT:    ret i1 false
+;
+  %load = load ptr addrspace(5), ptr addrspace(5) %ptr
+  %cmp = icmp eq ptr addrspace(5) %load, null
+  ret i1 %cmp
+}
+
+; A 0 valued byval pointer may be valid
+define i1 @byval_may_be_zero_addrspace3(ptr addrspace(3) byval(i32) %ptr) {
+; CHECK-LABEL: @byval_may_be_zero_addrspace3(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr addrspace(3) [[PTR:%.*]], null
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+; CHECK-DL-LABEL: @byval_may_be_zero_addrspace3(
+; CHECK-DL-NEXT:    ret i1 false
+;
+  %cmp = icmp eq ptr addrspace(3) %ptr, null
+  ret i1 %cmp
+}
+
+define i1 @non-byval_may_be_zero_addrspace3(ptr addrspace(3) %ptr) {
+; CHECK-LABEL: @non-byval_may_be_zero_addrspace3(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr addrspace(3) [[PTR:%.*]], null
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+; CHECK-DL-LABEL: @non-byval_may_be_zero_addrspace3(
+; CHECK-DL-NEXT:    ret i1 false
+;
+  %cmp = icmp eq ptr addrspace(3) %ptr, null
+  ret i1 %cmp
+}
+
+define i1 @ptr_may_be_zero_addrspace3(ptr addrspace(3) %ptr) {
+; CHECK-LABEL: @ptr_may_be_zero_addrspace3(
+; CHECK-NEXT:    [[LOAD:%.*]] = load ptr addrspace(3), ptr addrspace(3) [[PTR:%.*]], align 8
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr addrspace(3) [[LOAD]], null
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+; CHECK-DL-LABEL: @ptr_may_be_zero_addrspace3(
+; CHECK-DL-NEXT:    ret i1 false
+;
+  %load = load ptr addrspace(3), ptr addrspace(3) %ptr
+  %cmp = icmp eq ptr addrspace(3) %load, null
+  ret i1 %cmp
+}



More information about the llvm-commits mailing list