444 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py2; RUN: opt -passes=instcombine -S -mtriple=arm -o - %s | FileCheck %s3 4target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"5 6declare i32 @llvm.arm.mve.pred.v2i.v2i1(<2 x i1>)7declare i32 @llvm.arm.mve.pred.v2i.v4i1(<4 x i1>)8declare i32 @llvm.arm.mve.pred.v2i.v8i1(<8 x i1>)9declare i32 @llvm.arm.mve.pred.v2i.v16i1(<16 x i1>)10 11declare <2 x i1> @llvm.arm.mve.pred.i2v.v2i1(i32)12declare <4 x i1> @llvm.arm.mve.pred.i2v.v4i1(i32)13declare <8 x i1> @llvm.arm.mve.pred.i2v.v8i1(i32)14declare <16 x i1> @llvm.arm.mve.pred.i2v.v16i1(i32)15 16; Round-trip conversions from predicate vector to i32 back to the same17; size of vector should be eliminated.18 19define <2 x i1> @v2i2v_2(<2 x i1> %vin) {20; CHECK-LABEL: @v2i2v_2(21; CHECK-NEXT: entry:22; CHECK-NEXT: ret <2 x i1> [[VIN:%.*]]23;24entry:25 %int = call i32 @llvm.arm.mve.pred.v2i.v2i1(<2 x i1> %vin)26 %vout = call <2 x i1> @llvm.arm.mve.pred.i2v.v2i1(i32 %int)27 ret <2 x i1> %vout28}29 30define <4 x i1> @v2i2v_4(<4 x i1> %vin) {31; CHECK-LABEL: @v2i2v_4(32; CHECK-NEXT: entry:33; CHECK-NEXT: ret <4 x i1> [[VIN:%.*]]34;35entry:36 %int = call i32 @llvm.arm.mve.pred.v2i.v4i1(<4 x i1> %vin)37 %vout = call <4 x i1> @llvm.arm.mve.pred.i2v.v4i1(i32 %int)38 ret <4 x i1> %vout39}40 41define <8 x i1> @v2i2v_8(<8 x i1> %vin) {42; CHECK-LABEL: @v2i2v_8(43; CHECK-NEXT: entry:44; CHECK-NEXT: ret <8 x i1> [[VIN:%.*]]45;46entry:47 %int = call i32 @llvm.arm.mve.pred.v2i.v8i1(<8 x i1> %vin)48 %vout = call <8 x i1> @llvm.arm.mve.pred.i2v.v8i1(i32 %int)49 ret <8 x i1> %vout50}51 52define <16 x i1> @v2i2v_16(<16 x i1> %vin) {53; CHECK-LABEL: @v2i2v_16(54; CHECK-NEXT: entry:55; CHECK-NEXT: ret <16 x i1> [[VIN:%.*]]56;57entry:58 %int = call i32 @llvm.arm.mve.pred.v2i.v16i1(<16 x i1> %vin)59 %vout = call <16 x i1> @llvm.arm.mve.pred.i2v.v16i1(i32 %int)60 ret <16 x i1> %vout61}62 63; Conversions from a predicate vector to i32 and then to a _different_64; size of predicate vector should be left alone.65 66define <16 x i1> @v2i2v_2_16(<2 x i1> %vin) {67; CHECK-LABEL: @v2i2v_2_16(68; CHECK-NEXT: entry:69; CHECK-NEXT: [[INT:%.*]] = call noundef range(i32 0, 65536) i32 @llvm.arm.mve.pred.v2i.v2i1(<2 x i1> [[VIN:%.*]])70; CHECK-NEXT: [[VOUT:%.*]] = call <16 x i1> @llvm.arm.mve.pred.i2v.v16i1(i32 [[INT]])71; CHECK-NEXT: ret <16 x i1> [[VOUT]]72;73entry:74 %int = call i32 @llvm.arm.mve.pred.v2i.v2i1(<2 x i1> %vin)75 %vout = call <16 x i1> @llvm.arm.mve.pred.i2v.v16i1(i32 %int)76 ret <16 x i1> %vout77}78 79define <16 x i1> @v2i2v_4_16(<4 x i1> %vin) {80; CHECK-LABEL: @v2i2v_4_16(81; CHECK-NEXT: entry:82; CHECK-NEXT: [[INT:%.*]] = call noundef range(i32 0, 65536) i32 @llvm.arm.mve.pred.v2i.v4i1(<4 x i1> [[VIN:%.*]])83; CHECK-NEXT: [[VOUT:%.*]] = call <16 x i1> @llvm.arm.mve.pred.i2v.v16i1(i32 [[INT]])84; CHECK-NEXT: ret <16 x i1> [[VOUT]]85;86entry:87 %int = call i32 @llvm.arm.mve.pred.v2i.v4i1(<4 x i1> %vin)88 %vout = call <16 x i1> @llvm.arm.mve.pred.i2v.v16i1(i32 %int)89 ret <16 x i1> %vout90}91 92define <4 x i1> @v2i2v_8_4(<8 x i1> %vin) {93; CHECK-LABEL: @v2i2v_8_4(94; CHECK-NEXT: entry:95; CHECK-NEXT: [[INT:%.*]] = call noundef range(i32 0, 65536) i32 @llvm.arm.mve.pred.v2i.v8i1(<8 x i1> [[VIN:%.*]])96; CHECK-NEXT: [[VOUT:%.*]] = call <4 x i1> @llvm.arm.mve.pred.i2v.v4i1(i32 [[INT]])97; CHECK-NEXT: ret <4 x i1> [[VOUT]]98;99entry:100 %int = call i32 @llvm.arm.mve.pred.v2i.v8i1(<8 x i1> %vin)101 %vout = call <4 x i1> @llvm.arm.mve.pred.i2v.v4i1(i32 %int)102 ret <4 x i1> %vout103}104 105define <8 x i1> @v2i2v_16_8(<16 x i1> %vin) {106; CHECK-LABEL: @v2i2v_16_8(107; CHECK-NEXT: entry:108; CHECK-NEXT: [[INT:%.*]] = call noundef range(i32 0, 65536) i32 @llvm.arm.mve.pred.v2i.v16i1(<16 x i1> [[VIN:%.*]])109; CHECK-NEXT: [[VOUT:%.*]] = call <8 x i1> @llvm.arm.mve.pred.i2v.v8i1(i32 [[INT]])110; CHECK-NEXT: ret <8 x i1> [[VOUT]]111;112entry:113 %int = call i32 @llvm.arm.mve.pred.v2i.v16i1(<16 x i1> %vin)114 %vout = call <8 x i1> @llvm.arm.mve.pred.i2v.v8i1(i32 %int)115 ret <8 x i1> %vout116}117 118; Round-trip conversions from i32 to predicate vector back to i32119; should be eliminated.120 121define i32 @i2v2i_2(i32 %iin) {122; CHECK-LABEL: @i2v2i_2(123; CHECK-NEXT: entry:124; CHECK-NEXT: ret i32 [[IIN:%.*]]125;126entry:127 %vec = call <2 x i1> @llvm.arm.mve.pred.i2v.v2i1(i32 %iin)128 %iout = call i32 @llvm.arm.mve.pred.v2i.v2i1(<2 x i1> %vec)129 ret i32 %iout130}131 132define i32 @i2v2i_4(i32 %iin) {133; CHECK-LABEL: @i2v2i_4(134; CHECK-NEXT: entry:135; CHECK-NEXT: ret i32 [[IIN:%.*]]136;137entry:138 %vec = call <4 x i1> @llvm.arm.mve.pred.i2v.v4i1(i32 %iin)139 %iout = call i32 @llvm.arm.mve.pred.v2i.v4i1(<4 x i1> %vec)140 ret i32 %iout141}142 143define i32 @i2v2i_8(i32 %iin) {144; CHECK-LABEL: @i2v2i_8(145; CHECK-NEXT: entry:146; CHECK-NEXT: ret i32 [[IIN:%.*]]147;148entry:149 %vec = call <8 x i1> @llvm.arm.mve.pred.i2v.v8i1(i32 %iin)150 %iout = call i32 @llvm.arm.mve.pred.v2i.v8i1(<8 x i1> %vec)151 ret i32 %iout152}153 154define i32 @i2v2i_16(i32 %iin) {155; CHECK-LABEL: @i2v2i_16(156; CHECK-NEXT: entry:157; CHECK-NEXT: ret i32 [[IIN:%.*]]158;159entry:160 %vec = call <16 x i1> @llvm.arm.mve.pred.i2v.v16i1(i32 %iin)161 %iout = call i32 @llvm.arm.mve.pred.v2i.v16i1(<16 x i1> %vec)162 ret i32 %iout163}164 165; v2i leaves the top 16 bits clear. So a trunc/zext pair applied to166; its output, going via i16, can be completely eliminated - but not167; one going via i8. Similarly with other methods of clearing the top168; bits, like bitwise and.169 170define i32 @v2i_truncext_i16(<4 x i1> %vin) {171; CHECK-LABEL: @v2i_truncext_i16(172; CHECK-NEXT: entry:173; CHECK-NEXT: [[WIDE1:%.*]] = call noundef range(i32 0, 65536) i32 @llvm.arm.mve.pred.v2i.v4i1(<4 x i1> [[VIN:%.*]])174; CHECK-NEXT: ret i32 [[WIDE1]]175;176entry:177 %wide1 = call i32 @llvm.arm.mve.pred.v2i.v4i1(<4 x i1> %vin)178 %narrow = trunc i32 %wide1 to i16179 %wide2 = zext i16 %narrow to i32180 ret i32 %wide2181}182 183define i32 @v2i_truncext_i8(<4 x i1> %vin) {184; CHECK-LABEL: @v2i_truncext_i8(185; CHECK-NEXT: entry:186; CHECK-NEXT: [[WIDE1:%.*]] = call noundef range(i32 0, 65536) i32 @llvm.arm.mve.pred.v2i.v4i1(<4 x i1> [[VIN:%.*]])187; CHECK-NEXT: [[WIDE2:%.*]] = and i32 [[WIDE1]], 255188; CHECK-NEXT: ret i32 [[WIDE2]]189;190entry:191 %wide1 = call i32 @llvm.arm.mve.pred.v2i.v4i1(<4 x i1> %vin)192 %narrow = trunc i32 %wide1 to i8193 %wide2 = zext i8 %narrow to i32194 ret i32 %wide2195}196 197define i32 @v2i_and_16(<4 x i1> %vin) {198; CHECK-LABEL: @v2i_and_16(199; CHECK-NEXT: entry:200; CHECK-NEXT: [[WIDE1:%.*]] = call noundef range(i32 0, 65536) i32 @llvm.arm.mve.pred.v2i.v4i1(<4 x i1> [[VIN:%.*]])201; CHECK-NEXT: ret i32 [[WIDE1]]202;203entry:204 %wide1 = call i32 @llvm.arm.mve.pred.v2i.v4i1(<4 x i1> %vin)205 %wide2 = and i32 %wide1, 65535206 ret i32 %wide2207}208 209define i32 @v2i_and_15(<4 x i1> %vin) {210; CHECK-LABEL: @v2i_and_15(211; CHECK-NEXT: entry:212; CHECK-NEXT: [[WIDE1:%.*]] = call noundef range(i32 0, 65536) i32 @llvm.arm.mve.pred.v2i.v4i1(<4 x i1> [[VIN:%.*]])213; CHECK-NEXT: [[WIDE2:%.*]] = and i32 [[WIDE1]], 32767214; CHECK-NEXT: ret i32 [[WIDE2]]215;216entry:217 %wide1 = call i32 @llvm.arm.mve.pred.v2i.v4i1(<4 x i1> %vin)218 %wide2 = and i32 %wide1, 32767219 ret i32 %wide2220}221 222; i2v doesn't use the top bits of its input. So the same operations223; on a value that's about to be passed to i2v can be eliminated.224 225define <4 x i1> @i2v_truncext_i16(i32 %wide1) {226; CHECK-LABEL: @i2v_truncext_i16(227; CHECK-NEXT: entry:228; CHECK-NEXT: [[VOUT:%.*]] = call <4 x i1> @llvm.arm.mve.pred.i2v.v4i1(i32 [[WIDE1:%.*]])229; CHECK-NEXT: ret <4 x i1> [[VOUT]]230;231entry:232 %narrow = trunc i32 %wide1 to i16233 %wide2 = zext i16 %narrow to i32234 %vout = call <4 x i1> @llvm.arm.mve.pred.i2v.v4i1(i32 %wide2)235 ret <4 x i1> %vout236}237 238define <4 x i1> @i2v_truncext_i8(i32 %wide1) {239; CHECK-LABEL: @i2v_truncext_i8(240; CHECK-NEXT: entry:241; CHECK-NEXT: [[WIDE2:%.*]] = and i32 [[WIDE1:%.*]], 255242; CHECK-NEXT: [[VOUT:%.*]] = call <4 x i1> @llvm.arm.mve.pred.i2v.v4i1(i32 [[WIDE2]])243; CHECK-NEXT: ret <4 x i1> [[VOUT]]244;245entry:246 %narrow = trunc i32 %wide1 to i8247 %wide2 = zext i8 %narrow to i32248 %vout = call <4 x i1> @llvm.arm.mve.pred.i2v.v4i1(i32 %wide2)249 ret <4 x i1> %vout250}251 252define <4 x i1> @i2v_and_16(i32 %wide1) {253; CHECK-LABEL: @i2v_and_16(254; CHECK-NEXT: entry:255; CHECK-NEXT: [[VOUT:%.*]] = call <4 x i1> @llvm.arm.mve.pred.i2v.v4i1(i32 [[WIDE1:%.*]])256; CHECK-NEXT: ret <4 x i1> [[VOUT]]257;258entry:259 %wide2 = and i32 %wide1, 65535260 %vout = call <4 x i1> @llvm.arm.mve.pred.i2v.v4i1(i32 %wide2)261 ret <4 x i1> %vout262}263 264define <4 x i1> @i2v_and_15(i32 %wide1) {265; CHECK-LABEL: @i2v_and_15(266; CHECK-NEXT: entry:267; CHECK-NEXT: [[WIDE2:%.*]] = and i32 [[WIDE1:%.*]], 32767268; CHECK-NEXT: [[VOUT:%.*]] = call <4 x i1> @llvm.arm.mve.pred.i2v.v4i1(i32 [[WIDE2]])269; CHECK-NEXT: ret <4 x i1> [[VOUT]]270;271entry:272 %wide2 = and i32 %wide1, 32767273 %vout = call <4 x i1> @llvm.arm.mve.pred.i2v.v4i1(i32 %wide2)274 ret <4 x i1> %vout275}276 277; If a predicate vector is round-tripped to an integer and back, and278; complemented while it's in integer form, we should collapse that to279; a complement of the vector itself. (Rationale: this is likely to280; allow it to be code-generated as MVE VPNOT.)281 282define <2 x i1> @vpnot_2(<2 x i1> %vin) {283; CHECK-LABEL: @vpnot_2(284; CHECK-NEXT: entry:285; CHECK-NEXT: [[VOUT:%.*]] = xor <2 x i1> [[VIN:%.*]], splat (i1 true)286; CHECK-NEXT: ret <2 x i1> [[VOUT]]287;288entry:289 %int = call i32 @llvm.arm.mve.pred.v2i.v2i1(<2 x i1> %vin)290 %flipped = xor i32 %int, 65535291 %vout = call <2 x i1> @llvm.arm.mve.pred.i2v.v2i1(i32 %flipped)292 ret <2 x i1> %vout293}294 295define <4 x i1> @vpnot_4(<4 x i1> %vin) {296; CHECK-LABEL: @vpnot_4(297; CHECK-NEXT: entry:298; CHECK-NEXT: [[VOUT:%.*]] = xor <4 x i1> [[VIN:%.*]], splat (i1 true)299; CHECK-NEXT: ret <4 x i1> [[VOUT]]300;301entry:302 %int = call i32 @llvm.arm.mve.pred.v2i.v4i1(<4 x i1> %vin)303 %flipped = xor i32 %int, 65535304 %vout = call <4 x i1> @llvm.arm.mve.pred.i2v.v4i1(i32 %flipped)305 ret <4 x i1> %vout306}307 308define <8 x i1> @vpnot_8(<8 x i1> %vin) {309; CHECK-LABEL: @vpnot_8(310; CHECK-NEXT: entry:311; CHECK-NEXT: [[VOUT:%.*]] = xor <8 x i1> [[VIN:%.*]], splat (i1 true)312; CHECK-NEXT: ret <8 x i1> [[VOUT]]313;314entry:315 %int = call i32 @llvm.arm.mve.pred.v2i.v8i1(<8 x i1> %vin)316 %flipped = xor i32 %int, 65535317 %vout = call <8 x i1> @llvm.arm.mve.pred.i2v.v8i1(i32 %flipped)318 ret <8 x i1> %vout319}320 321define <16 x i1> @vpnot_16(<16 x i1> %vin) {322; CHECK-LABEL: @vpnot_16(323; CHECK-NEXT: entry:324; CHECK-NEXT: [[VOUT:%.*]] = xor <16 x i1> [[VIN:%.*]], splat (i1 true)325; CHECK-NEXT: ret <16 x i1> [[VOUT]]326;327entry:328 %int = call i32 @llvm.arm.mve.pred.v2i.v16i1(<16 x i1> %vin)329 %flipped = xor i32 %int, 65535330 %vout = call <16 x i1> @llvm.arm.mve.pred.i2v.v16i1(i32 %flipped)331 ret <16 x i1> %vout332}333 334; And this still works even if the i32 is narrowed to i16 and back on335; opposite sides of the xor.336 337define <2 x i1> @vpnot_narrow_2(<2 x i1> %vin) {338; CHECK-LABEL: @vpnot_narrow_2(339; CHECK-NEXT: entry:340; CHECK-NEXT: [[VOUT:%.*]] = xor <2 x i1> [[VIN:%.*]], splat (i1 true)341; CHECK-NEXT: ret <2 x i1> [[VOUT]]342;343entry:344 %int = call i32 @llvm.arm.mve.pred.v2i.v2i1(<2 x i1> %vin)345 %narrow = trunc i32 %int to i16346 %flipped_narrow = xor i16 %narrow, -1347 %flipped = zext i16 %flipped_narrow to i32348 %vout = call <2 x i1> @llvm.arm.mve.pred.i2v.v2i1(i32 %flipped)349 ret <2 x i1> %vout350}351 352define <4 x i1> @vpnot_narrow_4(<4 x i1> %vin) {353; CHECK-LABEL: @vpnot_narrow_4(354; CHECK-NEXT: entry:355; CHECK-NEXT: [[VOUT:%.*]] = xor <4 x i1> [[VIN:%.*]], splat (i1 true)356; CHECK-NEXT: ret <4 x i1> [[VOUT]]357;358entry:359 %int = call i32 @llvm.arm.mve.pred.v2i.v4i1(<4 x i1> %vin)360 %narrow = trunc i32 %int to i16361 %flipped_narrow = xor i16 %narrow, -1362 %flipped = zext i16 %flipped_narrow to i32363 %vout = call <4 x i1> @llvm.arm.mve.pred.i2v.v4i1(i32 %flipped)364 ret <4 x i1> %vout365}366 367define <8 x i1> @vpnot_narrow_8(<8 x i1> %vin) {368; CHECK-LABEL: @vpnot_narrow_8(369; CHECK-NEXT: entry:370; CHECK-NEXT: [[VOUT:%.*]] = xor <8 x i1> [[VIN:%.*]], splat (i1 true)371; CHECK-NEXT: ret <8 x i1> [[VOUT]]372;373entry:374 %int = call i32 @llvm.arm.mve.pred.v2i.v8i1(<8 x i1> %vin)375 %narrow = trunc i32 %int to i16376 %flipped_narrow = xor i16 %narrow, -1377 %flipped = zext i16 %flipped_narrow to i32378 %vout = call <8 x i1> @llvm.arm.mve.pred.i2v.v8i1(i32 %flipped)379 ret <8 x i1> %vout380}381 382define <16 x i1> @vpnot_narrow_16(<16 x i1> %vin) {383; CHECK-LABEL: @vpnot_narrow_16(384; CHECK-NEXT: entry:385; CHECK-NEXT: [[VOUT:%.*]] = xor <16 x i1> [[VIN:%.*]], splat (i1 true)386; CHECK-NEXT: ret <16 x i1> [[VOUT]]387;388entry:389 %int = call i32 @llvm.arm.mve.pred.v2i.v16i1(<16 x i1> %vin)390 %narrow = trunc i32 %int to i16391 %flipped_narrow = xor i16 %narrow, -1392 %flipped = zext i16 %flipped_narrow to i32393 %vout = call <16 x i1> @llvm.arm.mve.pred.i2v.v16i1(i32 %flipped)394 ret <16 x i1> %vout395}396 397define i32 @range_upper_limit(<16 x i1> %vin) {398; CHECK-LABEL: @range_upper_limit(399; CHECK-NEXT: entry:400; CHECK-NEXT: [[INT:%.*]] = call noundef range(i32 0, 65536) i32 @llvm.arm.mve.pred.v2i.v16i1(<16 x i1> [[VIN:%.*]])401; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[INT]], 65535402; CHECK-NEXT: [[S:%.*]] = zext i1 [[C]] to i32403; CHECK-NEXT: ret i32 [[S]]404;405entry:406 %int = call i32 @llvm.arm.mve.pred.v2i.v16i1(<16 x i1> %vin)407 %c = icmp eq i32 %int, 65535408 %s = select i1 %c, i32 1, i32 0409 ret i32 %s410}411 412define i32 @range_already_added_larger_range(<16 x i1> %vin) {413; CHECK-LABEL: @range_already_added_larger_range(414; CHECK-NEXT: entry:415; CHECK-NEXT: [[INT:%.*]] = call noundef range(i32 0, 65536) i32 @llvm.arm.mve.pred.v2i.v16i1(<16 x i1> [[VIN:%.*]])416; CHECK-NEXT: ret i32 [[INT]]417;418entry:419 %int = call noundef range(i32 0, 65540) i32 @llvm.arm.mve.pred.v2i.v16i1(<16 x i1> %vin)420 ret i32 %int421}422 423define i32 @range_already_added_smaller_range(<16 x i1> %vin) {424; CHECK-LABEL: @range_already_added_smaller_range(425; CHECK-NEXT: entry:426; CHECK-NEXT: [[INT:%.*]] = call noundef range(i32 0, 655) i32 @llvm.arm.mve.pred.v2i.v16i1(<16 x i1> [[VIN:%.*]])427; CHECK-NEXT: ret i32 [[INT]]428;429entry:430 %int = call noundef range(i32 0, 655) i32 @llvm.arm.mve.pred.v2i.v16i1(<16 x i1> %vin)431 ret i32 %int432}433 434define i32 @range_already_added_same_range(<16 x i1> %vin) {435; CHECK-LABEL: @range_already_added_same_range(436; CHECK-NEXT: entry:437; CHECK-NEXT: [[INT:%.*]] = call noundef range(i32 0, 65536) i32 @llvm.arm.mve.pred.v2i.v16i1(<16 x i1> [[VIN:%.*]])438; CHECK-NEXT: ret i32 [[INT]]439;440entry:441 %int = call noundef range(i32 0, 65536) i32 @llvm.arm.mve.pred.v2i.v16i1(<16 x i1> %vin)442 ret i32 %int443}444