summaryrefslogtreecommitdiff
path: root/llvm/test/Transforms/SROA/preserve-metadata.ll
blob: ba8fbc8efc3755acbc77195ee267d7f9ba0138c2 (plain)
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: {{.*}}