aboutsummaryrefslogtreecommitdiff
path: root/llvm/test/Transforms/InstCombine/may-alias-errno.ll
blob: 40fab8024b3626a3983aaacf8b678a1ca5dfbf1d (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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
; RUN: opt -S -passes=instcombine < %s | FileCheck %s

; sinf clobbering errno, but %p cannot alias errno per C/C++ strict aliasing rules via TBAA.
; Can do constant store-to-load forwarding.
define float @does_not_alias_errno(ptr %p, float %f) {
; CHECK-LABEL: define float @does_not_alias_errno(
; CHECK-SAME: ptr [[P:%.*]], float [[F:%.*]]) {
; CHECK-NEXT:  [[ENTRY:.*:]]
; CHECK-NEXT:    store float 0.000000e+00, ptr [[P]], align 4, !tbaa [[TBAA4:![0-9]+]]
; CHECK-NEXT:    [[CALL:%.*]] = call float @sinf(float [[F]])
; CHECK-NEXT:    ret float 0.000000e+00
;
entry:
  store float 0.000000e+00, ptr %p, align 4, !tbaa !4
  %call = call float @sinf(float %f)
  %0 = load float, ptr %p, align 4, !tbaa !4
  ret float %0
}

; sinf clobbering errno, but %p is alloca memory, wich can never aliases errno.
; Can do constant store-to-load forwarding.
define float @does_not_alias_errno_2(float %f) {
; CHECK-LABEL: define float @does_not_alias_errno_2(
; CHECK-SAME: float [[F:%.*]]) {
; CHECK-NEXT:  [[ENTRY:.*:]]
; CHECK-NEXT:    [[P:%.*]] = alloca float, align 4
; CHECK-NEXT:    call void @escape(ptr nonnull [[P]])
; CHECK-NEXT:    store float 0.000000e+00, ptr [[P]], align 4
; CHECK-NEXT:    [[TMP1:%.*]] = call float @sinf(float [[F]])
; CHECK-NEXT:    ret float 0.000000e+00
;
entry:
  %p = alloca float
  call void @escape(ptr %p)
  store float 0.0, ptr %p
  call float @sinf(float %f)
  %v = load float, ptr %p
  ret float %v
}

; sinf clobbering errno, but %p is memory accessed w/ size larger than errno.
; Can do constant store-to-load forwarding.
define double @does_not_alias_errno_3(ptr %p, float %f) {
; CHECK-LABEL: define double @does_not_alias_errno_3(
; CHECK-SAME: ptr [[P:%.*]], float [[F:%.*]]) {
; CHECK-NEXT:  [[ENTRY:.*:]]
; CHECK-NEXT:    call void @escape(ptr [[P]])
; CHECK-NEXT:    store double 0.000000e+00, ptr [[P]], align 8
; CHECK-NEXT:    [[TMP1:%.*]] = call float @sinf(float [[F]])
; CHECK-NEXT:    ret double 0.000000e+00
;
entry:
  call void @escape(ptr %p)
  store double 0.0, ptr %p
  call float @sinf(float %f)
  %v = load double, ptr %p
  ret double %v
}

; %p may alias errno, but read_errno does not clobber errno.
; Can do constant store-to-load forwarding.
define float @may_alias_errno_does_not_clobber(ptr %p, ptr byval(i8) %q) {
; CHECK-LABEL: define float @may_alias_errno_does_not_clobber(
; CHECK-SAME: ptr [[P:%.*]], ptr byval(i8) [[Q:%.*]]) {
; CHECK-NEXT:  [[ENTRY:.*:]]
; CHECK-NEXT:    store float 0.000000e+00, ptr [[P]], align 4
; CHECK-NEXT:    [[CALL:%.*]] = call float @read_errno(ptr nonnull [[Q]])
; CHECK-NEXT:    ret float 0.000000e+00
;
entry:
  store float 0.000000e+00, ptr %p, align 4
  %call = call float @read_errno(ptr %q)
  %0 = load float, ptr %p, align 4
  ret float %0
}

; sinf clobbering errno, unknown TBAA info, %p may alias errno.
; Cannot do constant store-to-load forwarding.
define float @may_alias_errno(ptr %p, float %f) {
; CHECK-LABEL: define float @may_alias_errno(
; CHECK-SAME: ptr [[P:%.*]], float [[F:%.*]]) {
; CHECK-NEXT:  [[ENTRY:.*:]]
; CHECK-NEXT:    store float 0.000000e+00, ptr [[P]], align 4
; CHECK-NEXT:    [[CALL:%.*]] = call float @sinf(float [[F]])
; CHECK-NEXT:    [[TMP0:%.*]] = load float, ptr [[P]], align 4
; CHECK-NEXT:    ret float [[TMP0]]
;
entry:
  store float 0.000000e+00, ptr %p, align 4
  %call = call float @sinf(float %f)
  %0 = load float, ptr %p, align 4
  ret float %0
}

; sinf clobbering errno, %p, a integer pointer, may alias errno.
; Cannot do constant store-to-load forwarding.
define i32 @may_alias_errno_2(ptr %p, float %f) {
; CHECK-LABEL: define i32 @may_alias_errno_2(
; CHECK-SAME: ptr [[P:%.*]], float [[F:%.*]]) {
; CHECK-NEXT:  [[ENTRY:.*:]]
; CHECK-NEXT:    store i32 0, ptr [[P]], align 4, !tbaa [[TBAA0:![0-9]+]]
; CHECK-NEXT:    [[CALL:%.*]] = call float @sinf(float [[F]])
; CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr [[P]], align 4, !tbaa [[TBAA0]]
; CHECK-NEXT:    ret i32 [[TMP0]]
;
entry:
  store i32 0, ptr %p, align 4, !tbaa !0
  %call = call float @sinf(float %f)
  %0 = load i32, ptr %p, align 4, !tbaa !0
  ret i32 %0
}

; sinf clobbering errno, but %p is memory accessed w/ vector size larger than errno.
; Can do constant store-to-load forwarding.
define <4 x i32> @does_not_alias_errno_vec(ptr %p, float %f) {
; CHECK-LABEL: define <4 x i32> @does_not_alias_errno_vec(
; CHECK-SAME: ptr [[P:%.*]], float [[F:%.*]]) {
; CHECK-NEXT:  [[ENTRY:.*:]]
; CHECK-NEXT:    call void @escape(ptr [[P]])
; CHECK-NEXT:    store <4 x i32> zeroinitializer, ptr [[P]], align 16
; CHECK-NEXT:    [[TMP0:%.*]] = call float @sinf(float [[F]])
; CHECK-NEXT:    ret <4 x i32> zeroinitializer
;
entry:
  call void @escape(ptr %p)
  store <4 x i32> zeroinitializer, ptr %p
  call float @sinf(float %f)
  %v = load <4 x i32>, ptr %p
  ret <4 x i32> %v
}

; sinf clobbering errno, but %p is memory accessed w/ scalable vector size larger than errno.
; Can do constant store-to-load forwarding.
define <vscale x 4 x i32> @does_not_alias_errno_scalablevec(ptr %p, float %f) {
; CHECK-LABEL: define <vscale x 4 x i32> @does_not_alias_errno_scalablevec(
; CHECK-SAME: ptr [[P:%.*]], float [[F:%.*]]) {
; CHECK-NEXT:  [[ENTRY:.*:]]
; CHECK-NEXT:    call void @escape(ptr [[P]])
; CHECK-NEXT:    store <vscale x 4 x i32> zeroinitializer, ptr [[P]], align 16
; CHECK-NEXT:    [[TMP0:%.*]] = call float @sinf(float [[F]])
; CHECK-NEXT:    ret <vscale x 4 x i32> zeroinitializer
;
entry:
  call void @escape(ptr %p)
  store <vscale x 4 x i32> zeroinitializer, ptr %p
  call float @sinf(float %f)
  %v = load <vscale x 4 x i32>, ptr %p
  ret <vscale x 4 x i32> %v
}

declare float @sinf(float) memory(errnomem: write)
declare float @read_errno(ptr) memory(argmem: write, errnomem: read)
declare void @escape(ptr %p)

!llvm.errno.tbaa = !{!0}

!0 = !{!1, !1, i64 0}
!1 = !{!"int", !2, i64 0}
!2 = !{!"omnipotent char", !3, i64 0}
!3 = !{!"Simple C/C++ TBAA"}
!4 = !{!5, !5, i64 0}
!5 = !{!"float", !2, i64 0}
;.
; CHECK: [[TBAA0]] = !{[[META1:![0-9]+]], [[META1]], i64 0}
; CHECK: [[META1]] = !{!"int", [[META2:![0-9]+]], i64 0}
; CHECK: [[META2]] = !{!"omnipotent char", [[META3:![0-9]+]], i64 0}
; CHECK: [[META3]] = !{!"Simple C/C++ TBAA"}
; CHECK: [[TBAA4]] = !{[[META5:![0-9]+]], [[META5]], i64 0}
; CHECK: [[META5]] = !{!"float", [[META2]], i64 0}
;.