From c45f92289b71b36cfba2b2e8e14547b3e04f8c21 Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Sun, 13 Oct 2019 17:11:16 +0000 Subject: [PATCH] [NFC][InstCombine] More test for "sign bit test via shifts" pattern (PR43595) While that pattern is indirectly handled via reassociateShiftAmtsOfTwoSameDirectionShifts(), that incursme one-use restriction on truncation, which is pointless since we know that we'll produce a single instruction. Additionally, *if* we are only looking for sign bit, we don't need shifts to be identical, which isn't the case in general, and is the blocker for me in bug in question: https://bugs.llvm.org/show_bug.cgi?id=43595 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@374726 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../shift-amount-reassociation-in-bittest.ll | 8 + ...ount-reassociation-with-truncation-ashr.ll | 26 ++- ...ount-reassociation-with-truncation-lshr.ll | 26 ++- ...mount-reassociation-with-truncation-shl.ll | 8 +- .../InstCombine/shift-amount-reassociation.ll | 116 ++++++++++ ...-test-via-right-shifting-all-other-bits.ll | 206 +++++++++++++++++- 6 files changed, 377 insertions(+), 13 deletions(-) diff --git a/test/Transforms/InstCombine/shift-amount-reassociation-in-bittest.ll b/test/Transforms/InstCombine/shift-amount-reassociation-in-bittest.ll index 9a2cfa5977a..27224705929 100644 --- a/test/Transforms/InstCombine/shift-amount-reassociation-in-bittest.ll +++ b/test/Transforms/InstCombine/shift-amount-reassociation-in-bittest.ll @@ -671,6 +671,14 @@ define <2 x i1> @n38_overshift(<2 x i32> %x, <2 x i32> %y) { ; As usual, don't crash given constantexpr's :/ @f.a = internal global i16 0 define i1 @constantexpr() { +; CHECK-LABEL: @constantexpr( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = load i16, i16* @f.a, align 2 +; CHECK-NEXT: [[TMP1:%.*]] = lshr i16 [[TMP0]], 1 +; CHECK-NEXT: [[TMP2:%.*]] = and i16 [[TMP1]], shl (i16 1, i16 zext (i1 icmp ne (i16 ptrtoint (i16* @f.a to i16), i16 1) to i16)) +; CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i16 [[TMP2]], 0 +; CHECK-NEXT: ret i1 [[TOBOOL]] +; entry: %0 = load i16, i16* @f.a %shr = ashr i16 %0, 1 diff --git a/test/Transforms/InstCombine/shift-amount-reassociation-with-truncation-ashr.ll b/test/Transforms/InstCombine/shift-amount-reassociation-with-truncation-ashr.ll index a0175387d1c..c4e337548d1 100644 --- a/test/Transforms/InstCombine/shift-amount-reassociation-with-truncation-ashr.ll +++ b/test/Transforms/InstCombine/shift-amount-reassociation-with-truncation-ashr.ll @@ -166,7 +166,9 @@ define i16 @t9_ashr(i32 %x, i16 %y) { ; CHECK-NEXT: [[T1:%.*]] = zext i16 [[T0]] to i32 ; CHECK-NEXT: [[T2:%.*]] = ashr i32 [[X:%.*]], [[T1]] ; CHECK-NEXT: [[T3:%.*]] = trunc i32 [[T2]] to i16 -; CHECK-NEXT: ret i16 [[T3]] +; CHECK-NEXT: [[T4:%.*]] = add i16 [[Y]], -2 +; CHECK-NEXT: [[T5:%.*]] = ashr i16 [[T3]], [[T4]] +; CHECK-NEXT: ret i16 [[T5]] ; %t0 = sub i16 32, %y %t1 = zext i16 %t0 to i32 @@ -174,5 +176,25 @@ define i16 @t9_ashr(i32 %x, i16 %y) { %t3 = trunc i32 %t2 to i16 %t4 = add i16 %y, -2 %t5 = ashr i16 %t3, %t4 - ret i16 %t3 + ret i16 %t5 +} + +; If we have different right-shifts, in general, we can't do anything with it. +define i16 @n10_lshr_ashr(i32 %x, i16 %y) { +; CHECK-LABEL: @n10_lshr_ashr( +; CHECK-NEXT: [[T0:%.*]] = sub i16 32, [[Y:%.*]] +; CHECK-NEXT: [[T1:%.*]] = zext i16 [[T0]] to i32 +; CHECK-NEXT: [[T2:%.*]] = lshr i32 [[X:%.*]], [[T1]] +; CHECK-NEXT: [[T3:%.*]] = trunc i32 [[T2]] to i16 +; CHECK-NEXT: [[T4:%.*]] = add i16 [[Y]], -1 +; CHECK-NEXT: [[T5:%.*]] = ashr i16 [[T3]], [[T4]] +; CHECK-NEXT: ret i16 [[T5]] +; + %t0 = sub i16 32, %y + %t1 = zext i16 %t0 to i32 + %t2 = lshr i32 %x, %t1 + %t3 = trunc i32 %t2 to i16 + %t4 = add i16 %y, -1 + %t5 = ashr i16 %t3, %t4 + ret i16 %t5 } diff --git a/test/Transforms/InstCombine/shift-amount-reassociation-with-truncation-lshr.ll b/test/Transforms/InstCombine/shift-amount-reassociation-with-truncation-lshr.ll index 7b9962eacb1..edb34fbb9e9 100644 --- a/test/Transforms/InstCombine/shift-amount-reassociation-with-truncation-lshr.ll +++ b/test/Transforms/InstCombine/shift-amount-reassociation-with-truncation-lshr.ll @@ -166,7 +166,9 @@ define i16 @t9_lshr(i32 %x, i16 %y) { ; CHECK-NEXT: [[T1:%.*]] = zext i16 [[T0]] to i32 ; CHECK-NEXT: [[T2:%.*]] = lshr i32 [[X:%.*]], [[T1]] ; CHECK-NEXT: [[T3:%.*]] = trunc i32 [[T2]] to i16 -; CHECK-NEXT: ret i16 [[T3]] +; CHECK-NEXT: [[T4:%.*]] = add i16 [[Y]], -2 +; CHECK-NEXT: [[T5:%.*]] = lshr i16 [[T3]], [[T4]] +; CHECK-NEXT: ret i16 [[T5]] ; %t0 = sub i16 32, %y %t1 = zext i16 %t0 to i32 @@ -174,5 +176,25 @@ define i16 @t9_lshr(i32 %x, i16 %y) { %t3 = trunc i32 %t2 to i16 %t4 = add i16 %y, -2 %t5 = lshr i16 %t3, %t4 - ret i16 %t3 + ret i16 %t5 +} + +; If we have different right-shifts, in general, we can't do anything with it. +define i16 @n10_ashr_lshr(i32 %x, i16 %y) { +; CHECK-LABEL: @n10_ashr_lshr( +; CHECK-NEXT: [[T0:%.*]] = sub i16 32, [[Y:%.*]] +; CHECK-NEXT: [[T1:%.*]] = zext i16 [[T0]] to i32 +; CHECK-NEXT: [[T2:%.*]] = ashr i32 [[X:%.*]], [[T1]] +; CHECK-NEXT: [[T3:%.*]] = trunc i32 [[T2]] to i16 +; CHECK-NEXT: [[T4:%.*]] = add i16 [[Y]], -1 +; CHECK-NEXT: [[T5:%.*]] = lshr i16 [[T3]], [[T4]] +; CHECK-NEXT: ret i16 [[T5]] +; + %t0 = sub i16 32, %y + %t1 = zext i16 %t0 to i32 + %t2 = ashr i32 %x, %t1 + %t3 = trunc i32 %t2 to i16 + %t4 = add i16 %y, -1 + %t5 = lshr i16 %t3, %t4 + ret i16 %t5 } diff --git a/test/Transforms/InstCombine/shift-amount-reassociation-with-truncation-shl.ll b/test/Transforms/InstCombine/shift-amount-reassociation-with-truncation-shl.ll index 2328ec7965e..7ae9b76fa5f 100644 --- a/test/Transforms/InstCombine/shift-amount-reassociation-with-truncation-shl.ll +++ b/test/Transforms/InstCombine/shift-amount-reassociation-with-truncation-shl.ll @@ -181,15 +181,17 @@ define i16 @n11(i32 %x, i16 %y) { ; CHECK-NEXT: [[T1:%.*]] = zext i16 [[T0]] to i32 ; CHECK-NEXT: [[T2:%.*]] = shl i32 [[X:%.*]], [[T1]] ; CHECK-NEXT: [[T3:%.*]] = trunc i32 [[T2]] to i16 -; CHECK-NEXT: ret i16 [[T3]] +; CHECK-NEXT: [[T4:%.*]] = add i16 [[Y]], -31 +; CHECK-NEXT: [[T5:%.*]] = shl i16 [[T3]], [[T4]] +; CHECK-NEXT: ret i16 [[T5]] ; %t0 = sub i16 30, %y %t1 = zext i16 %t0 to i32 %t2 = shl i32 %x, %t1 %t3 = trunc i32 %t2 to i16 - %t4 = add i16 %y, -24 + %t4 = add i16 %y, -31 %t5 = shl i16 %t3, %t4 - ret i16 %t3 + ret i16 %t5 } ; Bit width mismatch of shit amount diff --git a/test/Transforms/InstCombine/shift-amount-reassociation.ll b/test/Transforms/InstCombine/shift-amount-reassociation.ll index e124a035861..6e54133bacc 100644 --- a/test/Transforms/InstCombine/shift-amount-reassociation.ll +++ b/test/Transforms/InstCombine/shift-amount-reassociation.ll @@ -203,3 +203,119 @@ define <2 x i32> @t13_vec(<2 x i32> %x, <2 x i32> %y) { %t3 = lshr <2 x i32> %t1, %t2 ret <2 x i32> %t3 } + +; If we have different right-shifts, in general, we can't do anything with it. +define i32 @n13(i32 %x, i32 %y) { +; CHECK-LABEL: @n13( +; CHECK-NEXT: [[T0:%.*]] = sub i32 32, [[Y:%.*]] +; CHECK-NEXT: [[T1:%.*]] = lshr i32 [[X:%.*]], [[T0]] +; CHECK-NEXT: [[T2:%.*]] = add i32 [[Y]], -2 +; CHECK-NEXT: [[T3:%.*]] = ashr i32 [[T1]], [[T2]] +; CHECK-NEXT: ret i32 [[T3]] +; + %t0 = sub i32 32, %y + %t1 = lshr i32 %x, %t0 + %t2 = add i32 %y, -2 + %t3 = ashr i32 %t1, %t2 + ret i32 %t3 +} +define i32 @n14(i32 %x, i32 %y) { +; CHECK-LABEL: @n14( +; CHECK-NEXT: [[T0:%.*]] = sub i32 32, [[Y:%.*]] +; CHECK-NEXT: [[T1:%.*]] = lshr i32 [[X:%.*]], [[T0]] +; CHECK-NEXT: [[T2:%.*]] = add i32 [[Y]], -1 +; CHECK-NEXT: [[T3:%.*]] = ashr i32 [[T1]], [[T2]] +; CHECK-NEXT: ret i32 [[T3]] +; + %t0 = sub i32 32, %y + %t1 = lshr i32 %x, %t0 + %t2 = add i32 %y, -1 + %t3 = ashr i32 %t1, %t2 + ret i32 %t3 +} +define i32 @n15(i32 %x, i32 %y) { +; CHECK-LABEL: @n15( +; CHECK-NEXT: [[T0:%.*]] = sub i32 32, [[Y:%.*]] +; CHECK-NEXT: [[T1:%.*]] = ashr i32 [[X:%.*]], [[T0]] +; CHECK-NEXT: [[T2:%.*]] = add i32 [[Y]], -2 +; CHECK-NEXT: [[T3:%.*]] = lshr i32 [[T1]], [[T2]] +; CHECK-NEXT: ret i32 [[T3]] +; + %t0 = sub i32 32, %y + %t1 = ashr i32 %x, %t0 + %t2 = add i32 %y, -2 + %t3 = lshr i32 %t1, %t2 + ret i32 %t3 +} +define i32 @n16(i32 %x, i32 %y) { +; CHECK-LABEL: @n16( +; CHECK-NEXT: [[T0:%.*]] = sub i32 32, [[Y:%.*]] +; CHECK-NEXT: [[T1:%.*]] = ashr i32 [[X:%.*]], [[T0]] +; CHECK-NEXT: [[T2:%.*]] = add i32 [[Y]], -1 +; CHECK-NEXT: [[T3:%.*]] = lshr i32 [[T1]], [[T2]] +; CHECK-NEXT: ret i32 [[T3]] +; + %t0 = sub i32 32, %y + %t1 = ashr i32 %x, %t0 + %t2 = add i32 %y, -1 + %t3 = lshr i32 %t1, %t2 + ret i32 %t3 +} + +; If the shift direction is different, then this should be handled elsewhere. +define i32 @n17(i32 %x, i32 %y) { +; CHECK-LABEL: @n17( +; CHECK-NEXT: [[T0:%.*]] = sub i32 32, [[Y:%.*]] +; CHECK-NEXT: [[T1:%.*]] = shl i32 [[X:%.*]], [[T0]] +; CHECK-NEXT: [[T2:%.*]] = add i32 [[Y]], -1 +; CHECK-NEXT: [[T3:%.*]] = lshr i32 [[T1]], [[T2]] +; CHECK-NEXT: ret i32 [[T3]] +; + %t0 = sub i32 32, %y + %t1 = shl i32 %x, %t0 + %t2 = add i32 %y, -1 + %t3 = lshr i32 %t1, %t2 + ret i32 %t3 +} +define i32 @n18(i32 %x, i32 %y) { +; CHECK-LABEL: @n18( +; CHECK-NEXT: [[T0:%.*]] = sub i32 32, [[Y:%.*]] +; CHECK-NEXT: [[T1:%.*]] = shl i32 [[X:%.*]], [[T0]] +; CHECK-NEXT: [[T2:%.*]] = add i32 [[Y]], -1 +; CHECK-NEXT: [[T3:%.*]] = ashr i32 [[T1]], [[T2]] +; CHECK-NEXT: ret i32 [[T3]] +; + %t0 = sub i32 32, %y + %t1 = shl i32 %x, %t0 + %t2 = add i32 %y, -1 + %t3 = ashr i32 %t1, %t2 + ret i32 %t3 +} +define i32 @n19(i32 %x, i32 %y) { +; CHECK-LABEL: @n19( +; CHECK-NEXT: [[T0:%.*]] = sub i32 32, [[Y:%.*]] +; CHECK-NEXT: [[T1:%.*]] = lshr i32 [[X:%.*]], [[T0]] +; CHECK-NEXT: [[T2:%.*]] = add i32 [[Y]], -1 +; CHECK-NEXT: [[T3:%.*]] = shl i32 [[T1]], [[T2]] +; CHECK-NEXT: ret i32 [[T3]] +; + %t0 = sub i32 32, %y + %t1 = lshr i32 %x, %t0 + %t2 = add i32 %y, -1 + %t3 = shl i32 %t1, %t2 + ret i32 %t3 +} +define i32 @n20(i32 %x, i32 %y) { +; CHECK-LABEL: @n20( +; CHECK-NEXT: [[T0:%.*]] = sub i32 32, [[Y:%.*]] +; CHECK-NEXT: [[T1:%.*]] = ashr i32 [[X:%.*]], [[T0]] +; CHECK-NEXT: [[T2:%.*]] = add i32 [[Y]], -1 +; CHECK-NEXT: [[T3:%.*]] = shl i32 [[T1]], [[T2]] +; CHECK-NEXT: ret i32 [[T3]] +; + %t0 = sub i32 32, %y + %t1 = ashr i32 %x, %t0 + %t2 = add i32 %y, -1 + %t3 = shl i32 %t1, %t2 + ret i32 %t3 +} diff --git a/test/Transforms/InstCombine/sign-bit-test-via-right-shifting-all-other-bits.ll b/test/Transforms/InstCombine/sign-bit-test-via-right-shifting-all-other-bits.ll index c6507afab1f..0e5848e7303 100644 --- a/test/Transforms/InstCombine/sign-bit-test-via-right-shifting-all-other-bits.ll +++ b/test/Transforms/InstCombine/sign-bit-test-via-right-shifting-all-other-bits.ll @@ -1,22 +1,51 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt < %s -instcombine -S | FileCheck %s +declare void @use32(i32) +declare void @use64(i64) + define i1 @highest_bit_test_via_lshr(i32 %data, i32 %nbits) { ; CHECK-LABEL: @highest_bit_test_via_lshr( -; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i32 [[DATA:%.*]], 0 +; CHECK-NEXT: [[NUM_LOW_BITS_TO_SKIP:%.*]] = sub i32 32, [[NBITS:%.*]] +; CHECK-NEXT: [[HIGH_BITS_EXTRACTED:%.*]] = lshr i32 [[DATA:%.*]], [[NUM_LOW_BITS_TO_SKIP]] +; CHECK-NEXT: [[SKIP_ALL_BITS_TILL_SIGNBIT:%.*]] = add i32 [[NBITS]], -1 +; CHECK-NEXT: [[SIGNBIT:%.*]] = lshr i32 [[DATA]], 31 +; CHECK-NEXT: call void @use32(i32 [[NUM_LOW_BITS_TO_SKIP]]) +; CHECK-NEXT: call void @use32(i32 [[HIGH_BITS_EXTRACTED]]) +; CHECK-NEXT: call void @use32(i32 [[SKIP_ALL_BITS_TILL_SIGNBIT]]) +; CHECK-NEXT: call void @use32(i32 [[SIGNBIT]]) +; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i32 [[DATA]], 0 ; CHECK-NEXT: ret i1 [[ISNEG]] ; %num_low_bits_to_skip = sub i32 32, %nbits %high_bits_extracted = lshr i32 %data, %num_low_bits_to_skip %skip_all_bits_till_signbit = sub i32 %nbits, 1 %signbit = lshr i32 %high_bits_extracted, %skip_all_bits_till_signbit + + call void @use32(i32 %num_low_bits_to_skip) + call void @use32(i32 %high_bits_extracted) + call void @use32(i32 %skip_all_bits_till_signbit) + call void @use32(i32 %signbit) + %isneg = icmp ne i32 %signbit, 0 ret i1 %isneg } define i1 @highest_bit_test_via_lshr_with_truncation(i64 %data, i32 %nbits) { ; CHECK-LABEL: @highest_bit_test_via_lshr_with_truncation( -; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i64 [[DATA:%.*]], 0 +; CHECK-NEXT: [[NUM_LOW_BITS_TO_SKIP:%.*]] = sub i32 64, [[NBITS:%.*]] +; CHECK-NEXT: [[NUM_LOW_BITS_TO_SKIP_WIDE:%.*]] = zext i32 [[NUM_LOW_BITS_TO_SKIP]] to i64 +; CHECK-NEXT: [[HIGH_BITS_EXTRACTED:%.*]] = lshr i64 [[DATA:%.*]], [[NUM_LOW_BITS_TO_SKIP_WIDE]] +; CHECK-NEXT: [[HIGH_BITS_EXTRACTED_NARROW:%.*]] = trunc i64 [[HIGH_BITS_EXTRACTED]] to i32 +; CHECK-NEXT: [[SKIP_ALL_BITS_TILL_SIGNBIT:%.*]] = add i32 [[NBITS]], -1 +; CHECK-NEXT: [[SIGNBIT:%.*]] = lshr i32 [[HIGH_BITS_EXTRACTED_NARROW]], [[SKIP_ALL_BITS_TILL_SIGNBIT]] +; CHECK-NEXT: call void @use32(i32 [[NUM_LOW_BITS_TO_SKIP]]) +; CHECK-NEXT: call void @use64(i64 [[NUM_LOW_BITS_TO_SKIP_WIDE]]) +; CHECK-NEXT: call void @use64(i64 [[HIGH_BITS_EXTRACTED]]) +; CHECK-NEXT: call void @use32(i32 [[HIGH_BITS_EXTRACTED_NARROW]]) +; CHECK-NEXT: call void @use32(i32 [[SKIP_ALL_BITS_TILL_SIGNBIT]]) +; CHECK-NEXT: call void @use32(i32 [[SIGNBIT]]) +; CHECK-NEXT: [[ISNEG:%.*]] = icmp ne i32 [[SIGNBIT]], 0 ; CHECK-NEXT: ret i1 [[ISNEG]] ; %num_low_bits_to_skip = sub i32 64, %nbits @@ -25,26 +54,60 @@ define i1 @highest_bit_test_via_lshr_with_truncation(i64 %data, i32 %nbits) { %high_bits_extracted_narrow = trunc i64 %high_bits_extracted to i32 %skip_all_bits_till_signbit = sub i32 %nbits, 1 %signbit = lshr i32 %high_bits_extracted_narrow, %skip_all_bits_till_signbit + + call void @use32(i32 %num_low_bits_to_skip) + call void @use64(i64 %num_low_bits_to_skip_wide) + call void @use64(i64 %high_bits_extracted) + call void @use32(i32 %high_bits_extracted_narrow) + call void @use32(i32 %skip_all_bits_till_signbit) + call void @use32(i32 %signbit) + %isneg = icmp ne i32 %signbit, 0 ret i1 %isneg } define i1 @highest_bit_test_via_ashr(i32 %data, i32 %nbits) { ; CHECK-LABEL: @highest_bit_test_via_ashr( -; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i32 [[DATA:%.*]], 0 +; CHECK-NEXT: [[NUM_LOW_BITS_TO_SKIP:%.*]] = sub i32 32, [[NBITS:%.*]] +; CHECK-NEXT: [[HIGH_BITS_EXTRACTED:%.*]] = ashr i32 [[DATA:%.*]], [[NUM_LOW_BITS_TO_SKIP]] +; CHECK-NEXT: [[SKIP_ALL_BITS_TILL_SIGNBIT:%.*]] = add i32 [[NBITS]], -1 +; CHECK-NEXT: [[SIGNBIT:%.*]] = ashr i32 [[DATA]], 31 +; CHECK-NEXT: call void @use32(i32 [[NUM_LOW_BITS_TO_SKIP]]) +; CHECK-NEXT: call void @use32(i32 [[HIGH_BITS_EXTRACTED]]) +; CHECK-NEXT: call void @use32(i32 [[SKIP_ALL_BITS_TILL_SIGNBIT]]) +; CHECK-NEXT: call void @use32(i32 [[SIGNBIT]]) +; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i32 [[DATA]], 0 ; CHECK-NEXT: ret i1 [[ISNEG]] ; %num_low_bits_to_skip = sub i32 32, %nbits %high_bits_extracted = ashr i32 %data, %num_low_bits_to_skip %skip_all_bits_till_signbit = sub i32 %nbits, 1 %signbit = ashr i32 %high_bits_extracted, %skip_all_bits_till_signbit + + call void @use32(i32 %num_low_bits_to_skip) + call void @use32(i32 %high_bits_extracted) + call void @use32(i32 %skip_all_bits_till_signbit) + call void @use32(i32 %signbit) + %isneg = icmp ne i32 %signbit, 0 ret i1 %isneg } define i1 @highest_bit_test_via_ashr_with_truncation(i64 %data, i32 %nbits) { ; CHECK-LABEL: @highest_bit_test_via_ashr_with_truncation( -; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i64 [[DATA:%.*]], 0 +; CHECK-NEXT: [[NUM_LOW_BITS_TO_SKIP:%.*]] = sub i32 64, [[NBITS:%.*]] +; CHECK-NEXT: [[NUM_LOW_BITS_TO_SKIP_WIDE:%.*]] = zext i32 [[NUM_LOW_BITS_TO_SKIP]] to i64 +; CHECK-NEXT: [[HIGH_BITS_EXTRACTED:%.*]] = ashr i64 [[DATA:%.*]], [[NUM_LOW_BITS_TO_SKIP_WIDE]] +; CHECK-NEXT: [[HIGH_BITS_EXTRACTED_NARROW:%.*]] = trunc i64 [[HIGH_BITS_EXTRACTED]] to i32 +; CHECK-NEXT: [[SKIP_ALL_BITS_TILL_SIGNBIT:%.*]] = add i32 [[NBITS]], -1 +; CHECK-NEXT: [[SIGNBIT:%.*]] = ashr i32 [[HIGH_BITS_EXTRACTED_NARROW]], [[SKIP_ALL_BITS_TILL_SIGNBIT]] +; CHECK-NEXT: call void @use32(i32 [[NUM_LOW_BITS_TO_SKIP]]) +; CHECK-NEXT: call void @use64(i64 [[NUM_LOW_BITS_TO_SKIP_WIDE]]) +; CHECK-NEXT: call void @use64(i64 [[HIGH_BITS_EXTRACTED]]) +; CHECK-NEXT: call void @use32(i32 [[HIGH_BITS_EXTRACTED_NARROW]]) +; CHECK-NEXT: call void @use32(i32 [[SKIP_ALL_BITS_TILL_SIGNBIT]]) +; CHECK-NEXT: call void @use32(i32 [[SIGNBIT]]) +; CHECK-NEXT: [[ISNEG:%.*]] = icmp ne i32 [[SIGNBIT]], 0 ; CHECK-NEXT: ret i1 [[ISNEG]] ; %num_low_bits_to_skip = sub i32 64, %nbits @@ -53,12 +116,143 @@ define i1 @highest_bit_test_via_ashr_with_truncation(i64 %data, i32 %nbits) { %high_bits_extracted_narrow = trunc i64 %high_bits_extracted to i32 %skip_all_bits_till_signbit = sub i32 %nbits, 1 %signbit = ashr i32 %high_bits_extracted_narrow, %skip_all_bits_till_signbit + + call void @use32(i32 %num_low_bits_to_skip) + call void @use64(i64 %num_low_bits_to_skip_wide) + call void @use64(i64 %high_bits_extracted) + call void @use32(i32 %high_bits_extracted_narrow) + call void @use32(i32 %skip_all_bits_till_signbit) + call void @use32(i32 %signbit) + %isneg = icmp ne i32 %signbit, 0 ret i1 %isneg } -declare void @use32(i32) -declare void @use64(i64) +define i1 @highest_bit_test_via_lshr_ashr(i32 %data, i32 %nbits) { +; CHECK-LABEL: @highest_bit_test_via_lshr_ashr( +; CHECK-NEXT: [[NUM_LOW_BITS_TO_SKIP:%.*]] = sub i32 32, [[NBITS:%.*]] +; CHECK-NEXT: [[HIGH_BITS_EXTRACTED:%.*]] = lshr i32 [[DATA:%.*]], [[NUM_LOW_BITS_TO_SKIP]] +; CHECK-NEXT: [[SKIP_ALL_BITS_TILL_SIGNBIT:%.*]] = add i32 [[NBITS]], -1 +; CHECK-NEXT: [[SIGNBIT:%.*]] = ashr i32 [[HIGH_BITS_EXTRACTED]], [[SKIP_ALL_BITS_TILL_SIGNBIT]] +; CHECK-NEXT: call void @use32(i32 [[NUM_LOW_BITS_TO_SKIP]]) +; CHECK-NEXT: call void @use32(i32 [[HIGH_BITS_EXTRACTED]]) +; CHECK-NEXT: call void @use32(i32 [[SKIP_ALL_BITS_TILL_SIGNBIT]]) +; CHECK-NEXT: call void @use32(i32 [[SIGNBIT]]) +; CHECK-NEXT: [[ISNEG:%.*]] = icmp ne i32 [[SIGNBIT]], 0 +; CHECK-NEXT: ret i1 [[ISNEG]] +; + %num_low_bits_to_skip = sub i32 32, %nbits + %high_bits_extracted = lshr i32 %data, %num_low_bits_to_skip + %skip_all_bits_till_signbit = sub i32 %nbits, 1 + %signbit = ashr i32 %high_bits_extracted, %skip_all_bits_till_signbit + + call void @use32(i32 %num_low_bits_to_skip) + call void @use32(i32 %high_bits_extracted) + call void @use32(i32 %skip_all_bits_till_signbit) + call void @use32(i32 %signbit) + + %isneg = icmp ne i32 %signbit, 0 + ret i1 %isneg +} + +define i1 @highest_bit_test_via_lshr_ashe_with_truncation(i64 %data, i32 %nbits) { +; CHECK-LABEL: @highest_bit_test_via_lshr_ashe_with_truncation( +; CHECK-NEXT: [[NUM_LOW_BITS_TO_SKIP:%.*]] = sub i32 64, [[NBITS:%.*]] +; CHECK-NEXT: [[NUM_LOW_BITS_TO_SKIP_WIDE:%.*]] = zext i32 [[NUM_LOW_BITS_TO_SKIP]] to i64 +; CHECK-NEXT: [[HIGH_BITS_EXTRACTED:%.*]] = lshr i64 [[DATA:%.*]], [[NUM_LOW_BITS_TO_SKIP_WIDE]] +; CHECK-NEXT: [[HIGH_BITS_EXTRACTED_NARROW:%.*]] = trunc i64 [[HIGH_BITS_EXTRACTED]] to i32 +; CHECK-NEXT: [[SKIP_ALL_BITS_TILL_SIGNBIT:%.*]] = add i32 [[NBITS]], -1 +; CHECK-NEXT: [[SIGNBIT:%.*]] = ashr i32 [[HIGH_BITS_EXTRACTED_NARROW]], [[SKIP_ALL_BITS_TILL_SIGNBIT]] +; CHECK-NEXT: call void @use32(i32 [[NUM_LOW_BITS_TO_SKIP]]) +; CHECK-NEXT: call void @use64(i64 [[NUM_LOW_BITS_TO_SKIP_WIDE]]) +; CHECK-NEXT: call void @use64(i64 [[HIGH_BITS_EXTRACTED]]) +; CHECK-NEXT: call void @use32(i32 [[HIGH_BITS_EXTRACTED_NARROW]]) +; CHECK-NEXT: call void @use32(i32 [[SKIP_ALL_BITS_TILL_SIGNBIT]]) +; CHECK-NEXT: call void @use32(i32 [[SIGNBIT]]) +; CHECK-NEXT: [[ISNEG:%.*]] = icmp ne i32 [[SIGNBIT]], 0 +; CHECK-NEXT: ret i1 [[ISNEG]] +; + %num_low_bits_to_skip = sub i32 64, %nbits + %num_low_bits_to_skip_wide = zext i32 %num_low_bits_to_skip to i64 + %high_bits_extracted = lshr i64 %data, %num_low_bits_to_skip_wide + %high_bits_extracted_narrow = trunc i64 %high_bits_extracted to i32 + %skip_all_bits_till_signbit = sub i32 %nbits, 1 + %signbit = ashr i32 %high_bits_extracted_narrow, %skip_all_bits_till_signbit + + call void @use32(i32 %num_low_bits_to_skip) + call void @use64(i64 %num_low_bits_to_skip_wide) + call void @use64(i64 %high_bits_extracted) + call void @use32(i32 %high_bits_extracted_narrow) + call void @use32(i32 %skip_all_bits_till_signbit) + call void @use32(i32 %signbit) + + %isneg = icmp ne i32 %signbit, 0 + ret i1 %isneg +} + +define i1 @highest_bit_test_via_ashr_lshr(i32 %data, i32 %nbits) { +; CHECK-LABEL: @highest_bit_test_via_ashr_lshr( +; CHECK-NEXT: [[NUM_LOW_BITS_TO_SKIP:%.*]] = sub i32 32, [[NBITS:%.*]] +; CHECK-NEXT: [[HIGH_BITS_EXTRACTED:%.*]] = ashr i32 [[DATA:%.*]], [[NUM_LOW_BITS_TO_SKIP]] +; CHECK-NEXT: [[SKIP_ALL_BITS_TILL_SIGNBIT:%.*]] = add i32 [[NBITS]], -1 +; CHECK-NEXT: [[SIGNBIT:%.*]] = lshr i32 [[HIGH_BITS_EXTRACTED]], [[SKIP_ALL_BITS_TILL_SIGNBIT]] +; CHECK-NEXT: call void @use32(i32 [[NUM_LOW_BITS_TO_SKIP]]) +; CHECK-NEXT: call void @use32(i32 [[HIGH_BITS_EXTRACTED]]) +; CHECK-NEXT: call void @use32(i32 [[SKIP_ALL_BITS_TILL_SIGNBIT]]) +; CHECK-NEXT: call void @use32(i32 [[SIGNBIT]]) +; CHECK-NEXT: [[ISNEG:%.*]] = icmp ne i32 [[SIGNBIT]], 0 +; CHECK-NEXT: ret i1 [[ISNEG]] +; + %num_low_bits_to_skip = sub i32 32, %nbits + %high_bits_extracted = ashr i32 %data, %num_low_bits_to_skip + %skip_all_bits_till_signbit = sub i32 %nbits, 1 + %signbit = lshr i32 %high_bits_extracted, %skip_all_bits_till_signbit + + call void @use32(i32 %num_low_bits_to_skip) + call void @use32(i32 %high_bits_extracted) + call void @use32(i32 %skip_all_bits_till_signbit) + call void @use32(i32 %signbit) + + %isneg = icmp ne i32 %signbit, 0 + ret i1 %isneg +} + +define i1 @highest_bit_test_via_ashr_lshr_with_truncation(i64 %data, i32 %nbits) { +; CHECK-LABEL: @highest_bit_test_via_ashr_lshr_with_truncation( +; CHECK-NEXT: [[NUM_LOW_BITS_TO_SKIP:%.*]] = sub i32 64, [[NBITS:%.*]] +; CHECK-NEXT: [[NUM_LOW_BITS_TO_SKIP_WIDE:%.*]] = zext i32 [[NUM_LOW_BITS_TO_SKIP]] to i64 +; CHECK-NEXT: [[HIGH_BITS_EXTRACTED:%.*]] = ashr i64 [[DATA:%.*]], [[NUM_LOW_BITS_TO_SKIP_WIDE]] +; CHECK-NEXT: [[HIGH_BITS_EXTRACTED_NARROW:%.*]] = trunc i64 [[HIGH_BITS_EXTRACTED]] to i32 +; CHECK-NEXT: [[SKIP_ALL_BITS_TILL_SIGNBIT:%.*]] = add i32 [[NBITS]], -1 +; CHECK-NEXT: [[SIGNBIT:%.*]] = lshr i32 [[HIGH_BITS_EXTRACTED_NARROW]], [[SKIP_ALL_BITS_TILL_SIGNBIT]] +; CHECK-NEXT: call void @use32(i32 [[NUM_LOW_BITS_TO_SKIP]]) +; CHECK-NEXT: call void @use64(i64 [[NUM_LOW_BITS_TO_SKIP_WIDE]]) +; CHECK-NEXT: call void @use64(i64 [[HIGH_BITS_EXTRACTED]]) +; CHECK-NEXT: call void @use32(i32 [[HIGH_BITS_EXTRACTED_NARROW]]) +; CHECK-NEXT: call void @use32(i32 [[SKIP_ALL_BITS_TILL_SIGNBIT]]) +; CHECK-NEXT: call void @use32(i32 [[SIGNBIT]]) +; CHECK-NEXT: [[ISNEG:%.*]] = icmp ne i32 [[SIGNBIT]], 0 +; CHECK-NEXT: ret i1 [[ISNEG]] +; + %num_low_bits_to_skip = sub i32 64, %nbits + %num_low_bits_to_skip_wide = zext i32 %num_low_bits_to_skip to i64 + %high_bits_extracted = ashr i64 %data, %num_low_bits_to_skip_wide + %high_bits_extracted_narrow = trunc i64 %high_bits_extracted to i32 + %skip_all_bits_till_signbit = sub i32 %nbits, 1 + %signbit = lshr i32 %high_bits_extracted_narrow, %skip_all_bits_till_signbit + + call void @use32(i32 %num_low_bits_to_skip) + call void @use64(i64 %num_low_bits_to_skip_wide) + call void @use64(i64 %high_bits_extracted) + call void @use32(i32 %high_bits_extracted_narrow) + call void @use32(i32 %skip_all_bits_till_signbit) + call void @use32(i32 %signbit) + + %isneg = icmp ne i32 %signbit, 0 + ret i1 %isneg +} + +;------------------------------------------------------------------------------; define i1 @unsigned_sign_bit_extract(i32 %x) { ; CHECK-LABEL: @unsigned_sign_bit_extract( -- 2.40.0