270 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py2; RUN: opt < %s -passes=aggressive-instcombine -S | FileCheck %s3target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"4 5; Aggressive Instcombine should be able to reduce width of these expressions.6 7declare i32 @use32(i32)8declare i32 @use64(i64)9declare <2 x i32> @use32_vec(<2 x i32>)10declare <2 x i32> @use64_vec(<2 x i64>)11 12;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;13;; These tests check cases where expression dag post-dominated by TruncInst14;; contains instruction, which has more than one usage.15;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;16 17define void @multi_uses_add(i32 %X) {18; CHECK-LABEL: @multi_uses_add(19; CHECK-NEXT: [[A1:%.*]] = zext i32 [[X:%.*]] to i6420; CHECK-NEXT: [[B1:%.*]] = add i32 [[X]], 1521; CHECK-NEXT: [[C1:%.*]] = mul i32 [[B1]], [[B1]]22; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use32(i32 [[C1]])23; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use64(i64 [[A1]])24; CHECK-NEXT: ret void25;26 %A1 = zext i32 %X to i6427 %B1 = add i64 %A1, 1528 %C1 = mul i64 %B1, %B129 %T1 = trunc i64 %C1 to i3230 call i32 @use32(i32 %T1)31 ; make sure zext have another use that is not post-dominated by the TruncInst.32 call i32 @use64(i64 %A1)33 ret void34}35 36define void @multi_uses_or(i32 %X) {37; CHECK-LABEL: @multi_uses_or(38; CHECK-NEXT: [[A1:%.*]] = zext i32 [[X:%.*]] to i6439; CHECK-NEXT: [[B1:%.*]] = or i32 [[X]], 1540; CHECK-NEXT: [[C1:%.*]] = mul i32 [[B1]], [[B1]]41; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use32(i32 [[C1]])42; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use64(i64 [[A1]])43; CHECK-NEXT: ret void44;45 %A1 = zext i32 %X to i6446 %B1 = or i64 %A1, 1547 %C1 = mul i64 %B1, %B148 %T1 = trunc i64 %C1 to i3249 call i32 @use32(i32 %T1)50 ; make sure zext have another use that is not post-dominated by the TruncInst.51 call i32 @use64(i64 %A1)52 ret void53}54 55define void @multi_uses_xor(i32 %X) {56; CHECK-LABEL: @multi_uses_xor(57; CHECK-NEXT: [[A1:%.*]] = zext i32 [[X:%.*]] to i6458; CHECK-NEXT: [[B1:%.*]] = xor i32 [[X]], 1559; CHECK-NEXT: [[C1:%.*]] = mul i32 [[B1]], [[B1]]60; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use32(i32 [[C1]])61; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use64(i64 [[A1]])62; CHECK-NEXT: ret void63;64 %A1 = zext i32 %X to i6465 %B1 = xor i64 %A1, 1566 %C1 = mul i64 %B1, %B167 %T1 = trunc i64 %C1 to i3268 call i32 @use32(i32 %T1)69 ; make sure zext have another use that is not post-dominated by the TruncInst.70 call i32 @use64(i64 %A1)71 ret void72}73 74define void @multi_uses_and(i32 %X) {75; CHECK-LABEL: @multi_uses_and(76; CHECK-NEXT: [[A1:%.*]] = zext i32 [[X:%.*]] to i6477; CHECK-NEXT: [[B1:%.*]] = and i32 [[X]], 1578; CHECK-NEXT: [[C1:%.*]] = mul i32 [[B1]], [[B1]]79; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use32(i32 [[C1]])80; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use64(i64 [[A1]])81; CHECK-NEXT: ret void82;83 %A1 = zext i32 %X to i6484 %B1 = and i64 %A1, 1585 %C1 = mul i64 %B1, %B186 %T1 = trunc i64 %C1 to i3287 call i32 @use32(i32 %T1)88 ; make sure zext have another use that is not post-dominated by the TruncInst.89 call i32 @use64(i64 %A1)90 ret void91}92 93define void @multi_uses_sub(i32 %X, i32 %Y) {94; CHECK-LABEL: @multi_uses_sub(95; CHECK-NEXT: [[A1:%.*]] = zext i32 [[X:%.*]] to i6496; CHECK-NEXT: [[A2:%.*]] = zext i32 [[Y:%.*]] to i6497; CHECK-NEXT: [[B1:%.*]] = sub i32 [[X]], [[Y]]98; CHECK-NEXT: [[C1:%.*]] = mul i32 [[B1]], [[B1]]99; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use32(i32 [[C1]])100; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use64(i64 [[A1]])101; CHECK-NEXT: [[TMP3:%.*]] = call i32 @use64(i64 [[A2]])102; CHECK-NEXT: ret void103;104 %A1 = zext i32 %X to i64105 %A2 = zext i32 %Y to i64106 %B1 = sub i64 %A1, %A2107 %C1 = mul i64 %B1, %B1108 %T1 = trunc i64 %C1 to i32109 call i32 @use32(i32 %T1)110 ; make sure zext have another use that is not post-dominated by the TruncInst.111 call i32 @use64(i64 %A1)112 call i32 @use64(i64 %A2)113 ret void114}115 116define void @multi_use_vec_add(<2 x i32> %X) {117; CHECK-LABEL: @multi_use_vec_add(118; CHECK-NEXT: [[A1:%.*]] = zext <2 x i32> [[X:%.*]] to <2 x i64>119; CHECK-NEXT: [[B1:%.*]] = add <2 x i32> [[X]], splat (i32 15)120; CHECK-NEXT: [[C1:%.*]] = mul <2 x i32> [[B1]], [[B1]]121; CHECK-NEXT: [[TMP1:%.*]] = call <2 x i32> @use32_vec(<2 x i32> [[C1]])122; CHECK-NEXT: [[TMP2:%.*]] = call <2 x i32> @use64_vec(<2 x i64> [[A1]])123; CHECK-NEXT: ret void124;125 %A1 = zext <2 x i32> %X to <2 x i64>126 %B1 = add <2 x i64> %A1, <i64 15, i64 15>127 %C1 = mul <2 x i64> %B1, %B1128 %T1 = trunc <2 x i64> %C1 to <2 x i32>129 call <2 x i32> @use32_vec(<2 x i32> %T1)130 ; make sure zext have another use that is not post-dominated by the TruncInst.131 call <2 x i32> @use64_vec(<2 x i64> %A1)132 ret void133}134 135define void @multi_use_vec_or(<2 x i32> %X) {136; CHECK-LABEL: @multi_use_vec_or(137; CHECK-NEXT: [[A1:%.*]] = zext <2 x i32> [[X:%.*]] to <2 x i64>138; CHECK-NEXT: [[B1:%.*]] = or <2 x i32> [[X]], splat (i32 15)139; CHECK-NEXT: [[C1:%.*]] = mul <2 x i32> [[B1]], [[B1]]140; CHECK-NEXT: [[TMP1:%.*]] = call <2 x i32> @use32_vec(<2 x i32> [[C1]])141; CHECK-NEXT: [[TMP2:%.*]] = call <2 x i32> @use64_vec(<2 x i64> [[A1]])142; CHECK-NEXT: ret void143;144 %A1 = zext <2 x i32> %X to <2 x i64>145 %B1 = or <2 x i64> %A1, <i64 15, i64 15>146 %C1 = mul <2 x i64> %B1, %B1147 %T1 = trunc <2 x i64> %C1 to <2 x i32>148 call <2 x i32> @use32_vec(<2 x i32> %T1)149 ; make sure zext have another use that is not post-dominated by the TruncInst.150 call <2 x i32> @use64_vec(<2 x i64> %A1)151 ret void152}153 154define void @multi_use_vec_xor(<2 x i32> %X) {155; CHECK-LABEL: @multi_use_vec_xor(156; CHECK-NEXT: [[A1:%.*]] = zext <2 x i32> [[X:%.*]] to <2 x i64>157; CHECK-NEXT: [[B1:%.*]] = xor <2 x i32> [[X]], splat (i32 15)158; CHECK-NEXT: [[C1:%.*]] = mul <2 x i32> [[B1]], [[B1]]159; CHECK-NEXT: [[TMP1:%.*]] = call <2 x i32> @use32_vec(<2 x i32> [[C1]])160; CHECK-NEXT: [[TMP2:%.*]] = call <2 x i32> @use64_vec(<2 x i64> [[A1]])161; CHECK-NEXT: ret void162;163 %A1 = zext <2 x i32> %X to <2 x i64>164 %B1 = xor <2 x i64> %A1, <i64 15, i64 15>165 %C1 = mul <2 x i64> %B1, %B1166 %T1 = trunc <2 x i64> %C1 to <2 x i32>167 call <2 x i32> @use32_vec(<2 x i32> %T1)168 ; make sure zext have another use that is not post-dominated by the TruncInst.169 call <2 x i32> @use64_vec(<2 x i64> %A1)170 ret void171}172 173define void @multi_use_vec_and(<2 x i32> %X) {174; CHECK-LABEL: @multi_use_vec_and(175; CHECK-NEXT: [[A1:%.*]] = zext <2 x i32> [[X:%.*]] to <2 x i64>176; CHECK-NEXT: [[B1:%.*]] = and <2 x i32> [[X]], splat (i32 15)177; CHECK-NEXT: [[C1:%.*]] = mul <2 x i32> [[B1]], [[B1]]178; CHECK-NEXT: [[TMP1:%.*]] = call <2 x i32> @use32_vec(<2 x i32> [[C1]])179; CHECK-NEXT: [[TMP2:%.*]] = call <2 x i32> @use64_vec(<2 x i64> [[A1]])180; CHECK-NEXT: ret void181;182 %A1 = zext <2 x i32> %X to <2 x i64>183 %B1 = and <2 x i64> %A1, <i64 15, i64 15>184 %C1 = mul <2 x i64> %B1, %B1185 %T1 = trunc <2 x i64> %C1 to <2 x i32>186 call <2 x i32> @use32_vec(<2 x i32> %T1)187 ; make sure zext have another use that is not post-dominated by the TruncInst.188 call <2 x i32> @use64_vec(<2 x i64> %A1)189 ret void190}191 192define void @multi_use_vec_sub(<2 x i32> %X, <2 x i32> %Y) {193; CHECK-LABEL: @multi_use_vec_sub(194; CHECK-NEXT: [[A1:%.*]] = zext <2 x i32> [[X:%.*]] to <2 x i64>195; CHECK-NEXT: [[A2:%.*]] = zext <2 x i32> [[Y:%.*]] to <2 x i64>196; CHECK-NEXT: [[B1:%.*]] = sub <2 x i32> [[X]], [[Y]]197; CHECK-NEXT: [[C1:%.*]] = mul <2 x i32> [[B1]], [[B1]]198; CHECK-NEXT: [[TMP1:%.*]] = call <2 x i32> @use32_vec(<2 x i32> [[C1]])199; CHECK-NEXT: [[TMP2:%.*]] = call <2 x i32> @use64_vec(<2 x i64> [[A1]])200; CHECK-NEXT: [[TMP3:%.*]] = call <2 x i32> @use64_vec(<2 x i64> [[A2]])201; CHECK-NEXT: ret void202;203 %A1 = zext <2 x i32> %X to <2 x i64>204 %A2 = zext <2 x i32> %Y to <2 x i64>205 %B1 = sub <2 x i64> %A1, %A2206 %C1 = mul <2 x i64> %B1, %B1207 %T1 = trunc <2 x i64> %C1 to <2 x i32>208 call <2 x i32> @use32_vec(<2 x i32> %T1)209 ; make sure zext have another use that is not post-dominated by the TruncInst.210 call <2 x i32> @use64_vec(<2 x i64> %A1)211 call <2 x i32> @use64_vec(<2 x i64> %A2)212 ret void213}214 215;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;216;; These tests check cases where expression dag post-dominated by TruncInst217;; contains TruncInst leaf or ZEXT/SEXT leafs which turn into TruncInst leaves.218;; Check that both expressions are reduced and no TruncInst remains or (was219;; generated).220;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;221 222; Notice that there are two expression patterns below:223; 1. %T2->%C2->(%B2->(%T1, 15), %B2->(%T1, 15))224; 2. %T1`->%C1->(%B1->(%A1, 15), %B1->(%A1, 15))225; (where %T1` is the reduced node of %T1 into trunc instruction)226define void @trunc_as_a_leaf(i32 %X) {227; CHECK-LABEL: @trunc_as_a_leaf(228; CHECK-NEXT: [[B1:%.*]] = add i32 [[X:%.*]], 15229; CHECK-NEXT: [[C1:%.*]] = mul i32 [[B1]], [[B1]]230; CHECK-NEXT: [[B2:%.*]] = add i32 [[C1]], 15231; CHECK-NEXT: [[C2:%.*]] = mul i32 [[B2]], [[B2]]232; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use32(i32 [[C2]])233; CHECK-NEXT: ret void234;235 %A1 = zext i32 %X to i64236 %B1 = add i64 %A1, 15237 %C1 = mul i64 %B1, %B1238 %T1 = trunc i64 %C1 to i48 ; leaf trunc239 %B2 = add i48 %T1, 15240 %C2 = mul i48 %B2, %B2241 %T2 = trunc i48 %C2 to i32242 call i32 @use32(i32 %T2)243 ret void244}245 246; Notice that there are two expression patterns below:247; 1. %T2->%C2->(%B2->(%T1, 15), %B2->(%T1, 15))248; 2. %T1`->%C1->(%B1->(%A1, 15), %B1->(%A1, 15))249; (where %T1` is the reduced node of %T1 into trunc instruction)250define void @zext_as_a_leaf(i16 %X) {251; CHECK-LABEL: @zext_as_a_leaf(252; CHECK-NEXT: [[A1:%.*]] = zext i16 [[X:%.*]] to i32253; CHECK-NEXT: [[B1:%.*]] = add i32 [[A1]], 15254; CHECK-NEXT: [[C1:%.*]] = mul i32 [[B1]], [[B1]]255; CHECK-NEXT: [[B2:%.*]] = add i32 [[C1]], 15256; CHECK-NEXT: [[C2:%.*]] = mul i32 [[B2]], [[B2]]257; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use32(i32 [[C2]])258; CHECK-NEXT: ret void259;260 %A1 = zext i16 %X to i48261 %B1 = add i48 %A1, 15262 %C1 = mul i48 %B1, %B1263 %T1 = zext i48 %C1 to i64 ; leaf zext, which will turn into trunc264 %B2 = add i64 %T1, 15265 %C2 = mul i64 %B2, %B2266 %T2 = trunc i64 %C2 to i32267 call i32 @use32(i32 %T2)268 ret void269}270