; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt < %s -passes=instcombine -S -data-layout="n8:16:32:64" | FileCheck %s --check-prefixes=CHECK,DL64 ; RUN: opt < %s -passes=instcombine -S -data-layout="n8" | FileCheck %s --check-prefixes=CHECK,DL8 declare void @use(i8) define i1 @ult_2(i32 %x) { ; CHECK-LABEL: @ult_2( ; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[X:%.*]], 254 ; CHECK-NEXT: [[R:%.*]] = icmp eq i32 [[TMP1]], 0 ; CHECK-NEXT: ret i1 [[R]] ; %t = trunc i32 %x to i8 %r = icmp ult i8 %t, 2 ret i1 %r } define <2 x i1> @ult_16_splat(<2 x i16> %x) { ; CHECK-LABEL: @ult_16_splat( ; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i16> [[X:%.*]], ; CHECK-NEXT: [[R:%.*]] = icmp eq <2 x i16> [[TMP1]], zeroinitializer ; CHECK-NEXT: ret <2 x i1> [[R]] ; %t = trunc <2 x i16> %x to <2 x i11> %r = icmp ult <2 x i11> %t, ret <2 x i1> %r } ; negative test - need power-of-2 constant define i1 @ult_3(i32 %x) { ; CHECK-LABEL: @ult_3( ; CHECK-NEXT: [[T:%.*]] = trunc i32 [[X:%.*]] to i8 ; CHECK-NEXT: [[R:%.*]] = icmp ult i8 [[T]], 3 ; CHECK-NEXT: ret i1 [[R]] ; %t = trunc i32 %x to i8 %r = icmp ult i8 %t, 3 ret i1 %r } ; negative test - no extra use allowed define i1 @ult_2_use(i32 %x) { ; CHECK-LABEL: @ult_2_use( ; CHECK-NEXT: [[T:%.*]] = trunc i32 [[X:%.*]] to i8 ; CHECK-NEXT: call void @use(i8 [[T]]) ; CHECK-NEXT: [[R:%.*]] = icmp ult i8 [[T]], 2 ; CHECK-NEXT: ret i1 [[R]] ; %t = trunc i32 %x to i8 call void @use(i8 %t) %r = icmp ult i8 %t, 2 ret i1 %r } @a = internal unnamed_addr constant [3 x i32] [i32 0, i32 0, i32 1], align 4 define i1 @PR52260(i32 %x) { ; CHECK-LABEL: @PR52260( ; CHECK-NEXT: ret i1 true ; %idxprom = sext i32 %x to i64 %idx = getelementptr inbounds [3 x i32], ptr @a, i64 0, i64 %idxprom %t1 = load i32, ptr %idx, align 4 %conv1 = lshr i32 %t1, 1 %t2 = trunc i32 %conv1 to i8 %conv2 = and i8 %t2, 127 %tobool = icmp eq i8 %conv2, 0 ret i1 %tobool } define i1 @ult_192(i32 %x) { ; CHECK-LABEL: @ult_192( ; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[X:%.*]], 192 ; CHECK-NEXT: [[R:%.*]] = icmp ne i32 [[TMP1]], 192 ; CHECK-NEXT: ret i1 [[R]] ; %t = trunc i32 %x to i8 %r = icmp ult i8 %t, 192 ; 0b1100_0000 ret i1 %r } define <2 x i1> @ult_2044_splat(<2 x i16> %x) { ; CHECK-LABEL: @ult_2044_splat( ; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i16> [[X:%.*]], ; CHECK-NEXT: [[R:%.*]] = icmp ne <2 x i16> [[TMP1]], ; CHECK-NEXT: ret <2 x i1> [[R]] ; %t = trunc <2 x i16> %x to <2 x i11> %r = icmp ult <2 x i11> %t, ; 0b111_1111_1100 ret <2 x i1> %r } ; negative test - need high-bit-mask constant define i1 @ult_96(i32 %x) { ; CHECK-LABEL: @ult_96( ; CHECK-NEXT: [[T:%.*]] = trunc i32 [[X:%.*]] to i8 ; CHECK-NEXT: [[R:%.*]] = icmp ult i8 [[T]], 96 ; CHECK-NEXT: ret i1 [[R]] ; %t = trunc i32 %x to i8 %r = icmp ult i8 %t, 96 ; 0b0110_0000 ret i1 %r } ; negative test - no extra use allowed define i1 @ult_192_use(i32 %x) { ; CHECK-LABEL: @ult_192_use( ; CHECK-NEXT: [[T:%.*]] = trunc i32 [[X:%.*]] to i8 ; CHECK-NEXT: call void @use(i8 [[T]]) ; CHECK-NEXT: [[R:%.*]] = icmp ult i8 [[T]], -64 ; CHECK-NEXT: ret i1 [[R]] ; %t = trunc i32 %x to i8 call void @use(i8 %t) %r = icmp ult i8 %t, 192 ret i1 %r } define i1 @ugt_3(i32 %x) { ; CHECK-LABEL: @ugt_3( ; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[X:%.*]], 252 ; CHECK-NEXT: [[R:%.*]] = icmp ne i32 [[TMP1]], 0 ; CHECK-NEXT: ret i1 [[R]] ; %t = trunc i32 %x to i8 %r = icmp ugt i8 %t, 3 ret i1 %r } define <2 x i1> @ugt_7_splat(<2 x i16> %x) { ; CHECK-LABEL: @ugt_7_splat( ; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i16> [[X:%.*]], ; CHECK-NEXT: [[R:%.*]] = icmp ne <2 x i16> [[TMP1]], zeroinitializer ; CHECK-NEXT: ret <2 x i1> [[R]] ; %t = trunc <2 x i16> %x to <2 x i11> %r = icmp ugt <2 x i11> %t, ret <2 x i1> %r } ; negative test - need low-bit-mask constant define i1 @ugt_4(i32 %x) { ; CHECK-LABEL: @ugt_4( ; CHECK-NEXT: [[T:%.*]] = trunc i32 [[X:%.*]] to i8 ; CHECK-NEXT: [[R:%.*]] = icmp ugt i8 [[T]], 4 ; CHECK-NEXT: ret i1 [[R]] ; %t = trunc i32 %x to i8 %r = icmp ugt i8 %t, 4 ret i1 %r } ; negative test - no extra use allowed define i1 @ugt_3_use(i32 %x) { ; CHECK-LABEL: @ugt_3_use( ; CHECK-NEXT: [[T:%.*]] = trunc i32 [[X:%.*]] to i8 ; CHECK-NEXT: call void @use(i8 [[T]]) ; CHECK-NEXT: [[R:%.*]] = icmp ugt i8 [[T]], 3 ; CHECK-NEXT: ret i1 [[R]] ; %t = trunc i32 %x to i8 call void @use(i8 %t) %r = icmp ugt i8 %t, 3 ret i1 %r } define i1 @ugt_253(i32 %x) { ; CHECK-LABEL: @ugt_253( ; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[X:%.*]], 254 ; CHECK-NEXT: [[R:%.*]] = icmp eq i32 [[TMP1]], 254 ; CHECK-NEXT: ret i1 [[R]] ; %t = trunc i32 %x to i8 %r = icmp ugt i8 %t, 253 ret i1 %r } define <2 x i1> @ugt_2043_splat(<2 x i16> %x) { ; CHECK-LABEL: @ugt_2043_splat( ; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i16> [[X:%.*]], ; CHECK-NEXT: [[R:%.*]] = icmp eq <2 x i16> [[TMP1]], ; CHECK-NEXT: ret <2 x i1> [[R]] ; %t = trunc <2 x i16> %x to <2 x i11> %r = icmp ugt <2 x i11> %t, ; 0b111_1111_101 ret <2 x i1> %r } ; negative test - need not-of-power-of-2 constant define i1 @ugt_252(i32 %x) { ; CHECK-LABEL: @ugt_252( ; CHECK-NEXT: [[T:%.*]] = trunc i32 [[X:%.*]] to i8 ; CHECK-NEXT: [[R:%.*]] = icmp ugt i8 [[T]], -4 ; CHECK-NEXT: ret i1 [[R]] ; %t = trunc i32 %x to i8 %r = icmp ugt i8 %t, 252 ret i1 %r } ; negative test - no extra use allowed define i1 @ugt_253_use(i32 %x) { ; CHECK-LABEL: @ugt_253_use( ; CHECK-NEXT: [[T:%.*]] = trunc i32 [[X:%.*]] to i8 ; CHECK-NEXT: call void @use(i8 [[T]]) ; CHECK-NEXT: [[R:%.*]] = icmp ugt i8 [[T]], -3 ; CHECK-NEXT: ret i1 [[R]] ; %t = trunc i32 %x to i8 call void @use(i8 %t) %r = icmp ugt i8 %t, 253 ret i1 %r } define i1 @slt_0(i32 %x) { ; CHECK-LABEL: @slt_0( ; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[X:%.*]], 128 ; CHECK-NEXT: [[R:%.*]] = icmp ne i32 [[TMP1]], 0 ; CHECK-NEXT: ret i1 [[R]] ; %t = trunc i32 %x to i8 %r = icmp slt i8 %t, 0 ret i1 %r } define <2 x i1> @slt_0_splat(<2 x i16> %x) { ; CHECK-LABEL: @slt_0_splat( ; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i16> [[X:%.*]], ; CHECK-NEXT: [[R:%.*]] = icmp ne <2 x i16> [[TMP1]], zeroinitializer ; CHECK-NEXT: ret <2 x i1> [[R]] ; %t = trunc <2 x i16> %x to <2 x i11> %r = icmp slt <2 x i11> %t, zeroinitializer ret <2 x i1> %r } define i1 @slt_1(i32 %x) { ; CHECK-LABEL: @slt_1( ; CHECK-NEXT: [[T:%.*]] = trunc i32 [[X:%.*]] to i8 ; CHECK-NEXT: [[R:%.*]] = icmp slt i8 [[T]], 1 ; CHECK-NEXT: ret i1 [[R]] ; %t = trunc i32 %x to i8 %r = icmp slt i8 %t, 1 ret i1 %r } define i1 @slt_0_use(i32 %x) { ; CHECK-LABEL: @slt_0_use( ; CHECK-NEXT: [[T:%.*]] = trunc i32 [[X:%.*]] to i8 ; CHECK-NEXT: call void @use(i8 [[T]]) ; CHECK-NEXT: [[R:%.*]] = icmp slt i8 [[T]], 0 ; CHECK-NEXT: ret i1 [[R]] ; %t = trunc i32 %x to i8 call void @use(i8 %t) %r = icmp slt i8 %t, 0 ret i1 %r } define i1 @sgt_n1(i32 %x) { ; CHECK-LABEL: @sgt_n1( ; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[X:%.*]], 128 ; CHECK-NEXT: [[R:%.*]] = icmp eq i32 [[TMP1]], 0 ; CHECK-NEXT: ret i1 [[R]] ; %t = trunc i32 %x to i8 %r = icmp sgt i8 %t, -1 ret i1 %r } define <2 x i1> @sgt_n1_splat(<2 x i16> %x) { ; CHECK-LABEL: @sgt_n1_splat( ; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i16> [[X:%.*]], ; CHECK-NEXT: [[R:%.*]] = icmp eq <2 x i16> [[TMP1]], zeroinitializer ; CHECK-NEXT: ret <2 x i1> [[R]] ; %t = trunc <2 x i16> %x to <2 x i11> %r = icmp sgt <2 x i11> %t, ret <2 x i1> %r } define i1 @sgt_0(i32 %x) { ; CHECK-LABEL: @sgt_0( ; CHECK-NEXT: [[T:%.*]] = trunc i32 [[X:%.*]] to i8 ; CHECK-NEXT: [[R:%.*]] = icmp sgt i8 [[T]], 0 ; CHECK-NEXT: ret i1 [[R]] ; %t = trunc i32 %x to i8 %r = icmp sgt i8 %t, 0 ret i1 %r } define i1 @sgt_n1_use(i32 %x) { ; CHECK-LABEL: @sgt_n1_use( ; CHECK-NEXT: [[T:%.*]] = trunc i32 [[X:%.*]] to i8 ; CHECK-NEXT: call void @use(i8 [[T]]) ; CHECK-NEXT: [[R:%.*]] = icmp sgt i8 [[T]], -1 ; CHECK-NEXT: ret i1 [[R]] ; %t = trunc i32 %x to i8 call void @use(i8 %t) %r = icmp sgt i8 %t, -1 ret i1 %r } define i1 @trunc_eq_i32_i8(i32 %x) { ; DL64-LABEL: @trunc_eq_i32_i8( ; DL64-NEXT: [[TMP1:%.*]] = and i32 [[X:%.*]], 255 ; DL64-NEXT: [[R:%.*]] = icmp eq i32 [[TMP1]], 42 ; DL64-NEXT: ret i1 [[R]] ; ; DL8-LABEL: @trunc_eq_i32_i8( ; DL8-NEXT: [[T:%.*]] = trunc i32 [[X:%.*]] to i8 ; DL8-NEXT: [[R:%.*]] = icmp eq i8 [[T]], 42 ; DL8-NEXT: ret i1 [[R]] ; %t = trunc i32 %x to i8 %r = icmp eq i8 %t, 42 ret i1 %r } define <2 x i1> @trunc_eq_v2i32_v2i8(<2 x i32> %x) { ; CHECK-LABEL: @trunc_eq_v2i32_v2i8( ; CHECK-NEXT: [[T:%.*]] = trunc <2 x i32> [[X:%.*]] to <2 x i8> ; CHECK-NEXT: [[R:%.*]] = icmp eq <2 x i8> [[T]], ; CHECK-NEXT: ret <2 x i1> [[R]] ; %t = trunc <2 x i32> %x to <2 x i8> %r = icmp eq <2 x i8> %t, ret <2 x i1> %r } define i1 @trunc_ne_i64_i10(i64 %x) { ; DL64-LABEL: @trunc_ne_i64_i10( ; DL64-NEXT: [[TMP1:%.*]] = and i64 [[X:%.*]], 1023 ; DL64-NEXT: [[R:%.*]] = icmp eq i64 [[TMP1]], 42 ; DL64-NEXT: ret i1 [[R]] ; ; DL8-LABEL: @trunc_ne_i64_i10( ; DL8-NEXT: [[T:%.*]] = trunc i64 [[X:%.*]] to i10 ; DL8-NEXT: [[R:%.*]] = icmp eq i10 [[T]], 42 ; DL8-NEXT: ret i1 [[R]] ; %t = trunc i64 %x to i10 %r = icmp eq i10 %t, 42 ret i1 %r } define i1 @shl1_trunc_eq0(i32 %a) { ; CHECK-LABEL: @shl1_trunc_eq0( ; CHECK-NEXT: [[R:%.*]] = icmp ugt i32 [[A:%.*]], 15 ; CHECK-NEXT: ret i1 [[R]] ; %shl = shl i32 1, %a %t = trunc i32 %shl to i16 %r = icmp eq i16 %t, 0 ret i1 %r } define <2 x i1> @shl1_trunc_ne0(<2 x i8> %a) { ; CHECK-LABEL: @shl1_trunc_ne0( ; CHECK-NEXT: [[R:%.*]] = icmp ult <2 x i8> [[A:%.*]], ; CHECK-NEXT: ret <2 x i1> [[R]] ; %shl = shl <2 x i8> , %a %t = trunc <2 x i8> %shl to <2 x i5> %r = icmp ne <2 x i5> %t, zeroinitializer ret <2 x i1> %r } define i1 @shl1_trunc_eq0_use1(i8 %a) { ; CHECK-LABEL: @shl1_trunc_eq0_use1( ; CHECK-NEXT: [[SHL:%.*]] = shl nuw i8 1, [[A:%.*]] ; CHECK-NEXT: call void @use(i8 [[SHL]]) ; CHECK-NEXT: [[R:%.*]] = icmp ugt i8 [[A]], 5 ; CHECK-NEXT: ret i1 [[R]] ; %shl = shl i8 1, %a call void @use(i8 %shl) %t = trunc i8 %shl to i6 %r = icmp eq i6 %t, 0 ret i1 %r } define i1 @shl1_trunc_ne0_use2(i37 %a) { ; CHECK-LABEL: @shl1_trunc_ne0_use2( ; CHECK-NEXT: [[SHL:%.*]] = shl nuw i37 1, [[A:%.*]] ; CHECK-NEXT: [[T:%.*]] = trunc i37 [[SHL]] to i8 ; CHECK-NEXT: call void @use(i8 [[T]]) ; CHECK-NEXT: [[R:%.*]] = icmp ult i37 [[A]], 8 ; CHECK-NEXT: ret i1 [[R]] ; %shl = shl i37 1, %a %t = trunc i37 %shl to i8 call void @use(i8 %t) %r = icmp ne i8 %t, 0 ret i1 %r } ; TODO: A > 4 define i1 @shl2_trunc_eq0(i9 %a) { ; CHECK-LABEL: @shl2_trunc_eq0( ; CHECK-NEXT: [[SHL:%.*]] = shl i9 2, [[A:%.*]] ; CHECK-NEXT: [[T:%.*]] = trunc i9 [[SHL]] to i6 ; CHECK-NEXT: [[R:%.*]] = icmp eq i6 [[T]], 0 ; CHECK-NEXT: ret i1 [[R]] ; %shl = shl i9 2, %a %t = trunc i9 %shl to i6 %r = icmp eq i6 %t, 0 ret i1 %r } define i1 @shl2_trunc_ne0(i9 %a) { ; CHECK-LABEL: @shl2_trunc_ne0( ; CHECK-NEXT: [[SHL:%.*]] = shl i9 2, [[A:%.*]] ; CHECK-NEXT: [[T:%.*]] = trunc i9 [[SHL]] to i6 ; CHECK-NEXT: [[R:%.*]] = icmp ne i6 [[T]], 0 ; CHECK-NEXT: ret i1 [[R]] ; %shl = shl i9 2, %a %t = trunc i9 %shl to i6 %r = icmp ne i6 %t, 0 ret i1 %r } define i1 @shl3_trunc_eq0(i9 %a) { ; CHECK-LABEL: @shl3_trunc_eq0( ; CHECK-NEXT: [[SHL:%.*]] = shl i9 3, [[A:%.*]] ; CHECK-NEXT: [[T:%.*]] = trunc i9 [[SHL]] to i6 ; CHECK-NEXT: [[R:%.*]] = icmp eq i6 [[T]], 0 ; CHECK-NEXT: ret i1 [[R]] ; %shl = shl i9 3, %a %t = trunc i9 %shl to i6 %r = icmp eq i6 %t, 0 ret i1 %r } define <2 x i1> @shl4_trunc_ne0(<2 x i8> %a) { ; CHECK-LABEL: @shl4_trunc_ne0( ; CHECK-NEXT: [[SHL:%.*]] = shl <2 x i8> , [[A:%.*]] ; CHECK-NEXT: [[T:%.*]] = trunc <2 x i8> [[SHL]] to <2 x i5> ; CHECK-NEXT: [[R:%.*]] = icmp ne <2 x i5> [[T]], zeroinitializer ; CHECK-NEXT: ret <2 x i1> [[R]] ; %shl = shl <2 x i8> , %a %t = trunc <2 x i8> %shl to <2 x i5> %r = icmp ne <2 x i5> %t, zeroinitializer ret <2 x i1> %r } ; TODO: A < 5 define i1 @shl1_trunc_sgt0(i9 %a) { ; CHECK-LABEL: @shl1_trunc_sgt0( ; CHECK-NEXT: [[SHL:%.*]] = shl nuw i9 1, [[A:%.*]] ; CHECK-NEXT: [[T:%.*]] = trunc i9 [[SHL]] to i6 ; CHECK-NEXT: [[R:%.*]] = icmp sgt i6 [[T]], 0 ; CHECK-NEXT: ret i1 [[R]] ; %shl = shl i9 1, %a %t = trunc i9 %shl to i6 %r = icmp sgt i6 %t, 0 ret i1 %r } define i1 @shl1_trunc_eq1(i64 %a) { ; CHECK-LABEL: @shl1_trunc_eq1( ; CHECK-NEXT: [[SHL:%.*]] = shl nuw i64 1, [[A:%.*]] ; CHECK-NEXT: [[T:%.*]] = trunc i64 [[SHL]] to i8 ; CHECK-NEXT: call void @use(i8 [[T]]) ; CHECK-NEXT: [[R:%.*]] = icmp eq i64 [[A]], 0 ; CHECK-NEXT: ret i1 [[R]] ; %shl = shl i64 1, %a %t = trunc i64 %shl to i8 call void @use(i8 %t) %r = icmp eq i8 %t, 1 ret i1 %r } define i1 @shl1_trunc_ne32(i8 %a) { ; CHECK-LABEL: @shl1_trunc_ne32( ; CHECK-NEXT: [[SHL:%.*]] = shl nuw i8 1, [[A:%.*]] ; CHECK-NEXT: call void @use(i8 [[SHL]]) ; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[A]], 5 ; CHECK-NEXT: ret i1 [[R]] ; %shl = shl i8 1, %a call void @use(i8 %shl) %t = trunc i8 %shl to i6 %r = icmp ne i6 %t, 32 ret i1 %r } define i1 @shl2_trunc_eq8_i32(i32 %a) { ; DL64-LABEL: @shl2_trunc_eq8_i32( ; DL64-NEXT: [[SHL:%.*]] = shl i32 2, [[A:%.*]] ; DL64-NEXT: [[TMP1:%.*]] = and i32 [[SHL]], 65534 ; DL64-NEXT: [[R:%.*]] = icmp eq i32 [[TMP1]], 8 ; DL64-NEXT: ret i1 [[R]] ; ; DL8-LABEL: @shl2_trunc_eq8_i32( ; DL8-NEXT: [[SHL:%.*]] = shl i32 2, [[A:%.*]] ; DL8-NEXT: [[T:%.*]] = trunc i32 [[SHL]] to i16 ; DL8-NEXT: [[R:%.*]] = icmp eq i16 [[T]], 8 ; DL8-NEXT: ret i1 [[R]] ; %shl = shl i32 2, %a %t = trunc i32 %shl to i16 %r = icmp eq i16 %t, 8 ret i1 %r } define i1 @shl2_trunc_ne8_i32(i32 %a) { ; DL64-LABEL: @shl2_trunc_ne8_i32( ; DL64-NEXT: [[SHL:%.*]] = shl i32 2, [[A:%.*]] ; DL64-NEXT: [[TMP1:%.*]] = and i32 [[SHL]], 65534 ; DL64-NEXT: [[R:%.*]] = icmp ne i32 [[TMP1]], 8 ; DL64-NEXT: ret i1 [[R]] ; ; DL8-LABEL: @shl2_trunc_ne8_i32( ; DL8-NEXT: [[SHL:%.*]] = shl i32 2, [[A:%.*]] ; DL8-NEXT: [[T:%.*]] = trunc i32 [[SHL]] to i16 ; DL8-NEXT: [[R:%.*]] = icmp ne i16 [[T]], 8 ; DL8-NEXT: ret i1 [[R]] ; %shl = shl i32 2, %a %t = trunc i32 %shl to i16 %r = icmp ne i16 %t, 8 ret i1 %r } define i1 @shl1_trunc_sgt4(i32 %a) { ; CHECK-LABEL: @shl1_trunc_sgt4( ; CHECK-NEXT: [[SHL:%.*]] = shl nuw i32 1, [[A:%.*]] ; CHECK-NEXT: [[T:%.*]] = trunc i32 [[SHL]] to i16 ; CHECK-NEXT: [[R:%.*]] = icmp sgt i16 [[T]], 4 ; CHECK-NEXT: ret i1 [[R]] ; %shl = shl i32 1, %a %t = trunc i32 %shl to i16 %r = icmp sgt i16 %t, 4 ret i1 %r }