diff --git a/llvm/test/Transforms/InstCombine/icmp-topbitssame.ll b/llvm/test/Transforms/InstCombine/icmp-topbitssame.ll new file mode 100644 index 0000000000000..2794e1345b34e --- /dev/null +++ b/llvm/test/Transforms/InstCombine/icmp-topbitssame.ll @@ -0,0 +1,239 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instcombine -S | FileCheck %s +target 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" + +declare void @use(i8) +declare void @use16(i16) + +define i1 @testi16i8(i16 %add) { +; CHECK-LABEL: @testi16i8( +; CHECK-NEXT: [[SH:%.*]] = lshr i16 [[ADD:%.*]], 8 +; CHECK-NEXT: [[CONV_I:%.*]] = trunc i16 [[SH]] to i8 +; CHECK-NEXT: [[CONV1_I:%.*]] = trunc i16 [[ADD]] to i8 +; CHECK-NEXT: [[SHR2_I:%.*]] = ashr i8 [[CONV1_I]], 7 +; CHECK-NEXT: [[CMP_NOT_I:%.*]] = icmp eq i8 [[SHR2_I]], [[CONV_I]] +; CHECK-NEXT: ret i1 [[CMP_NOT_I]] +; + %sh = lshr i16 %add, 8 + %conv.i = trunc i16 %sh to i8 + %conv1.i = trunc i16 %add to i8 + %shr2.i = ashr i8 %conv1.i, 7 + %cmp.not.i = icmp eq i8 %shr2.i, %conv.i + ret i1 %cmp.not.i +} + +define i1 @testi16i8_com(i16 %add) { +; CHECK-LABEL: @testi16i8_com( +; CHECK-NEXT: [[SH:%.*]] = lshr i16 [[ADD:%.*]], 8 +; CHECK-NEXT: [[CONV_I:%.*]] = trunc i16 [[SH]] to i8 +; CHECK-NEXT: [[CONV1_I:%.*]] = trunc i16 [[ADD]] to i8 +; CHECK-NEXT: [[SHR2_I:%.*]] = ashr i8 [[CONV1_I]], 7 +; CHECK-NEXT: [[CMP_NOT_I:%.*]] = icmp eq i8 [[SHR2_I]], [[CONV_I]] +; CHECK-NEXT: ret i1 [[CMP_NOT_I]] +; + %sh = lshr i16 %add, 8 + %conv.i = trunc i16 %sh to i8 + %conv1.i = trunc i16 %add to i8 + %shr2.i = ashr i8 %conv1.i, 7 + %cmp.not.i = icmp eq i8 %conv.i, %shr2.i + ret i1 %cmp.not.i +} + +define i1 @testi16i8_ne(i16 %add) { +; CHECK-LABEL: @testi16i8_ne( +; CHECK-NEXT: [[SH:%.*]] = lshr i16 [[ADD:%.*]], 8 +; CHECK-NEXT: [[CONV_I:%.*]] = trunc i16 [[SH]] to i8 +; CHECK-NEXT: [[CONV1_I:%.*]] = trunc i16 [[ADD]] to i8 +; CHECK-NEXT: [[SHR2_I:%.*]] = ashr i8 [[CONV1_I]], 7 +; CHECK-NEXT: [[CMP_NOT_I:%.*]] = icmp ne i8 [[SHR2_I]], [[CONV_I]] +; CHECK-NEXT: ret i1 [[CMP_NOT_I]] +; + %sh = lshr i16 %add, 8 + %conv.i = trunc i16 %sh to i8 + %conv1.i = trunc i16 %add to i8 + %shr2.i = ashr i8 %conv1.i, 7 + %cmp.not.i = icmp ne i8 %shr2.i, %conv.i + ret i1 %cmp.not.i +} + +define i1 @testi16i8_ne_com(i16 %add) { +; CHECK-LABEL: @testi16i8_ne_com( +; CHECK-NEXT: [[SH:%.*]] = lshr i16 [[ADD:%.*]], 8 +; CHECK-NEXT: [[CONV_I:%.*]] = trunc i16 [[SH]] to i8 +; CHECK-NEXT: [[CONV1_I:%.*]] = trunc i16 [[ADD]] to i8 +; CHECK-NEXT: [[SHR2_I:%.*]] = ashr i8 [[CONV1_I]], 7 +; CHECK-NEXT: [[CMP_NOT_I:%.*]] = icmp ne i8 [[SHR2_I]], [[CONV_I]] +; CHECK-NEXT: ret i1 [[CMP_NOT_I]] +; + %sh = lshr i16 %add, 8 + %conv.i = trunc i16 %sh to i8 + %conv1.i = trunc i16 %add to i8 + %shr2.i = ashr i8 %conv1.i, 7 + %cmp.not.i = icmp ne i8 %conv.i, %shr2.i + ret i1 %cmp.not.i +} + +define i1 @testi64i32(i64 %add) { +; CHECK-LABEL: @testi64i32( +; CHECK-NEXT: [[SH:%.*]] = lshr i64 [[ADD:%.*]], 32 +; CHECK-NEXT: [[CONV_I:%.*]] = trunc i64 [[SH]] to i32 +; CHECK-NEXT: [[CONV1_I:%.*]] = trunc i64 [[ADD]] to i32 +; CHECK-NEXT: [[SHR2_I:%.*]] = ashr i32 [[CONV1_I]], 31 +; CHECK-NEXT: [[CMP_NOT_I:%.*]] = icmp eq i32 [[SHR2_I]], [[CONV_I]] +; CHECK-NEXT: ret i1 [[CMP_NOT_I]] +; + %sh = lshr i64 %add, 32 + %conv.i = trunc i64 %sh to i32 + %conv1.i = trunc i64 %add to i32 + %shr2.i = ashr i32 %conv1.i, 31 + %cmp.not.i = icmp eq i32 %shr2.i, %conv.i + ret i1 %cmp.not.i +} + +define i1 @testi64i32_ne(i64 %add) { +; CHECK-LABEL: @testi64i32_ne( +; CHECK-NEXT: [[SH:%.*]] = lshr i64 [[ADD:%.*]], 32 +; CHECK-NEXT: [[CONV_I:%.*]] = trunc i64 [[SH]] to i32 +; CHECK-NEXT: [[CONV1_I:%.*]] = trunc i64 [[ADD]] to i32 +; CHECK-NEXT: [[SHR2_I:%.*]] = ashr i32 [[CONV1_I]], 31 +; CHECK-NEXT: [[CMP_NOT_I:%.*]] = icmp ne i32 [[SHR2_I]], [[CONV_I]] +; CHECK-NEXT: ret i1 [[CMP_NOT_I]] +; + %sh = lshr i64 %add, 32 + %conv.i = trunc i64 %sh to i32 + %conv1.i = trunc i64 %add to i32 + %shr2.i = ashr i32 %conv1.i, 31 + %cmp.not.i = icmp ne i32 %shr2.i, %conv.i + ret i1 %cmp.not.i +} + +; Negative tests + +define i1 @testi32i8(i32 %add) { +; CHECK-LABEL: @testi32i8( +; CHECK-NEXT: [[SH:%.*]] = lshr i32 [[ADD:%.*]], 8 +; CHECK-NEXT: [[CONV_I:%.*]] = trunc i32 [[SH]] to i8 +; CHECK-NEXT: [[CONV1_I:%.*]] = trunc i32 [[ADD]] to i8 +; CHECK-NEXT: [[SHR2_I:%.*]] = ashr i8 [[CONV1_I]], 7 +; CHECK-NEXT: [[CMP_NOT_I:%.*]] = icmp eq i8 [[SHR2_I]], [[CONV_I]] +; CHECK-NEXT: ret i1 [[CMP_NOT_I]] +; + %sh = lshr i32 %add, 8 + %conv.i = trunc i32 %sh to i8 + %conv1.i = trunc i32 %add to i8 + %shr2.i = ashr i8 %conv1.i, 7 + %cmp.not.i = icmp eq i8 %shr2.i, %conv.i + ret i1 %cmp.not.i +} + +define i1 @wrongimm1(i16 %add) { +; CHECK-LABEL: @wrongimm1( +; CHECK-NEXT: [[SH:%.*]] = lshr i16 [[ADD:%.*]], 7 +; CHECK-NEXT: [[CONV_I:%.*]] = trunc i16 [[SH]] to i8 +; CHECK-NEXT: [[CONV1_I:%.*]] = trunc i16 [[ADD]] to i8 +; CHECK-NEXT: [[SHR2_I:%.*]] = ashr i8 [[CONV1_I]], 7 +; CHECK-NEXT: [[CMP_NOT_I:%.*]] = icmp eq i8 [[SHR2_I]], [[CONV_I]] +; CHECK-NEXT: ret i1 [[CMP_NOT_I]] +; + %sh = lshr i16 %add, 7 + %conv.i = trunc i16 %sh to i8 + %conv1.i = trunc i16 %add to i8 + %shr2.i = ashr i8 %conv1.i, 7 + %cmp.not.i = icmp eq i8 %shr2.i, %conv.i + ret i1 %cmp.not.i +} + +define i1 @wrongimm2(i16 %add) { +; CHECK-LABEL: @wrongimm2( +; CHECK-NEXT: [[SH:%.*]] = lshr i16 [[ADD:%.*]], 8 +; CHECK-NEXT: [[CONV_I:%.*]] = trunc i16 [[SH]] to i8 +; CHECK-NEXT: [[CONV1_I:%.*]] = trunc i16 [[ADD]] to i8 +; CHECK-NEXT: [[SHR2_I:%.*]] = ashr i8 [[CONV1_I]], 6 +; CHECK-NEXT: [[CMP_NOT_I:%.*]] = icmp eq i8 [[SHR2_I]], [[CONV_I]] +; CHECK-NEXT: ret i1 [[CMP_NOT_I]] +; + %sh = lshr i16 %add, 8 + %conv.i = trunc i16 %sh to i8 + %conv1.i = trunc i16 %add to i8 + %shr2.i = ashr i8 %conv1.i, 6 + %cmp.not.i = icmp eq i8 %shr2.i, %conv.i + ret i1 %cmp.not.i +} + +define i1 @slt(i64 %add) { +; CHECK-LABEL: @slt( +; CHECK-NEXT: [[SH:%.*]] = lshr i64 [[ADD:%.*]], 32 +; CHECK-NEXT: [[CONV_I:%.*]] = trunc i64 [[SH]] to i32 +; CHECK-NEXT: [[CONV1_I:%.*]] = trunc i64 [[ADD]] to i32 +; CHECK-NEXT: [[SHR2_I:%.*]] = ashr i32 [[CONV1_I]], 31 +; CHECK-NEXT: [[CMP_NOT_I:%.*]] = icmp slt i32 [[SHR2_I]], [[CONV_I]] +; CHECK-NEXT: ret i1 [[CMP_NOT_I]] +; + %sh = lshr i64 %add, 32 + %conv.i = trunc i64 %sh to i32 + %conv1.i = trunc i64 %add to i32 + %shr2.i = ashr i32 %conv1.i, 31 + %cmp.not.i = icmp slt i32 %shr2.i, %conv.i + ret i1 %cmp.not.i +} + +; Use checks + +define i1 @extrause_a(i16 %add) { +; CHECK-LABEL: @extrause_a( +; CHECK-NEXT: [[SH:%.*]] = lshr i16 [[ADD:%.*]], 8 +; CHECK-NEXT: [[CONV_I:%.*]] = trunc i16 [[SH]] to i8 +; CHECK-NEXT: [[CONV1_I:%.*]] = trunc i16 [[ADD]] to i8 +; CHECK-NEXT: [[SHR2_I:%.*]] = ashr i8 [[CONV1_I]], 7 +; CHECK-NEXT: [[CMP_NOT_I:%.*]] = icmp eq i8 [[SHR2_I]], [[CONV_I]] +; CHECK-NEXT: call void @use(i8 [[SHR2_I]]) +; CHECK-NEXT: ret i1 [[CMP_NOT_I]] +; + %sh = lshr i16 %add, 8 + %conv.i = trunc i16 %sh to i8 + %conv1.i = trunc i16 %add to i8 + %shr2.i = ashr i8 %conv1.i, 7 + %cmp.not.i = icmp eq i8 %shr2.i, %conv.i + call void @use(i8 %shr2.i) + ret i1 %cmp.not.i +} + +define i1 @extrause_l(i16 %add) { +; CHECK-LABEL: @extrause_l( +; CHECK-NEXT: [[SH:%.*]] = lshr i16 [[ADD:%.*]], 8 +; CHECK-NEXT: [[CONV_I:%.*]] = trunc i16 [[SH]] to i8 +; CHECK-NEXT: [[CONV1_I:%.*]] = trunc i16 [[ADD]] to i8 +; CHECK-NEXT: [[SHR2_I:%.*]] = ashr i8 [[CONV1_I]], 7 +; CHECK-NEXT: [[CMP_NOT_I:%.*]] = icmp eq i8 [[SHR2_I]], [[CONV_I]] +; CHECK-NEXT: call void @use(i8 [[CONV_I]]) +; CHECK-NEXT: ret i1 [[CMP_NOT_I]] +; + %sh = lshr i16 %add, 8 + %conv.i = trunc i16 %sh to i8 + %conv1.i = trunc i16 %add to i8 + %shr2.i = ashr i8 %conv1.i, 7 + %cmp.not.i = icmp eq i8 %shr2.i, %conv.i + call void @use(i8 %conv.i) + ret i1 %cmp.not.i +} + +define i1 @extrause_la(i16 %add) { +; CHECK-LABEL: @extrause_la( +; CHECK-NEXT: [[SH:%.*]] = lshr i16 [[ADD:%.*]], 8 +; CHECK-NEXT: [[CONV_I:%.*]] = trunc i16 [[SH]] to i8 +; CHECK-NEXT: [[CONV1_I:%.*]] = trunc i16 [[ADD]] to i8 +; CHECK-NEXT: [[SHR2_I:%.*]] = ashr i8 [[CONV1_I]], 7 +; CHECK-NEXT: [[CMP_NOT_I:%.*]] = icmp eq i8 [[SHR2_I]], [[CONV_I]] +; CHECK-NEXT: call void @use(i8 [[SHR2_I]]) +; CHECK-NEXT: call void @use(i8 [[CONV_I]]) +; CHECK-NEXT: ret i1 [[CMP_NOT_I]] +; + %sh = lshr i16 %add, 8 + %conv.i = trunc i16 %sh to i8 + %conv1.i = trunc i16 %add to i8 + %shr2.i = ashr i8 %conv1.i, 7 + %cmp.not.i = icmp eq i8 %shr2.i, %conv.i + call void @use(i8 %shr2.i) + call void @use(i8 %conv.i) + ret i1 %cmp.not.i +} diff --git a/llvm/test/Transforms/InstCombine/truncating-saturate.ll b/llvm/test/Transforms/InstCombine/truncating-saturate.ll index 07899b9490cf1..06d2c208fd28e 100644 --- a/llvm/test/Transforms/InstCombine/truncating-saturate.ll +++ b/llvm/test/Transforms/InstCombine/truncating-saturate.ll @@ -583,3 +583,33 @@ define i8 @C0zero(i8 %X, i8 %y, i8 %z) { %r = select i1 %cmp, i8 %X, i8 %f ret i8 %r } + +define <2 x i8> @C0zeroV(<2 x i8> %X, <2 x i8> %y, <2 x i8> %z) { +; CHECK-LABEL: @C0zeroV( +; CHECK-NEXT: [[C:%.*]] = icmp slt <2 x i8> [[X:%.*]], +; CHECK-NEXT: [[F:%.*]] = select <2 x i1> [[C]], <2 x i8> [[Y:%.*]], <2 x i8> [[Z:%.*]] +; CHECK-NEXT: ret <2 x i8> [[F]] +; + %a = add <2 x i8> %X, + %cmp = icmp ult <2 x i8> %a, zeroinitializer + %c = icmp slt <2 x i8> %X, + %f = select <2 x i1> %c, <2 x i8> %y, <2 x i8> %z + %r = select <2 x i1> %cmp, <2 x i8> %X, <2 x i8> %f + ret <2 x i8> %r +} + +define <2 x i8> @C0zeroVu(<2 x i8> %X, <2 x i8> %y, <2 x i8> %z) { +; CHECK-LABEL: @C0zeroVu( +; CHECK-NEXT: [[TMP1:%.*]] = icmp slt <2 x i8> [[X:%.*]], +; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt <2 x i8> [[X]], +; CHECK-NEXT: [[TMP3:%.*]] = select <2 x i1> [[TMP1]], <2 x i8> [[Y:%.*]], <2 x i8> [[X]] +; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[TMP2]], <2 x i8> [[Z:%.*]], <2 x i8> [[TMP3]] +; CHECK-NEXT: ret <2 x i8> [[R]] +; + %a = add <2 x i8> %X, + %cmp = icmp ult <2 x i8> %a, + %c = icmp slt <2 x i8> %X, + %f = select <2 x i1> %c, <2 x i8> %y, <2 x i8> %z + %r = select <2 x i1> %cmp, <2 x i8> %X, <2 x i8> %f + ret <2 x i8> %r +} diff --git a/llvm/test/Transforms/InstCombine/xor-ashr.ll b/llvm/test/Transforms/InstCombine/xor-ashr.ll new file mode 100644 index 0000000000000..146206b43f1e7 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/xor-ashr.ll @@ -0,0 +1,140 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instcombine -S | FileCheck %s +target 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" + +declare void @use16(i16) +declare void @use32(i32) + +define i8 @testi8i8(i8 %add) { +; CHECK-LABEL: @testi8i8( +; CHECK-NEXT: [[SH:%.*]] = ashr i8 [[ADD:%.*]], 7 +; CHECK-NEXT: [[X:%.*]] = xor i8 [[SH]], 127 +; CHECK-NEXT: ret i8 [[X]] +; + %sh = ashr i8 %add, 7 + %x = xor i8 %sh, 127 + ret i8 %x +} + +define i8 @testi16i8(i16 %add) { +; CHECK-LABEL: @testi16i8( +; CHECK-NEXT: [[SH:%.*]] = ashr i16 [[ADD:%.*]], 15 +; CHECK-NEXT: [[T:%.*]] = trunc i16 [[SH]] to i8 +; CHECK-NEXT: [[X:%.*]] = xor i8 [[T]], 27 +; CHECK-NEXT: ret i8 [[X]] +; + %sh = ashr i16 %add, 15 + %t = trunc i16 %sh to i8 + %x = xor i8 %t, 27 + ret i8 %x +} + +define i32 @testi64i32(i64 %add) { +; CHECK-LABEL: @testi64i32( +; CHECK-NEXT: [[SH:%.*]] = ashr i64 [[ADD:%.*]], 63 +; CHECK-NEXT: [[T:%.*]] = trunc i64 [[SH]] to i32 +; CHECK-NEXT: [[X:%.*]] = xor i32 [[T]], 127 +; CHECK-NEXT: ret i32 [[X]] +; + %sh = ashr i64 %add, 63 + %t = trunc i64 %sh to i32 + %x = xor i32 %t, 127 + ret i32 %x +} + +define i128 @testi128i128(i128 %add) { +; CHECK-LABEL: @testi128i128( +; CHECK-NEXT: [[SH:%.*]] = ashr i128 [[ADD:%.*]], 127 +; CHECK-NEXT: [[X:%.*]] = xor i128 [[SH]], 27 +; CHECK-NEXT: ret i128 [[X]] +; + %sh = ashr i128 %add, 127 + %x = xor i128 %sh, 27 + ret i128 %x +} + +define <4 x i8> @testv4i16i8(<4 x i16> %add) { +; CHECK-LABEL: @testv4i16i8( +; CHECK-NEXT: [[SH:%.*]] = ashr <4 x i16> [[ADD:%.*]], +; CHECK-NEXT: [[T:%.*]] = trunc <4 x i16> [[SH]] to <4 x i8> +; CHECK-NEXT: [[X:%.*]] = xor <4 x i8> [[T]], +; CHECK-NEXT: ret <4 x i8> [[X]] +; + %sh = ashr <4 x i16> %add, + %t = trunc <4 x i16> %sh to <4 x i8> + %x = xor <4 x i8> %t, + ret <4 x i8> %x +} + +define <4 x i8> @testv4i16i8_undef(<4 x i16> %add) { +; CHECK-LABEL: @testv4i16i8_undef( +; CHECK-NEXT: [[SH:%.*]] = ashr <4 x i16> [[ADD:%.*]], +; CHECK-NEXT: [[T:%.*]] = trunc <4 x i16> [[SH]] to <4 x i8> +; CHECK-NEXT: [[X:%.*]] = xor <4 x i8> [[T]], +; CHECK-NEXT: ret <4 x i8> [[X]] +; + %sh = ashr <4 x i16> %add, + %t = trunc <4 x i16> %sh to <4 x i8> + %x = xor <4 x i8> %t, + ret <4 x i8> %x +} + +; Negative tests + +define i8 @wrongimm(i16 %add) { +; CHECK-LABEL: @wrongimm( +; CHECK-NEXT: [[SH:%.*]] = ashr i16 [[ADD:%.*]], 14 +; CHECK-NEXT: [[T:%.*]] = trunc i16 [[SH]] to i8 +; CHECK-NEXT: [[X:%.*]] = xor i8 [[T]], 27 +; CHECK-NEXT: ret i8 [[X]] +; + %sh = ashr i16 %add, 14 + %t = trunc i16 %sh to i8 + %x = xor i8 %t, 27 + ret i8 %x +} + +; One use + +define i16 @extrause(i16 %add) { +; CHECK-LABEL: @extrause( +; CHECK-NEXT: [[SH:%.*]] = ashr i16 [[ADD:%.*]], 15 +; CHECK-NEXT: [[X:%.*]] = xor i16 [[SH]], 27 +; CHECK-NEXT: call void @use16(i16 [[SH]]) +; CHECK-NEXT: ret i16 [[X]] +; + %sh = ashr i16 %add, 15 + %x = xor i16 %sh, 27 + call void @use16(i16 %sh) + ret i16 %x +} + +define i16 @extrause_trunc1(i32 %add) { +; CHECK-LABEL: @extrause_trunc1( +; CHECK-NEXT: [[SH:%.*]] = ashr i32 [[ADD:%.*]], 31 +; CHECK-NEXT: [[T:%.*]] = trunc i32 [[SH]] to i16 +; CHECK-NEXT: call void @use32(i32 [[SH]]) +; CHECK-NEXT: [[X:%.*]] = xor i16 [[T]], 127 +; CHECK-NEXT: ret i16 [[X]] +; + %sh = ashr i32 %add, 31 + %t = trunc i32 %sh to i16 + call void @use32(i32 %sh) + %x = xor i16 %t, 127 + ret i16 %x +} + +define i16 @extrause_trunc2(i32 %add) { +; CHECK-LABEL: @extrause_trunc2( +; CHECK-NEXT: [[SH:%.*]] = ashr i32 [[ADD:%.*]], 31 +; CHECK-NEXT: [[T:%.*]] = trunc i32 [[SH]] to i16 +; CHECK-NEXT: call void @use16(i16 [[T]]) +; CHECK-NEXT: [[X:%.*]] = xor i16 [[T]], 127 +; CHECK-NEXT: ret i16 [[X]] +; + %sh = ashr i32 %add, 31 + %t = trunc i32 %sh to i16 + call void @use16(i16 %t) + %x = xor i16 %t, 127 + ret i16 %x +}