1; RUN: opt < %s -instcombine -S | FileCheck %s 2 3define i16 @narrow_sext_and(i16 %x16, i32 %y32) { 4; CHECK-LABEL: @narrow_sext_and( 5; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 %y32 to i16 6; CHECK-NEXT: [[R:%.*]] = and i16 [[TMP1]], %x16 7; CHECK-NEXT: ret i16 [[R]] 8; 9 %x32 = sext i16 %x16 to i32 10 %b = and i32 %x32, %y32 11 %r = trunc i32 %b to i16 12 ret i16 %r 13} 14 15define i16 @narrow_zext_and(i16 %x16, i32 %y32) { 16; CHECK-LABEL: @narrow_zext_and( 17; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 %y32 to i16 18; CHECK-NEXT: [[R:%.*]] = and i16 [[TMP1]], %x16 19; CHECK-NEXT: ret i16 [[R]] 20; 21 %x32 = zext i16 %x16 to i32 22 %b = and i32 %x32, %y32 23 %r = trunc i32 %b to i16 24 ret i16 %r 25} 26 27define i16 @narrow_sext_or(i16 %x16, i32 %y32) { 28; CHECK-LABEL: @narrow_sext_or( 29; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 %y32 to i16 30; CHECK-NEXT: [[R:%.*]] = or i16 [[TMP1]], %x16 31; CHECK-NEXT: ret i16 [[R]] 32; 33 %x32 = sext i16 %x16 to i32 34 %b = or i32 %x32, %y32 35 %r = trunc i32 %b to i16 36 ret i16 %r 37} 38 39define i16 @narrow_zext_or(i16 %x16, i32 %y32) { 40; CHECK-LABEL: @narrow_zext_or( 41; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 %y32 to i16 42; CHECK-NEXT: [[R:%.*]] = or i16 [[TMP1]], %x16 43; CHECK-NEXT: ret i16 [[R]] 44; 45 %x32 = zext i16 %x16 to i32 46 %b = or i32 %x32, %y32 47 %r = trunc i32 %b to i16 48 ret i16 %r 49} 50 51define i16 @narrow_sext_xor(i16 %x16, i32 %y32) { 52; CHECK-LABEL: @narrow_sext_xor( 53; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 %y32 to i16 54; CHECK-NEXT: [[R:%.*]] = xor i16 [[TMP1]], %x16 55; CHECK-NEXT: ret i16 [[R]] 56; 57 %x32 = sext i16 %x16 to i32 58 %b = xor i32 %x32, %y32 59 %r = trunc i32 %b to i16 60 ret i16 %r 61} 62 63define i16 @narrow_zext_xor(i16 %x16, i32 %y32) { 64; CHECK-LABEL: @narrow_zext_xor( 65; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 %y32 to i16 66; CHECK-NEXT: [[R:%.*]] = xor i16 [[TMP1]], %x16 67; CHECK-NEXT: ret i16 [[R]] 68; 69 %x32 = zext i16 %x16 to i32 70 %b = xor i32 %x32, %y32 71 %r = trunc i32 %b to i16 72 ret i16 %r 73} 74 75define i16 @narrow_sext_add(i16 %x16, i32 %y32) { 76; CHECK-LABEL: @narrow_sext_add( 77; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 %y32 to i16 78; CHECK-NEXT: [[R:%.*]] = add i16 [[TMP1]], %x16 79; CHECK-NEXT: ret i16 [[R]] 80; 81 %x32 = sext i16 %x16 to i32 82 %b = add i32 %x32, %y32 83 %r = trunc i32 %b to i16 84 ret i16 %r 85} 86 87define i16 @narrow_zext_add(i16 %x16, i32 %y32) { 88; CHECK-LABEL: @narrow_zext_add( 89; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 %y32 to i16 90; CHECK-NEXT: [[R:%.*]] = add i16 [[TMP1]], %x16 91; CHECK-NEXT: ret i16 [[R]] 92; 93 %x32 = zext i16 %x16 to i32 94 %b = add i32 %x32, %y32 95 %r = trunc i32 %b to i16 96 ret i16 %r 97} 98 99define i16 @narrow_sext_sub(i16 %x16, i32 %y32) { 100; CHECK-LABEL: @narrow_sext_sub( 101; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 %y32 to i16 102; CHECK-NEXT: [[R:%.*]] = sub i16 %x16, [[TMP1]] 103; CHECK-NEXT: ret i16 [[R]] 104; 105 %x32 = sext i16 %x16 to i32 106 %b = sub i32 %x32, %y32 107 %r = trunc i32 %b to i16 108 ret i16 %r 109} 110 111define i16 @narrow_zext_sub(i16 %x16, i32 %y32) { 112; CHECK-LABEL: @narrow_zext_sub( 113; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 %y32 to i16 114; CHECK-NEXT: [[R:%.*]] = sub i16 %x16, [[TMP1]] 115; CHECK-NEXT: ret i16 [[R]] 116; 117 %x32 = zext i16 %x16 to i32 118 %b = sub i32 %x32, %y32 119 %r = trunc i32 %b to i16 120 ret i16 %r 121} 122 123define i16 @narrow_sext_mul(i16 %x16, i32 %y32) { 124; CHECK-LABEL: @narrow_sext_mul( 125; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 %y32 to i16 126; CHECK-NEXT: [[R:%.*]] = mul i16 [[TMP1]], %x16 127; CHECK-NEXT: ret i16 [[R]] 128; 129 %x32 = sext i16 %x16 to i32 130 %b = mul i32 %x32, %y32 131 %r = trunc i32 %b to i16 132 ret i16 %r 133} 134 135define i16 @narrow_zext_mul(i16 %x16, i32 %y32) { 136; CHECK-LABEL: @narrow_zext_mul( 137; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 %y32 to i16 138; CHECK-NEXT: [[R:%.*]] = mul i16 [[TMP1]], %x16 139; CHECK-NEXT: ret i16 [[R]] 140; 141 %x32 = zext i16 %x16 to i32 142 %b = mul i32 %x32, %y32 143 %r = trunc i32 %b to i16 144 ret i16 %r 145} 146 147; Verify that the commuted patterns work. The div is to ensure that complexity-based 148; canonicalization doesn't swap the binop operands. Use vector types to show those work too. 149 150define <2 x i16> @narrow_sext_and_commute(<2 x i16> %x16, <2 x i32> %y32) { 151; CHECK-LABEL: @narrow_sext_and_commute( 152; CHECK-NEXT: [[Y32OP0:%.*]] = sdiv <2 x i32> %y32, <i32 7, i32 -17> 153; CHECK-NEXT: [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16> 154; CHECK-NEXT: [[R:%.*]] = and <2 x i16> [[TMP1]], %x16 155; CHECK-NEXT: ret <2 x i16> [[R]] 156; 157 %y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17> 158 %x32 = sext <2 x i16> %x16 to <2 x i32> 159 %b = and <2 x i32> %y32op0, %x32 160 %r = trunc <2 x i32> %b to <2 x i16> 161 ret <2 x i16> %r 162} 163 164define <2 x i16> @narrow_zext_and_commute(<2 x i16> %x16, <2 x i32> %y32) { 165; CHECK-LABEL: @narrow_zext_and_commute( 166; CHECK-NEXT: [[Y32OP0:%.*]] = sdiv <2 x i32> %y32, <i32 7, i32 -17> 167; CHECK-NEXT: [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16> 168; CHECK-NEXT: [[R:%.*]] = and <2 x i16> [[TMP1]], %x16 169; CHECK-NEXT: ret <2 x i16> [[R]] 170; 171 %y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17> 172 %x32 = zext <2 x i16> %x16 to <2 x i32> 173 %b = and <2 x i32> %y32op0, %x32 174 %r = trunc <2 x i32> %b to <2 x i16> 175 ret <2 x i16> %r 176} 177 178define <2 x i16> @narrow_sext_or_commute(<2 x i16> %x16, <2 x i32> %y32) { 179; CHECK-LABEL: @narrow_sext_or_commute( 180; CHECK-NEXT: [[Y32OP0:%.*]] = sdiv <2 x i32> %y32, <i32 7, i32 -17> 181; CHECK-NEXT: [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16> 182; CHECK-NEXT: [[R:%.*]] = or <2 x i16> [[TMP1]], %x16 183; CHECK-NEXT: ret <2 x i16> [[R]] 184; 185 %y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17> 186 %x32 = sext <2 x i16> %x16 to <2 x i32> 187 %b = or <2 x i32> %y32op0, %x32 188 %r = trunc <2 x i32> %b to <2 x i16> 189 ret <2 x i16> %r 190} 191 192define <2 x i16> @narrow_zext_or_commute(<2 x i16> %x16, <2 x i32> %y32) { 193; CHECK-LABEL: @narrow_zext_or_commute( 194; CHECK-NEXT: [[Y32OP0:%.*]] = sdiv <2 x i32> %y32, <i32 7, i32 -17> 195; CHECK-NEXT: [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16> 196; CHECK-NEXT: [[R:%.*]] = or <2 x i16> [[TMP1]], %x16 197; CHECK-NEXT: ret <2 x i16> [[R]] 198; 199 %y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17> 200 %x32 = zext <2 x i16> %x16 to <2 x i32> 201 %b = or <2 x i32> %y32op0, %x32 202 %r = trunc <2 x i32> %b to <2 x i16> 203 ret <2 x i16> %r 204} 205 206define <2 x i16> @narrow_sext_xor_commute(<2 x i16> %x16, <2 x i32> %y32) { 207; CHECK-LABEL: @narrow_sext_xor_commute( 208; CHECK-NEXT: [[Y32OP0:%.*]] = sdiv <2 x i32> %y32, <i32 7, i32 -17> 209; CHECK-NEXT: [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16> 210; CHECK-NEXT: [[R:%.*]] = xor <2 x i16> [[TMP1]], %x16 211; CHECK-NEXT: ret <2 x i16> [[R]] 212; 213 %y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17> 214 %x32 = sext <2 x i16> %x16 to <2 x i32> 215 %b = xor <2 x i32> %y32op0, %x32 216 %r = trunc <2 x i32> %b to <2 x i16> 217 ret <2 x i16> %r 218} 219 220define <2 x i16> @narrow_zext_xor_commute(<2 x i16> %x16, <2 x i32> %y32) { 221; CHECK-LABEL: @narrow_zext_xor_commute( 222; CHECK-NEXT: [[Y32OP0:%.*]] = sdiv <2 x i32> %y32, <i32 7, i32 -17> 223; CHECK-NEXT: [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16> 224; CHECK-NEXT: [[R:%.*]] = xor <2 x i16> [[TMP1]], %x16 225; CHECK-NEXT: ret <2 x i16> [[R]] 226; 227 %y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17> 228 %x32 = zext <2 x i16> %x16 to <2 x i32> 229 %b = xor <2 x i32> %y32op0, %x32 230 %r = trunc <2 x i32> %b to <2 x i16> 231 ret <2 x i16> %r 232} 233 234define <2 x i16> @narrow_sext_add_commute(<2 x i16> %x16, <2 x i32> %y32) { 235; CHECK-LABEL: @narrow_sext_add_commute( 236; CHECK-NEXT: [[Y32OP0:%.*]] = sdiv <2 x i32> %y32, <i32 7, i32 -17> 237; CHECK-NEXT: [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16> 238; CHECK-NEXT: [[R:%.*]] = add <2 x i16> [[TMP1]], %x16 239; CHECK-NEXT: ret <2 x i16> [[R]] 240; 241 %y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17> 242 %x32 = sext <2 x i16> %x16 to <2 x i32> 243 %b = add <2 x i32> %y32op0, %x32 244 %r = trunc <2 x i32> %b to <2 x i16> 245 ret <2 x i16> %r 246} 247 248define <2 x i16> @narrow_zext_add_commute(<2 x i16> %x16, <2 x i32> %y32) { 249; CHECK-LABEL: @narrow_zext_add_commute( 250; CHECK-NEXT: [[Y32OP0:%.*]] = sdiv <2 x i32> %y32, <i32 7, i32 -17> 251; CHECK-NEXT: [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16> 252; CHECK-NEXT: [[R:%.*]] = add <2 x i16> [[TMP1]], %x16 253; CHECK-NEXT: ret <2 x i16> [[R]] 254; 255 %y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17> 256 %x32 = zext <2 x i16> %x16 to <2 x i32> 257 %b = add <2 x i32> %y32op0, %x32 258 %r = trunc <2 x i32> %b to <2 x i16> 259 ret <2 x i16> %r 260} 261 262define <2 x i16> @narrow_sext_sub_commute(<2 x i16> %x16, <2 x i32> %y32) { 263; CHECK-LABEL: @narrow_sext_sub_commute( 264; CHECK-NEXT: [[Y32OP0:%.*]] = sdiv <2 x i32> %y32, <i32 7, i32 -17> 265; CHECK-NEXT: [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16> 266; CHECK-NEXT: [[R:%.*]] = sub <2 x i16> [[TMP1]], %x16 267; CHECK-NEXT: ret <2 x i16> [[R]] 268; 269 %y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17> 270 %x32 = sext <2 x i16> %x16 to <2 x i32> 271 %b = sub <2 x i32> %y32op0, %x32 272 %r = trunc <2 x i32> %b to <2 x i16> 273 ret <2 x i16> %r 274} 275 276define <2 x i16> @narrow_zext_sub_commute(<2 x i16> %x16, <2 x i32> %y32) { 277; CHECK-LABEL: @narrow_zext_sub_commute( 278; CHECK-NEXT: [[Y32OP0:%.*]] = sdiv <2 x i32> %y32, <i32 7, i32 -17> 279; CHECK-NEXT: [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16> 280; CHECK-NEXT: [[R:%.*]] = sub <2 x i16> [[TMP1]], %x16 281; CHECK-NEXT: ret <2 x i16> [[R]] 282; 283 %y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17> 284 %x32 = zext <2 x i16> %x16 to <2 x i32> 285 %b = sub <2 x i32> %y32op0, %x32 286 %r = trunc <2 x i32> %b to <2 x i16> 287 ret <2 x i16> %r 288} 289 290define <2 x i16> @narrow_sext_mul_commute(<2 x i16> %x16, <2 x i32> %y32) { 291; CHECK-LABEL: @narrow_sext_mul_commute( 292; CHECK-NEXT: [[Y32OP0:%.*]] = sdiv <2 x i32> %y32, <i32 7, i32 -17> 293; CHECK-NEXT: [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16> 294; CHECK-NEXT: [[R:%.*]] = mul <2 x i16> [[TMP1]], %x16 295; CHECK-NEXT: ret <2 x i16> [[R]] 296; 297 %y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17> 298 %x32 = sext <2 x i16> %x16 to <2 x i32> 299 %b = mul <2 x i32> %y32op0, %x32 300 %r = trunc <2 x i32> %b to <2 x i16> 301 ret <2 x i16> %r 302} 303 304define <2 x i16> @narrow_zext_mul_commute(<2 x i16> %x16, <2 x i32> %y32) { 305; CHECK-LABEL: @narrow_zext_mul_commute( 306; CHECK-NEXT: [[Y32OP0:%.*]] = sdiv <2 x i32> %y32, <i32 7, i32 -17> 307; CHECK-NEXT: [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16> 308; CHECK-NEXT: [[R:%.*]] = mul <2 x i16> [[TMP1]], %x16 309; CHECK-NEXT: ret <2 x i16> [[R]] 310; 311 %y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17> 312 %x32 = zext <2 x i16> %x16 to <2 x i32> 313 %b = mul <2 x i32> %y32op0, %x32 314 %r = trunc <2 x i32> %b to <2 x i16> 315 ret <2 x i16> %r 316} 317 318; Test cases for PR43580 319define i8 @narrow_zext_ashr_keep_trunc(i8 %i1, i8 %i2) { 320; CHECK-LABEL: @narrow_zext_ashr_keep_trunc( 321; CHECK-NEXT: [[I1_EXT:%.*]] = sext i8 [[I1:%.*]] to i16 322; CHECK-NEXT: [[I2_EXT:%.*]] = sext i8 [[I2:%.*]] to i16 323; CHECK-NEXT: [[SUB:%.*]] = add nsw i16 [[I1_EXT]], [[I2_EXT]] 324; CHECK-NEXT: [[TMP1:%.*]] = lshr i16 [[SUB]], 1 325; CHECK-NEXT: [[T:%.*]] = trunc i16 [[TMP1]] to i8 326; CHECK-NEXT: ret i8 [[T]] 327; 328 %i1.ext = sext i8 %i1 to i32 329 %i2.ext = sext i8 %i2 to i32 330 %sub = add nsw i32 %i1.ext, %i2.ext 331 %shift = ashr i32 %sub, 1 332 %t = trunc i32 %shift to i8 333 ret i8 %t 334} 335 336define i8 @narrow_zext_ashr_keep_trunc2(i9 %i1, i9 %i2) { 337; CHECK-LABEL: @narrow_zext_ashr_keep_trunc2( 338; CHECK-NEXT: [[I1_EXT1:%.*]] = zext i9 [[I1:%.*]] to i16 339; CHECK-NEXT: [[I2_EXT2:%.*]] = zext i9 [[I2:%.*]] to i16 340; CHECK-NEXT: [[SUB:%.*]] = add nuw nsw i16 [[I1_EXT1]], [[I2_EXT2]] 341; CHECK-NEXT: [[TMP1:%.*]] = lshr i16 [[SUB]], 1 342; CHECK-NEXT: [[T:%.*]] = trunc i16 [[TMP1]] to i8 343; CHECK-NEXT: ret i8 [[T]] 344; 345 %i1.ext = sext i9 %i1 to i64 346 %i2.ext = sext i9 %i2 to i64 347 %sub = add nsw i64 %i1.ext, %i2.ext 348 %shift = ashr i64 %sub, 1 349 %t = trunc i64 %shift to i8 350 ret i8 %t 351} 352 353define i7 @narrow_zext_ashr_keep_trunc3(i8 %i1, i8 %i2) { 354; CHECK-LABEL: @narrow_zext_ashr_keep_trunc3( 355; CHECK-NEXT: [[I1_EXT1:%.*]] = zext i8 [[I1:%.*]] to i14 356; CHECK-NEXT: [[I2_EXT2:%.*]] = zext i8 [[I2:%.*]] to i14 357; CHECK-NEXT: [[SUB:%.*]] = add nuw nsw i14 [[I1_EXT1]], [[I2_EXT2]] 358; CHECK-NEXT: [[TMP1:%.*]] = lshr i14 [[SUB]], 1 359; CHECK-NEXT: [[T:%.*]] = trunc i14 [[TMP1]] to i7 360; CHECK-NEXT: ret i7 [[T]] 361; 362 %i1.ext = sext i8 %i1 to i64 363 %i2.ext = sext i8 %i2 to i64 364 %sub = add nsw i64 %i1.ext, %i2.ext 365 %shift = ashr i64 %sub, 1 366 %t = trunc i64 %shift to i7 367 ret i7 %t 368} 369 370define <8 x i8> @narrow_zext_ashr_keep_trunc_vector(<8 x i8> %i1, <8 x i8> %i2) { 371; CHECK-LABEL: @narrow_zext_ashr_keep_trunc_vector( 372; CHECK-NEXT: [[I1_EXT:%.*]] = sext <8 x i8> [[I1:%.*]] to <8 x i32> 373; CHECK-NEXT: [[I2_EXT:%.*]] = sext <8 x i8> [[I2:%.*]] to <8 x i32> 374; CHECK-NEXT: [[SUB:%.*]] = add nsw <8 x i32> [[I1_EXT]], [[I2_EXT]] 375; CHECK-NEXT: [[TMP1:%.*]] = lshr <8 x i32> [[SUB]], <i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1> 376; CHECK-NEXT: [[T:%.*]] = trunc <8 x i32> [[TMP1]] to <8 x i8> 377; CHECK-NEXT: ret <8 x i8> [[T]] 378; 379 %i1.ext = sext <8 x i8> %i1 to <8 x i32> 380 %i2.ext = sext <8 x i8> %i2 to <8 x i32> 381 %sub = add nsw <8 x i32> %i1.ext, %i2.ext 382 %shift = ashr <8 x i32> %sub, <i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1> 383 %t = trunc <8 x i32> %shift to <8 x i8> 384 ret <8 x i8> %t 385} 386 387define i8 @dont_narrow_zext_ashr_keep_trunc(i8 %i1, i8 %i2) { 388; CHECK-LABEL: @dont_narrow_zext_ashr_keep_trunc( 389; CHECK-NEXT: [[I1_EXT:%.*]] = sext i8 [[I1:%.*]] to i16 390; CHECK-NEXT: [[I2_EXT:%.*]] = sext i8 [[I2:%.*]] to i16 391; CHECK-NEXT: [[SUB:%.*]] = add nsw i16 [[I1_EXT]], [[I2_EXT]] 392; CHECK-NEXT: [[TMP1:%.*]] = lshr i16 [[SUB]], 1 393; CHECK-NEXT: [[T:%.*]] = trunc i16 [[TMP1]] to i8 394; CHECK-NEXT: ret i8 [[T]] 395; 396 %i1.ext = sext i8 %i1 to i16 397 %i2.ext = sext i8 %i2 to i16 398 %sub = add nsw i16 %i1.ext, %i2.ext 399 %shift = ashr i16 %sub, 1 400 %t = trunc i16 %shift to i8 401 ret i8 %t 402} 403