1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt -instcombine -S < %s | FileCheck --check-prefix OPT %s
4 target triple = "aarch64"
6 ; Most of the testing is covered by the lastb cases, but here we ensure that
7 ; lasta with a predicate having no active lanes is treated as an alias to
8 ; extracting the first vector element.
9 define i8 @lasta_extractelement_0(<vscale x 16 x i8> %v) #0 {
10 ; OPT-LABEL: @lasta_extractelement_0(
11 ; OPT-NEXT: [[E0:%.*]] = extractelement <vscale x 16 x i8> [[V:%.*]], i64 0
12 ; OPT-NEXT: ret i8 [[E0]]
14 %e0 = tail call i8 @llvm.aarch64.sve.lasta.nxv16i8(<vscale x 16 x i1> zeroinitializer, <vscale x 16 x i8> %v)
18 ; Most of the testing is covered by the lastb cases, but here we check the
19 ; resulting extraction index is one more than the lastb case because lasta
20 ; extracts the element after the last active.
21 define i8 @lasta_extractelement_8(<vscale x 16 x i8> %v) #0 {
22 ; OPT-LABEL: @lasta_extractelement_8(
23 ; OPT-NEXT: [[E1:%.*]] = extractelement <vscale x 16 x i8> [[V:%.*]], i64 8
24 ; OPT-NEXT: ret i8 [[E1]]
26 %pg = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 8)
27 %e1 = tail call i8 @llvm.aarch64.sve.lasta.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %v)
31 define i8 @lastb_extractelement_0(<vscale x 16 x i8> %v) #0 {
32 ; OPT-LABEL: @lastb_extractelement_0(
33 ; OPT-NEXT: [[E0:%.*]] = extractelement <vscale x 16 x i8> [[V:%.*]], i64 0
34 ; OPT-NEXT: ret i8 [[E0]]
36 %pg = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 1)
37 %e0 = tail call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %v)
41 define i8 @lastb_extractelement_1(<vscale x 16 x i8> %v) #0 {
42 ; OPT-LABEL: @lastb_extractelement_1(
43 ; OPT-NEXT: [[E1:%.*]] = extractelement <vscale x 16 x i8> [[V:%.*]], i64 1
44 ; OPT-NEXT: ret i8 [[E1]]
46 %pg = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 2)
47 %e1 = tail call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %v)
51 define i8 @lastb_extractelement_2(<vscale x 16 x i8> %v) #0 {
52 ; OPT-LABEL: @lastb_extractelement_2(
53 ; OPT-NEXT: [[E2:%.*]] = extractelement <vscale x 16 x i8> [[V:%.*]], i64 2
54 ; OPT-NEXT: ret i8 [[E2]]
56 %pg = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 3)
57 %e2 = tail call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %v)
61 define i8 @lastb_extractelement_3(<vscale x 16 x i8> %v) #0 {
62 ; OPT-LABEL: @lastb_extractelement_3(
63 ; OPT-NEXT: [[E3:%.*]] = extractelement <vscale x 16 x i8> [[V:%.*]], i64 3
64 ; OPT-NEXT: ret i8 [[E3]]
66 %pg = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 4)
67 %e3 = tail call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %v)
71 define i8 @lastb_extractelement_4(<vscale x 16 x i8> %v) #0 {
72 ; OPT-LABEL: @lastb_extractelement_4(
73 ; OPT-NEXT: [[E4:%.*]] = extractelement <vscale x 16 x i8> [[V:%.*]], i64 4
74 ; OPT-NEXT: ret i8 [[E4]]
76 %pg = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 5)
77 %e4 = tail call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %v)
81 define i8 @lastb_extractelement_5(<vscale x 16 x i8> %v) #0 {
82 ; OPT-LABEL: @lastb_extractelement_5(
83 ; OPT-NEXT: [[E5:%.*]] = extractelement <vscale x 16 x i8> [[V:%.*]], i64 5
84 ; OPT-NEXT: ret i8 [[E5]]
86 %pg = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 6)
87 %e5 = tail call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %v)
91 define i8 @lastb_extractelement_6(<vscale x 16 x i8> %v) #0 {
92 ; OPT-LABEL: @lastb_extractelement_6(
93 ; OPT-NEXT: [[E6:%.*]] = extractelement <vscale x 16 x i8> [[V:%.*]], i64 6
94 ; OPT-NEXT: ret i8 [[E6]]
96 %pg = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 7)
97 %e6 = tail call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %v)
101 define i8 @lastb_extractelement_7(<vscale x 16 x i8> %v) #0 {
102 ; OPT-LABEL: @lastb_extractelement_7(
103 ; OPT-NEXT: [[E7:%.*]] = extractelement <vscale x 16 x i8> [[V:%.*]], i64 7
104 ; OPT-NEXT: ret i8 [[E7]]
106 %pg = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 8)
107 %e7 = tail call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %v)
111 define i8 @lastb_extractelement_15(<vscale x 16 x i8> %v) #0 {
112 ; OPT-LABEL: @lastb_extractelement_15(
113 ; OPT-NEXT: [[E15:%.*]] = extractelement <vscale x 16 x i8> [[V:%.*]], i64 15
114 ; OPT-NEXT: ret i8 [[E15]]
116 %pg = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 9)
117 %e15 = tail call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %v)
121 ; No transformation because the requested element is beyond the range of the
122 ; known minimum element count so we maintain the user's intentions.
123 define i8 @lastb_extractelement_31(<vscale x 16 x i8> %v) #0 {
124 ; OPT-LABEL: @lastb_extractelement_31(
125 ; OPT-NEXT: [[PG:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 10)
126 ; OPT-NEXT: [[E31:%.*]] = tail call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[V:%.*]])
127 ; OPT-NEXT: ret i8 [[E31]]
129 %pg = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 10)
130 %e31 = tail call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %v)
134 ; No transformation because the ptrue's predicate pattern is bogus and thus
135 ; nothing can be inferred about the result.
136 define i8 @lastb_extractelement_invalid_predicate_pattern(<vscale x 16 x i8> %v) #0 {
137 ; OPT-LABEL: @lastb_extractelement_invalid_predicate_pattern(
138 ; OPT-NEXT: [[PG:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 15)
139 ; OPT-NEXT: [[E:%.*]] = tail call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[V:%.*]])
140 ; OPT-NEXT: ret i8 [[E]]
142 %pg = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 15)
143 %e = tail call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %v)
147 ; Return the splatted value irrespective of the predicate.
148 define i8 @lasta_splat(<vscale x 16 x i1> %pg, i8 %a) #0 {
149 ; OPT-LABEL: @lasta_splat(
150 ; OPT-NEXT: ret i8 [[A:%.*]]
152 %splat_insert = insertelement <vscale x 16 x i8> poison, i8 %a, i32 0
153 %splat = shufflevector <vscale x 16 x i8> %splat_insert, <vscale x 16 x i8> poison, <vscale x 16 x i32> zeroinitializer
154 %last = tail call i8 @llvm.aarch64.sve.lasta.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %splat)
158 define i8 @lastb_splat(<vscale x 16 x i1> %pg, i8 %a) #0 {
159 ; OPT-LABEL: @lastb_splat(
160 ; OPT-NEXT: ret i8 [[A:%.*]]
162 %splat_insert = insertelement <vscale x 16 x i8> poison, i8 %a, i32 0
163 %splat = shufflevector <vscale x 16 x i8> %splat_insert, <vscale x 16 x i8> poison, <vscale x 16 x i32> zeroinitializer
164 %last = tail call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %splat)
168 ; Check that we move the lastb before the binary operation so that the new binary op is scalar.
169 define i8 @lastb_binop_RHS_splat_sdiv(<vscale x 16 x i1> %pg, i8 %scalar, <vscale x 16 x i8> %vector) #0 {
170 ; OPT-LABEL: @lastb_binop_RHS_splat_sdiv(
171 ; OPT-NEXT: [[TMP1:%.*]] = call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> [[PG:%.*]], <vscale x 16 x i8> [[VECTOR:%.*]])
172 ; OPT-NEXT: [[BINOP1:%.*]] = sdiv i8 [[TMP1]], [[SCALAR:%.*]]
173 ; OPT-NEXT: ret i8 [[BINOP1]]
175 %splat_insert = insertelement <vscale x 16 x i8> poison, i8 %scalar, i32 0
176 %splat = shufflevector <vscale x 16 x i8> %splat_insert, <vscale x 16 x i8> poison, <vscale x 16 x i32> zeroinitializer
177 %binop = sdiv <vscale x 16 x i8> %vector, %splat
178 %last = tail call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %binop)
182 define i8 @lastb_binop_RHS_splat_sdiv_exact(<vscale x 16 x i1> %pg, i8 %scalar, <vscale x 16 x i8> %vector) #0 {
183 ; OPT-LABEL: @lastb_binop_RHS_splat_sdiv_exact(
184 ; OPT-NEXT: [[TMP1:%.*]] = call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> [[PG:%.*]], <vscale x 16 x i8> [[VECTOR:%.*]])
185 ; OPT-NEXT: [[BINOP1:%.*]] = sdiv exact i8 [[TMP1]], [[SCALAR:%.*]]
186 ; OPT-NEXT: ret i8 [[BINOP1]]
188 %splat_insert = insertelement <vscale x 16 x i8> poison, i8 %scalar, i32 0
189 %splat = shufflevector <vscale x 16 x i8> %splat_insert, <vscale x 16 x i8> poison, <vscale x 16 x i32> zeroinitializer
190 %binop = sdiv exact <vscale x 16 x i8> %vector, %splat
191 %last = tail call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %binop)
195 define float @lastb_binop_RHS_splat_fdiv_float_fast(<vscale x 4 x i1> %pg, float %scalar, <vscale x 4 x float> %vector) #0 {
196 ; OPT-LABEL: @lastb_binop_RHS_splat_fdiv_float_fast(
197 ; OPT-NEXT: [[TMP1:%.*]] = call float @llvm.aarch64.sve.lastb.nxv4f32(<vscale x 4 x i1> [[PG:%.*]], <vscale x 4 x float> [[VECTOR:%.*]])
198 ; OPT-NEXT: [[BINOP1:%.*]] = fdiv fast float [[TMP1]], [[SCALAR:%.*]]
199 ; OPT-NEXT: ret float [[BINOP1]]
201 %splat_insert = insertelement <vscale x 4 x float> poison, float %scalar, i32 0
202 %splat = shufflevector <vscale x 4 x float> %splat_insert, <vscale x 4 x float> poison, <vscale x 4 x i32> zeroinitializer
203 %binop = fdiv fast <vscale x 4 x float> %vector, %splat
204 %last = tail call float @llvm.aarch64.sve.lastb.nxv4f32(<vscale x 4 x i1> %pg, <vscale x 4 x float> %binop)
208 define float @lastb_binop_RHS_splat_fdiv_float(<vscale x 4 x i1> %pg, float %scalar, <vscale x 4 x float> %vector) #0 {
209 ; OPT-LABEL: @lastb_binop_RHS_splat_fdiv_float(
210 ; OPT-NEXT: [[TMP1:%.*]] = call float @llvm.aarch64.sve.lastb.nxv4f32(<vscale x 4 x i1> [[PG:%.*]], <vscale x 4 x float> [[VECTOR:%.*]])
211 ; OPT-NEXT: [[BINOP1:%.*]] = fdiv float [[TMP1]], [[SCALAR:%.*]]
212 ; OPT-NEXT: ret float [[BINOP1]]
214 %splat_insert = insertelement <vscale x 4 x float> poison, float %scalar, i32 0
215 %splat = shufflevector <vscale x 4 x float> %splat_insert, <vscale x 4 x float> poison, <vscale x 4 x i32> zeroinitializer
216 %binop = fdiv <vscale x 4 x float> %vector, %splat
217 %last = tail call float @llvm.aarch64.sve.lastb.nxv4f32(<vscale x 4 x i1> %pg, <vscale x 4 x float> %binop)
221 define i8 @lastb_binop_LHS_splat_sdiv(<vscale x 16 x i1> %pg, i8 %scalar, <vscale x 16 x i8> %vector) #0 {
222 ; OPT-LABEL: @lastb_binop_LHS_splat_sdiv(
223 ; OPT-NEXT: [[TMP1:%.*]] = call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> [[PG:%.*]], <vscale x 16 x i8> [[VECTOR:%.*]])
224 ; OPT-NEXT: [[BINOP1:%.*]] = sdiv i8 [[SCALAR:%.*]], [[TMP1]]
225 ; OPT-NEXT: ret i8 [[BINOP1]]
227 %splat_insert = insertelement <vscale x 16 x i8> poison, i8 %scalar, i32 0
228 %splat = shufflevector <vscale x 16 x i8> %splat_insert, <vscale x 16 x i8> poison, <vscale x 16 x i32> zeroinitializer
229 %binop = sdiv <vscale x 16 x i8> %splat, %vector
230 %last = tail call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %binop)
234 define i8 @lastb_binop_LHS_splat_sdiv_exact(<vscale x 16 x i1> %pg, i8 %scalar, <vscale x 16 x i8> %vector) #0 {
235 ; OPT-LABEL: @lastb_binop_LHS_splat_sdiv_exact(
236 ; OPT-NEXT: [[TMP1:%.*]] = call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> [[PG:%.*]], <vscale x 16 x i8> [[VECTOR:%.*]])
237 ; OPT-NEXT: [[BINOP1:%.*]] = sdiv exact i8 [[SCALAR:%.*]], [[TMP1]]
238 ; OPT-NEXT: ret i8 [[BINOP1]]
240 %splat_insert = insertelement <vscale x 16 x i8> poison, i8 %scalar, i32 0
241 %splat = shufflevector <vscale x 16 x i8> %splat_insert, <vscale x 16 x i8> poison, <vscale x 16 x i32> zeroinitializer
242 %binop = sdiv exact <vscale x 16 x i8> %splat, %vector
243 %last = tail call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %binop)
247 define float @lastb_binop_LHS_splat_fdiv_float_fast(<vscale x 4 x i1> %pg, float %scalar, <vscale x 4 x float> %vector) #0 {
248 ; OPT-LABEL: @lastb_binop_LHS_splat_fdiv_float_fast(
249 ; OPT-NEXT: [[TMP1:%.*]] = call float @llvm.aarch64.sve.lastb.nxv4f32(<vscale x 4 x i1> [[PG:%.*]], <vscale x 4 x float> [[VECTOR:%.*]])
250 ; OPT-NEXT: [[BINOP1:%.*]] = fdiv fast float [[SCALAR:%.*]], [[TMP1]]
251 ; OPT-NEXT: ret float [[BINOP1]]
253 %splat_insert = insertelement <vscale x 4 x float> poison, float %scalar, i32 0
254 %splat = shufflevector <vscale x 4 x float> %splat_insert, <vscale x 4 x float> poison, <vscale x 4 x i32> zeroinitializer
255 %binop = fdiv fast <vscale x 4 x float> %splat, %vector
256 %last = tail call float @llvm.aarch64.sve.lastb.nxv4f32(<vscale x 4 x i1> %pg, <vscale x 4 x float> %binop)
260 define float @lastb_binop_LHS_splat_fdiv_float(<vscale x 4 x i1> %pg, float %scalar, <vscale x 4 x float> %vector) #0 {
261 ; OPT-LABEL: @lastb_binop_LHS_splat_fdiv_float(
262 ; OPT-NEXT: [[TMP1:%.*]] = call float @llvm.aarch64.sve.lastb.nxv4f32(<vscale x 4 x i1> [[PG:%.*]], <vscale x 4 x float> [[VECTOR:%.*]])
263 ; OPT-NEXT: [[BINOP1:%.*]] = fdiv float [[SCALAR:%.*]], [[TMP1]]
264 ; OPT-NEXT: ret float [[BINOP1]]
266 %splat_insert = insertelement <vscale x 4 x float> poison, float %scalar, i32 0
267 %splat = shufflevector <vscale x 4 x float> %splat_insert, <vscale x 4 x float> poison, <vscale x 4 x i32> zeroinitializer
268 %binop = fdiv <vscale x 4 x float> %splat, %vector
269 %last = tail call float @llvm.aarch64.sve.lastb.nxv4f32(<vscale x 4 x i1> %pg, <vscale x 4 x float> %binop)
273 define i8 @lastb_binop_LHS_RHS_splat_sdiv(<vscale x 16 x i1> %pg, i8 %scalar1, i8 %scalar2) #0 {
274 ; OPT-LABEL: @lastb_binop_LHS_RHS_splat_sdiv(
275 ; OPT-NEXT: [[BINOP1:%.*]] = sdiv i8 [[SCALAR1:%.*]], [[SCALAR2:%.*]]
276 ; OPT-NEXT: ret i8 [[BINOP1]]
278 %splat_insert = insertelement <vscale x 16 x i8> poison, i8 %scalar1, i8 0
279 %splat = shufflevector <vscale x 16 x i8> %splat_insert, <vscale x 16 x i8> poison, <vscale x 16 x i32> zeroinitializer
280 %splat_insert2 = insertelement <vscale x 16 x i8> poison, i8 %scalar2, i8 0
281 %splat2 = shufflevector <vscale x 16 x i8> %splat_insert2, <vscale x 16 x i8> poison, <vscale x 16 x i32> zeroinitializer
282 %binop = sdiv <vscale x 16 x i8> %splat, %splat2
283 %last = tail call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %binop)
287 ; Check that we don't do anything as the binary op has multiple uses.
288 define i8 @lastb_binop_nochange(<vscale x 16 x i1> %pg, i8 %scalar, <vscale x 16 x i8> %vector) #0 {
289 ; OPT-LABEL: @lastb_binop_nochange(
290 ; OPT-NEXT: [[SPLAT_INSERT:%.*]] = insertelement <vscale x 16 x i8> poison, i8 [[SCALAR:%.*]], i32 0
291 ; OPT-NEXT: [[SPLAT:%.*]] = shufflevector <vscale x 16 x i8> [[SPLAT_INSERT]], <vscale x 16 x i8> poison, <vscale x 16 x i32> zeroinitializer
292 ; OPT-NEXT: [[BINOP:%.*]] = sdiv <vscale x 16 x i8> [[VECTOR:%.*]], [[SPLAT]]
293 ; OPT-NEXT: [[LAST:%.*]] = tail call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> [[PG:%.*]], <vscale x 16 x i8> [[BINOP]])
294 ; OPT-NEXT: call void @use(<vscale x 16 x i8> [[BINOP]])
295 ; OPT-NEXT: ret i8 [[LAST]]
297 %splat_insert = insertelement <vscale x 16 x i8> poison, i8 %scalar, i32 0
298 %splat = shufflevector <vscale x 16 x i8> %splat_insert, <vscale x 16 x i8> poison, <vscale x 16 x i32> zeroinitializer
299 %binop = sdiv <vscale x 16 x i8> %vector, %splat
300 %last = tail call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %binop)
301 call void @use(<vscale x 16 x i8> %binop)
305 declare void @use(<vscale x 16 x i8>)
306 declare <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32)
307 declare i8 @llvm.aarch64.sve.lasta.nxv16i8(<vscale x 16 x i1>, <vscale x 16 x i8>)
308 declare i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1>, <vscale x 16 x i8>)
309 declare float @llvm.aarch64.sve.lastb.nxv4f32(<vscale x 4 x i1>, <vscale x 4 x float>)
311 attributes #0 = { "target-features"="+sve" }