1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
|
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-PRESERVE-CFG
; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-MODIFY-CFG
;
; Make sure that SROA doesn't lose nonnull metadata
; on loads from allocas that get optimized out.
declare void @llvm.memcpy.p0.p0.i64(ptr nocapture writeonly, ptr nocapture readonly, i64, i1)
; Check that we do basic propagation of nonnull when rewriting.
define ptr @propagate_nonnull(ptr %v) {
; CHECK-LABEL: @propagate_nonnull(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A_SROA_1:%.*]] = alloca ptr, align 8
; CHECK-NEXT: store ptr [[V:%.*]], ptr [[A_SROA_1]], align 8
; CHECK-NEXT: [[A_SROA_1_0_A_SROA_1_8_LOAD:%.*]] = load volatile ptr, ptr [[A_SROA_1]], align 8, !nonnull !0
; CHECK-NEXT: ret ptr [[A_SROA_1_0_A_SROA_1_8_LOAD]]
;
entry:
%a = alloca [2 x ptr]
%a.gep1 = getelementptr [2 x ptr], ptr %a, i32 0, i32 1
store ptr %v, ptr %a.gep1
store ptr null, ptr %a
%load = load volatile ptr, ptr %a.gep1, !nonnull !0
ret ptr %load
}
define i32 @propagate_range(i32 %v) {
; CHECK-LABEL: @propagate_range(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A_SROA_1:%.*]] = alloca i32, align 4
; CHECK-NEXT: store i32 [[V:%.*]], ptr [[A_SROA_1]], align 4
; CHECK-NEXT: [[A_SROA_1_0_A_SROA_1_4_LOAD:%.*]] = load volatile i32, ptr [[A_SROA_1]], align 4, !range [[RNG1:![0-9]+]]
; CHECK-NEXT: ret i32 [[A_SROA_1_0_A_SROA_1_4_LOAD]]
;
entry:
%a = alloca [2 x i32]
%a.gep1 = getelementptr [2 x i32], ptr %a, i32 0, i32 1
store i32 %v, ptr %a.gep1
store i32 0, ptr %a
%load = load volatile i32, ptr %a.gep1, !range !{i32 0, i32 10}
ret i32 %load
}
define ptr @propagate_noundef(ptr %v) {
; CHECK-LABEL: @propagate_noundef(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A_SROA_1:%.*]] = alloca ptr, align 8
; CHECK-NEXT: store ptr [[V:%.*]], ptr [[A_SROA_1]], align 8
; CHECK-NEXT: [[A_SROA_1_0_A_SROA_1_8_LOAD:%.*]] = load volatile ptr, ptr [[A_SROA_1]], align 8, !noundef !0
; CHECK-NEXT: ret ptr [[A_SROA_1_0_A_SROA_1_8_LOAD]]
;
entry:
%a = alloca [2 x ptr]
%a.gep1 = getelementptr [2 x ptr], ptr %a, i32 0, i32 1
store ptr %v, ptr %a.gep1
store ptr null, ptr %a
%load = load volatile ptr, ptr %a.gep1, !noundef !0
ret ptr %load
}
define ptr @turn_nonnull_noundef_into_assume(ptr %arg) {
; CHECK-LABEL: @turn_nonnull_noundef_into_assume(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[BUF_0_COPYLOAD:%.*]] = load ptr, ptr [[ARG:%.*]], align 8
; CHECK-NEXT: [[TMP0:%.*]] = icmp ne ptr [[BUF_0_COPYLOAD]], null
; CHECK-NEXT: call void @llvm.assume(i1 [[TMP0]])
; CHECK-NEXT: ret ptr [[BUF_0_COPYLOAD]]
;
entry:
%buf = alloca ptr
call void @llvm.memcpy.p0.p0.i64(ptr align 8 %buf, ptr align 8 %arg, i64 8, i1 false)
%ret = load ptr, ptr %buf, align 8, !nonnull !0, !noundef !0
ret ptr %ret
}
define ptr @dont_turn_nonnull_without_noundef_into_assume(ptr %arg) {
; CHECK-LABEL: @dont_turn_nonnull_without_noundef_into_assume(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[BUF_0_COPYLOAD:%.*]] = load ptr, ptr [[ARG:%.*]], align 8
; CHECK-NEXT: ret ptr [[BUF_0_COPYLOAD]]
;
entry:
%buf = alloca ptr
call void @llvm.memcpy.p0.p0.i64(ptr align 8 %buf, ptr align 8 %arg, i64 8, i1 false)
%ret = load ptr, ptr %buf, align 8, !nonnull !0
ret ptr %ret
}
; Make sure we properly handle the !nonnull attribute when we convert
; a pointer load to an integer load.
; FIXME: While this doesn't do anythnig actively harmful today, it really
; should propagate the !nonnull metadata to range metadata. The irony is, it
; *does* initially, but then we lose that !range metadata before we finish
; SROA.
define ptr @propagate_nonnull_to_int() {
; CHECK-LABEL: @propagate_nonnull_to_int(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A_SROA_1:%.*]] = alloca ptr, align 8
; CHECK-NEXT: store ptr inttoptr (i64 42 to ptr), ptr [[A_SROA_1]], align 8
; CHECK-NEXT: [[A_SROA_1_0_A_SROA_1_8_LOAD:%.*]] = load volatile ptr, ptr [[A_SROA_1]], align 8, !nonnull !0
; CHECK-NEXT: ret ptr [[A_SROA_1_0_A_SROA_1_8_LOAD]]
;
entry:
%a = alloca [2 x ptr]
%a.gep1 = getelementptr [2 x ptr], ptr %a, i32 0, i32 1
store i64 42, ptr %a.gep1
store i64 0, ptr %a
%load = load volatile ptr, ptr %a.gep1, !nonnull !0
ret ptr %load
}
; Make sure we properly handle the !nonnull attribute when we convert
; a pointer load to an integer load and immediately promote it to an SSA
; register. This can fail in interesting ways due to the rewrite iteration of
; SROA, resulting in PR32902.
define ptr @propagate_nonnull_to_int_and_promote() {
; CHECK-LABEL: @propagate_nonnull_to_int_and_promote(
; CHECK-NEXT: entry:
; CHECK-NEXT: ret ptr inttoptr (i64 42 to ptr)
;
entry:
%a = alloca [2 x ptr], align 8
%a.gep1 = getelementptr [2 x ptr], ptr %a, i32 0, i32 1
store i64 42, ptr %a.gep1
store i64 0, ptr %a
%load = load ptr, ptr %a.gep1, align 8, !nonnull !0
ret ptr %load
}
define i128 @load_i128_to_load_ptr() {
; CHECK-LABEL: @load_i128_to_load_ptr(
; CHECK-NEXT: [[TMP1:%.*]] = ptrtoint ptr null to i64
; CHECK-NEXT: [[A_SROA_2_0_INSERT_EXT:%.*]] = zext i64 undef to i128
; CHECK-NEXT: [[A_SROA_2_0_INSERT_SHIFT:%.*]] = shl i128 [[A_SROA_2_0_INSERT_EXT]], 64
; CHECK-NEXT: [[A_SROA_2_0_INSERT_MASK:%.*]] = and i128 undef, 18446744073709551615
; CHECK-NEXT: [[A_SROA_2_0_INSERT_INSERT:%.*]] = or i128 [[A_SROA_2_0_INSERT_MASK]], [[A_SROA_2_0_INSERT_SHIFT]]
; CHECK-NEXT: [[A_SROA_0_0_INSERT_EXT:%.*]] = zext i64 [[TMP1]] to i128
; CHECK-NEXT: [[A_SROA_0_0_INSERT_MASK:%.*]] = and i128 [[A_SROA_2_0_INSERT_INSERT]], -18446744073709551616
; CHECK-NEXT: [[A_SROA_0_0_INSERT_INSERT:%.*]] = or i128 [[A_SROA_0_0_INSERT_MASK]], [[A_SROA_0_0_INSERT_EXT]]
; CHECK-NEXT: ret i128 [[A_SROA_0_0_INSERT_INSERT]]
;
%a = alloca i128
store ptr null, ptr %a
%v = load i128, ptr %a, !range !{i128 1, i128 0}
ret i128 %v
}
!0 = !{}
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
; CHECK-MODIFY-CFG: {{.*}}
; CHECK-PRESERVE-CFG: {{.*}}
|