diff --git a/llvm/test/Transforms/InstCombine/conditional-variable-length-signext-after-high-bit-extract.ll b/llvm/test/Transforms/InstCombine/conditional-variable-length-signext-after-high-bit-extract.ll new file mode 100644 index 000000000000..70877dd526f4 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/conditional-variable-length-signext-after-high-bit-extract.ll @@ -0,0 +1,1040 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt %s -instcombine -S | FileCheck %s + +; If we extract (via lshr) some high bits, and then perform their sign-extension +; conditionally depending on whether the extracted value is negative or not +; (i.e. interpreting the highest extracted bit, which was the original signbit +; of the value from which we extracted as a signbit), then we should just +; perform extraction via `ashr`. + +; Base patterns. + +declare void @use1(i1) +declare void @use16(i16) +declare void @use32(i32) +declare void @use64(i64) + +define i32 @t0_notrunc_add(i32 %data, i32 %nbits) { +; CHECK-LABEL: @t0_notrunc_add( +; CHECK-NEXT: [[LOW_BITS_TO_SKIP:%.*]] = sub i32 32, [[NBITS:%.*]] +; CHECK-NEXT: [[HIGH_BITS_EXTRACTED:%.*]] = lshr i32 [[DATA:%.*]], [[LOW_BITS_TO_SKIP]] +; CHECK-NEXT: [[SHOULD_SIGNEXT:%.*]] = icmp slt i32 [[DATA]], 0 +; CHECK-NEXT: [[ALL_BITS_EXCEPT_LOW_NBITS:%.*]] = shl i32 -1, [[NBITS]] +; CHECK-NEXT: [[MAGIC:%.*]] = select i1 [[SHOULD_SIGNEXT]], i32 [[ALL_BITS_EXCEPT_LOW_NBITS]], i32 0 +; CHECK-NEXT: call void @use32(i32 [[LOW_BITS_TO_SKIP]]) +; CHECK-NEXT: call void @use32(i32 [[HIGH_BITS_EXTRACTED]]) +; CHECK-NEXT: call void @use1(i1 [[SHOULD_SIGNEXT]]) +; CHECK-NEXT: call void @use32(i32 [[ALL_BITS_EXCEPT_LOW_NBITS]]) +; CHECK-NEXT: call void @use32(i32 [[MAGIC]]) +; CHECK-NEXT: [[SIGNEXTENDED:%.*]] = add i32 [[HIGH_BITS_EXTRACTED]], [[MAGIC]] +; CHECK-NEXT: ret i32 [[SIGNEXTENDED]] +; + %low_bits_to_skip = sub i32 32, %nbits + %high_bits_extracted = lshr i32 %data, %low_bits_to_skip + %should_signext = icmp slt i32 %data, 0 + %all_bits_except_low_nbits = shl i32 -1, %nbits + %magic = select i1 %should_signext, i32 %all_bits_except_low_nbits, i32 0 + + call void @use32(i32 %low_bits_to_skip) + call void @use32(i32 %high_bits_extracted) + call void @use1(i1 %should_signext) + call void @use32(i32 %all_bits_except_low_nbits) + call void @use32(i32 %magic) + + %signextended = add i32 %high_bits_extracted, %magic + ret i32 %signextended +} + +define i32 @t1_notrunc_sub(i32 %data, i32 %nbits) { +; CHECK-LABEL: @t1_notrunc_sub( +; CHECK-NEXT: [[LOW_BITS_TO_SKIP:%.*]] = sub i32 32, [[NBITS:%.*]] +; CHECK-NEXT: [[HIGH_BITS_EXTRACTED:%.*]] = lshr i32 [[DATA:%.*]], [[LOW_BITS_TO_SKIP]] +; CHECK-NEXT: [[SHOULD_SIGNEXT:%.*]] = icmp slt i32 [[DATA]], 0 +; CHECK-NEXT: [[HIGHER_BIT_AFTER_SIGNBIT:%.*]] = shl i32 1, [[NBITS]] +; CHECK-NEXT: [[MAGIC:%.*]] = select i1 [[SHOULD_SIGNEXT]], i32 [[HIGHER_BIT_AFTER_SIGNBIT]], i32 0 +; CHECK-NEXT: call void @use32(i32 [[LOW_BITS_TO_SKIP]]) +; CHECK-NEXT: call void @use32(i32 [[HIGH_BITS_EXTRACTED]]) +; CHECK-NEXT: call void @use1(i1 [[SHOULD_SIGNEXT]]) +; CHECK-NEXT: call void @use32(i32 [[HIGHER_BIT_AFTER_SIGNBIT]]) +; CHECK-NEXT: call void @use32(i32 [[MAGIC]]) +; CHECK-NEXT: [[SIGNEXTENDED:%.*]] = sub i32 [[HIGH_BITS_EXTRACTED]], [[MAGIC]] +; CHECK-NEXT: ret i32 [[SIGNEXTENDED]] +; + %low_bits_to_skip = sub i32 32, %nbits + %high_bits_extracted = lshr i32 %data, %low_bits_to_skip + %should_signext = icmp slt i32 %data, 0 + %higher_bit_after_signbit = shl i32 1, %nbits + %magic = select i1 %should_signext, i32 %higher_bit_after_signbit, i32 0 + + call void @use32(i32 %low_bits_to_skip) + call void @use32(i32 %high_bits_extracted) + call void @use1(i1 %should_signext) + call void @use32(i32 %higher_bit_after_signbit) + call void @use32(i32 %magic) + + %signextended = sub i32 %high_bits_extracted, %magic + ret i32 %signextended +} + +define i32 @t2_trunc_add(i64 %data, i32 %nbits) { +; CHECK-LABEL: @t2_trunc_add( +; CHECK-NEXT: [[LOW_BITS_TO_SKIP:%.*]] = sub i32 64, [[NBITS:%.*]] +; CHECK-NEXT: [[LOW_BITS_TO_SKIP_WIDE:%.*]] = zext i32 [[LOW_BITS_TO_SKIP]] to i64 +; CHECK-NEXT: [[HIGH_BITS_EXTRACTED_WIDE:%.*]] = lshr i64 [[DATA:%.*]], [[LOW_BITS_TO_SKIP_WIDE]] +; CHECK-NEXT: [[HIGH_BITS_EXTRACTED:%.*]] = trunc i64 [[HIGH_BITS_EXTRACTED_WIDE]] to i32 +; CHECK-NEXT: [[SHOULD_SIGNEXT:%.*]] = icmp slt i64 [[DATA]], 0 +; CHECK-NEXT: [[ALL_BITS_EXCEPT_LOW_NBITS:%.*]] = shl i32 -1, [[NBITS]] +; CHECK-NEXT: [[MAGIC:%.*]] = select i1 [[SHOULD_SIGNEXT]], i32 [[ALL_BITS_EXCEPT_LOW_NBITS]], i32 0 +; CHECK-NEXT: call void @use32(i32 [[LOW_BITS_TO_SKIP]]) +; CHECK-NEXT: call void @use64(i64 [[LOW_BITS_TO_SKIP_WIDE]]) +; CHECK-NEXT: call void @use64(i64 [[HIGH_BITS_EXTRACTED_WIDE]]) +; CHECK-NEXT: call void @use32(i32 [[HIGH_BITS_EXTRACTED]]) +; CHECK-NEXT: call void @use1(i1 [[SHOULD_SIGNEXT]]) +; CHECK-NEXT: call void @use32(i32 [[ALL_BITS_EXCEPT_LOW_NBITS]]) +; CHECK-NEXT: [[SIGNEXTENDED:%.*]] = add i32 [[MAGIC]], [[HIGH_BITS_EXTRACTED]] +; CHECK-NEXT: ret i32 [[SIGNEXTENDED]] +; + %low_bits_to_skip = sub i32 64, %nbits + %low_bits_to_skip_wide = zext i32 %low_bits_to_skip to i64 + %high_bits_extracted_wide = lshr i64 %data, %low_bits_to_skip_wide + %high_bits_extracted = trunc i64 %high_bits_extracted_wide to i32 + %should_signext = icmp slt i64 %data, 0 + %all_bits_except_low_nbits = shl i32 -1, %nbits + %magic = select i1 %should_signext, i32 %all_bits_except_low_nbits, i32 0 ; one-use + + call void @use32(i32 %low_bits_to_skip) + call void @use64(i64 %low_bits_to_skip_wide) + call void @use64(i64 %high_bits_extracted_wide) + call void @use32(i32 %high_bits_extracted) + call void @use1(i1 %should_signext) + call void @use32(i32 %all_bits_except_low_nbits) + + %signextended = add i32 %magic, %high_bits_extracted + ret i32 %signextended +} + +define i32 @t3_trunc_sub(i64 %data, i32 %nbits) { +; CHECK-LABEL: @t3_trunc_sub( +; CHECK-NEXT: [[LOW_BITS_TO_SKIP:%.*]] = sub i32 64, [[NBITS:%.*]] +; CHECK-NEXT: [[LOW_BITS_TO_SKIP_WIDE:%.*]] = zext i32 [[LOW_BITS_TO_SKIP]] to i64 +; CHECK-NEXT: [[HIGH_BITS_EXTRACTED_WIDE:%.*]] = lshr i64 [[DATA:%.*]], [[LOW_BITS_TO_SKIP_WIDE]] +; CHECK-NEXT: [[HIGH_BITS_EXTRACTED:%.*]] = trunc i64 [[HIGH_BITS_EXTRACTED_WIDE]] to i32 +; CHECK-NEXT: [[SHOULD_SIGNEXT:%.*]] = icmp slt i64 [[DATA]], 0 +; CHECK-NEXT: [[HIGHER_BIT_AFTER_SIGNBIT:%.*]] = shl i32 1, [[NBITS]] +; CHECK-NEXT: [[MAGIC:%.*]] = select i1 [[SHOULD_SIGNEXT]], i32 [[HIGHER_BIT_AFTER_SIGNBIT]], i32 0 +; CHECK-NEXT: call void @use32(i32 [[LOW_BITS_TO_SKIP]]) +; CHECK-NEXT: call void @use64(i64 [[LOW_BITS_TO_SKIP_WIDE]]) +; CHECK-NEXT: call void @use64(i64 [[HIGH_BITS_EXTRACTED_WIDE]]) +; CHECK-NEXT: call void @use32(i32 [[HIGH_BITS_EXTRACTED]]) +; CHECK-NEXT: call void @use1(i1 [[SHOULD_SIGNEXT]]) +; CHECK-NEXT: call void @use32(i32 [[HIGHER_BIT_AFTER_SIGNBIT]]) +; CHECK-NEXT: [[SIGNEXTENDED:%.*]] = sub i32 [[HIGH_BITS_EXTRACTED]], [[MAGIC]] +; CHECK-NEXT: ret i32 [[SIGNEXTENDED]] +; + %low_bits_to_skip = sub i32 64, %nbits + %low_bits_to_skip_wide = zext i32 %low_bits_to_skip to i64 + %high_bits_extracted_wide = lshr i64 %data, %low_bits_to_skip_wide + %high_bits_extracted = trunc i64 %high_bits_extracted_wide to i32 + %should_signext = icmp slt i64 %data, 0 + %higher_bit_after_signbit = shl i32 1, %nbits + %magic = select i1 %should_signext, i32 %higher_bit_after_signbit, i32 0 ; one-use + + call void @use32(i32 %low_bits_to_skip) + call void @use64(i64 %low_bits_to_skip_wide) + call void @use64(i64 %high_bits_extracted_wide) + call void @use32(i32 %high_bits_extracted) + call void @use1(i1 %should_signext) + call void @use32(i32 %higher_bit_after_signbit) + + %signextended = sub i32 %high_bits_extracted, %magic + ret i32 %signextended +} + +; Commutativity + +define i32 @t4_commutativity0(i32 %data, i32 %nbits) { +; CHECK-LABEL: @t4_commutativity0( +; CHECK-NEXT: [[LOW_BITS_TO_SKIP:%.*]] = sub i32 32, [[NBITS:%.*]] +; CHECK-NEXT: [[HIGH_BITS_EXTRACTED:%.*]] = lshr i32 [[DATA:%.*]], [[LOW_BITS_TO_SKIP]] +; CHECK-NEXT: [[SHOULD_SIGNEXT:%.*]] = icmp slt i32 [[DATA]], 0 +; CHECK-NEXT: [[ALL_BITS_EXCEPT_LOW_NBITS:%.*]] = shl i32 -1, [[NBITS]] +; CHECK-NEXT: [[MAGIC:%.*]] = select i1 [[SHOULD_SIGNEXT]], i32 [[ALL_BITS_EXCEPT_LOW_NBITS]], i32 0 +; CHECK-NEXT: call void @use32(i32 [[LOW_BITS_TO_SKIP]]) +; CHECK-NEXT: call void @use32(i32 [[HIGH_BITS_EXTRACTED]]) +; CHECK-NEXT: call void @use1(i1 [[SHOULD_SIGNEXT]]) +; CHECK-NEXT: call void @use32(i32 [[ALL_BITS_EXCEPT_LOW_NBITS]]) +; CHECK-NEXT: call void @use32(i32 [[MAGIC]]) +; CHECK-NEXT: [[SIGNEXTENDED:%.*]] = add i32 [[HIGH_BITS_EXTRACTED]], [[MAGIC]] +; CHECK-NEXT: ret i32 [[SIGNEXTENDED]] +; + %low_bits_to_skip = sub i32 32, %nbits + %high_bits_extracted = lshr i32 %data, %low_bits_to_skip + %should_signext = icmp slt i32 %data, 0 + %all_bits_except_low_nbits = shl i32 -1, %nbits + %magic = select i1 %should_signext, i32 %all_bits_except_low_nbits, i32 0 + + call void @use32(i32 %low_bits_to_skip) + call void @use32(i32 %high_bits_extracted) + call void @use1(i1 %should_signext) + call void @use32(i32 %all_bits_except_low_nbits) + call void @use32(i32 %magic) + + %signextended = add i32 %high_bits_extracted, %magic + ret i32 %signextended +} +define i32 @t5_commutativity1(i32 %data, i32 %nbits) { +; CHECK-LABEL: @t5_commutativity1( +; CHECK-NEXT: [[LOW_BITS_TO_SKIP:%.*]] = sub i32 32, [[NBITS:%.*]] +; CHECK-NEXT: [[HIGH_BITS_EXTRACTED:%.*]] = lshr i32 [[DATA:%.*]], [[LOW_BITS_TO_SKIP]] +; CHECK-NEXT: [[SHOULD_SIGNEXT:%.*]] = icmp sgt i32 [[DATA]], -1 +; CHECK-NEXT: [[ALL_BITS_EXCEPT_LOW_NBITS:%.*]] = shl i32 -1, [[NBITS]] +; CHECK-NEXT: [[MAGIC:%.*]] = select i1 [[SHOULD_SIGNEXT]], i32 0, i32 [[ALL_BITS_EXCEPT_LOW_NBITS]] +; CHECK-NEXT: call void @use32(i32 [[LOW_BITS_TO_SKIP]]) +; CHECK-NEXT: call void @use32(i32 [[HIGH_BITS_EXTRACTED]]) +; CHECK-NEXT: call void @use1(i1 [[SHOULD_SIGNEXT]]) +; CHECK-NEXT: call void @use32(i32 [[ALL_BITS_EXCEPT_LOW_NBITS]]) +; CHECK-NEXT: call void @use32(i32 [[MAGIC]]) +; CHECK-NEXT: [[SIGNEXTENDED:%.*]] = add i32 [[HIGH_BITS_EXTRACTED]], [[MAGIC]] +; CHECK-NEXT: ret i32 [[SIGNEXTENDED]] +; + %low_bits_to_skip = sub i32 32, %nbits + %high_bits_extracted = lshr i32 %data, %low_bits_to_skip + %should_signext = icmp sgt i32 %data, -1 ; swapped + %all_bits_except_low_nbits = shl i32 -1, %nbits + %magic = select i1 %should_signext, i32 0, i32 %all_bits_except_low_nbits ; swapped + + call void @use32(i32 %low_bits_to_skip) + call void @use32(i32 %high_bits_extracted) + call void @use1(i1 %should_signext) + call void @use32(i32 %all_bits_except_low_nbits) + call void @use32(i32 %magic) + + %signextended = add i32 %high_bits_extracted, %magic + ret i32 %signextended +} +define i32 @t6_commutativity2(i32 %data, i32 %nbits) { +; CHECK-LABEL: @t6_commutativity2( +; CHECK-NEXT: [[LOW_BITS_TO_SKIP:%.*]] = sub i32 32, [[NBITS:%.*]] +; CHECK-NEXT: [[HIGH_BITS_EXTRACTED:%.*]] = lshr i32 [[DATA:%.*]], [[LOW_BITS_TO_SKIP]] +; CHECK-NEXT: [[SHOULD_SIGNEXT:%.*]] = icmp slt i32 [[DATA]], 0 +; CHECK-NEXT: [[ALL_BITS_EXCEPT_LOW_NBITS:%.*]] = shl i32 -1, [[NBITS]] +; CHECK-NEXT: [[MAGIC:%.*]] = select i1 [[SHOULD_SIGNEXT]], i32 [[ALL_BITS_EXCEPT_LOW_NBITS]], i32 0 +; CHECK-NEXT: call void @use32(i32 [[LOW_BITS_TO_SKIP]]) +; CHECK-NEXT: call void @use32(i32 [[HIGH_BITS_EXTRACTED]]) +; CHECK-NEXT: call void @use1(i1 [[SHOULD_SIGNEXT]]) +; CHECK-NEXT: call void @use32(i32 [[ALL_BITS_EXCEPT_LOW_NBITS]]) +; CHECK-NEXT: call void @use32(i32 [[MAGIC]]) +; CHECK-NEXT: [[SIGNEXTENDED:%.*]] = add i32 [[MAGIC]], [[HIGH_BITS_EXTRACTED]] +; CHECK-NEXT: ret i32 [[SIGNEXTENDED]] +; + %low_bits_to_skip = sub i32 32, %nbits + %high_bits_extracted = lshr i32 %data, %low_bits_to_skip + %should_signext = icmp slt i32 %data, 0 + %all_bits_except_low_nbits = shl i32 -1, %nbits + %magic = select i1 %should_signext, i32 %all_bits_except_low_nbits, i32 0 + + call void @use32(i32 %low_bits_to_skip) + call void @use32(i32 %high_bits_extracted) + call void @use1(i1 %should_signext) + call void @use32(i32 %all_bits_except_low_nbits) + call void @use32(i32 %magic) + + %signextended = add i32 %magic, %high_bits_extracted ; swapped + ret i32 %signextended +} + +; Extra uses + +define i32 @t7_trunc_extrause0(i64 %data, i32 %nbits) { +; CHECK-LABEL: @t7_trunc_extrause0( +; CHECK-NEXT: [[LOW_BITS_TO_SKIP:%.*]] = sub i32 64, [[NBITS:%.*]] +; CHECK-NEXT: [[LOW_BITS_TO_SKIP_WIDE:%.*]] = zext i32 [[LOW_BITS_TO_SKIP]] to i64 +; CHECK-NEXT: [[HIGH_BITS_EXTRACTED_WIDE:%.*]] = lshr i64 [[DATA:%.*]], [[LOW_BITS_TO_SKIP_WIDE]] +; CHECK-NEXT: [[HIGH_BITS_EXTRACTED:%.*]] = trunc i64 [[HIGH_BITS_EXTRACTED_WIDE]] to i32 +; CHECK-NEXT: [[SHOULD_SIGNEXT:%.*]] = icmp slt i64 [[DATA]], 0 +; CHECK-NEXT: [[ALL_BITS_EXCEPT_LOW_NBITS:%.*]] = shl i32 -1, [[NBITS]] +; CHECK-NEXT: [[MAGIC:%.*]] = select i1 [[SHOULD_SIGNEXT]], i32 [[ALL_BITS_EXCEPT_LOW_NBITS]], i32 0 +; CHECK-NEXT: call void @use32(i32 [[LOW_BITS_TO_SKIP]]) +; CHECK-NEXT: call void @use64(i64 [[LOW_BITS_TO_SKIP_WIDE]]) +; CHECK-NEXT: call void @use64(i64 [[HIGH_BITS_EXTRACTED_WIDE]]) +; CHECK-NEXT: call void @use32(i32 [[HIGH_BITS_EXTRACTED]]) +; CHECK-NEXT: call void @use1(i1 [[SHOULD_SIGNEXT]]) +; CHECK-NEXT: call void @use32(i32 [[ALL_BITS_EXCEPT_LOW_NBITS]]) +; CHECK-NEXT: [[SIGNEXTENDED:%.*]] = add i32 [[MAGIC]], [[HIGH_BITS_EXTRACTED]] +; CHECK-NEXT: ret i32 [[SIGNEXTENDED]] +; + %low_bits_to_skip = sub i32 64, %nbits + %low_bits_to_skip_wide = zext i32 %low_bits_to_skip to i64 + %high_bits_extracted_wide = lshr i64 %data, %low_bits_to_skip_wide + %high_bits_extracted = trunc i64 %high_bits_extracted_wide to i32 ; has extra use + %should_signext = icmp slt i64 %data, 0 + %all_bits_except_low_nbits = shl i32 -1, %nbits + %magic = select i1 %should_signext, i32 %all_bits_except_low_nbits, i32 0 ; one-use + + call void @use32(i32 %low_bits_to_skip) + call void @use64(i64 %low_bits_to_skip_wide) + call void @use64(i64 %high_bits_extracted_wide) + call void @use32(i32 %high_bits_extracted) + call void @use1(i1 %should_signext) + call void @use32(i32 %all_bits_except_low_nbits) + + %signextended = add i32 %magic, %high_bits_extracted + ret i32 %signextended +} +define i32 @t8_trunc_extrause1(i64 %data, i32 %nbits) { +; CHECK-LABEL: @t8_trunc_extrause1( +; CHECK-NEXT: [[LOW_BITS_TO_SKIP:%.*]] = sub i32 64, [[NBITS:%.*]] +; CHECK-NEXT: [[LOW_BITS_TO_SKIP_WIDE:%.*]] = zext i32 [[LOW_BITS_TO_SKIP]] to i64 +; CHECK-NEXT: [[HIGH_BITS_EXTRACTED_WIDE:%.*]] = lshr i64 [[DATA:%.*]], [[LOW_BITS_TO_SKIP_WIDE]] +; CHECK-NEXT: [[HIGH_BITS_EXTRACTED:%.*]] = trunc i64 [[HIGH_BITS_EXTRACTED_WIDE]] to i32 +; CHECK-NEXT: [[SHOULD_SIGNEXT:%.*]] = icmp slt i64 [[DATA]], 0 +; CHECK-NEXT: [[ALL_BITS_EXCEPT_LOW_NBITS:%.*]] = shl i32 -1, [[NBITS]] +; CHECK-NEXT: [[MAGIC:%.*]] = select i1 [[SHOULD_SIGNEXT]], i32 [[ALL_BITS_EXCEPT_LOW_NBITS]], i32 0 +; CHECK-NEXT: call void @use32(i32 [[LOW_BITS_TO_SKIP]]) +; CHECK-NEXT: call void @use64(i64 [[LOW_BITS_TO_SKIP_WIDE]]) +; CHECK-NEXT: call void @use64(i64 [[HIGH_BITS_EXTRACTED_WIDE]]) +; CHECK-NEXT: call void @use1(i1 [[SHOULD_SIGNEXT]]) +; CHECK-NEXT: call void @use32(i32 [[ALL_BITS_EXCEPT_LOW_NBITS]]) +; CHECK-NEXT: call void @use32(i32 [[MAGIC]]) +; CHECK-NEXT: [[SIGNEXTENDED:%.*]] = add i32 [[MAGIC]], [[HIGH_BITS_EXTRACTED]] +; CHECK-NEXT: ret i32 [[SIGNEXTENDED]] +; + %low_bits_to_skip = sub i32 64, %nbits + %low_bits_to_skip_wide = zext i32 %low_bits_to_skip to i64 + %high_bits_extracted_wide = lshr i64 %data, %low_bits_to_skip_wide + %high_bits_extracted = trunc i64 %high_bits_extracted_wide to i32 ; one-use + %should_signext = icmp slt i64 %data, 0 + %all_bits_except_low_nbits = shl i32 -1, %nbits + %magic = select i1 %should_signext, i32 %all_bits_except_low_nbits, i32 0 ; has extra use + + call void @use32(i32 %low_bits_to_skip) + call void @use64(i64 %low_bits_to_skip_wide) + call void @use64(i64 %high_bits_extracted_wide) + call void @use1(i1 %should_signext) + call void @use32(i32 %all_bits_except_low_nbits) + call void @use32(i32 %magic) + + %signextended = add i32 %magic, %high_bits_extracted + ret i32 %signextended +} +define i32 @n9_trunc_extrause2(i64 %data, i32 %nbits) { +; CHECK-LABEL: @n9_trunc_extrause2( +; CHECK-NEXT: [[LOW_BITS_TO_SKIP:%.*]] = sub i32 64, [[NBITS:%.*]] +; CHECK-NEXT: [[LOW_BITS_TO_SKIP_WIDE:%.*]] = zext i32 [[LOW_BITS_TO_SKIP]] to i64 +; CHECK-NEXT: [[HIGH_BITS_EXTRACTED_WIDE:%.*]] = lshr i64 [[DATA:%.*]], [[LOW_BITS_TO_SKIP_WIDE]] +; CHECK-NEXT: [[HIGH_BITS_EXTRACTED:%.*]] = trunc i64 [[HIGH_BITS_EXTRACTED_WIDE]] to i32 +; CHECK-NEXT: [[SHOULD_SIGNEXT:%.*]] = icmp slt i64 [[DATA]], 0 +; CHECK-NEXT: [[ALL_BITS_EXCEPT_LOW_NBITS:%.*]] = shl i32 -1, [[NBITS]] +; CHECK-NEXT: [[MAGIC:%.*]] = select i1 [[SHOULD_SIGNEXT]], i32 [[ALL_BITS_EXCEPT_LOW_NBITS]], i32 0 +; CHECK-NEXT: call void @use32(i32 [[LOW_BITS_TO_SKIP]]) +; CHECK-NEXT: call void @use64(i64 [[LOW_BITS_TO_SKIP_WIDE]]) +; CHECK-NEXT: call void @use64(i64 [[HIGH_BITS_EXTRACTED_WIDE]]) +; CHECK-NEXT: call void @use32(i32 [[HIGH_BITS_EXTRACTED]]) +; CHECK-NEXT: call void @use1(i1 [[SHOULD_SIGNEXT]]) +; CHECK-NEXT: call void @use32(i32 [[ALL_BITS_EXCEPT_LOW_NBITS]]) +; CHECK-NEXT: call void @use32(i32 [[MAGIC]]) +; CHECK-NEXT: [[SIGNEXTENDED:%.*]] = add i32 [[MAGIC]], [[HIGH_BITS_EXTRACTED]] +; CHECK-NEXT: ret i32 [[SIGNEXTENDED]] +; + %low_bits_to_skip = sub i32 64, %nbits + %low_bits_to_skip_wide = zext i32 %low_bits_to_skip to i64 + %high_bits_extracted_wide = lshr i64 %data, %low_bits_to_skip_wide + %high_bits_extracted = trunc i64 %high_bits_extracted_wide to i32 ; has extra use + %should_signext = icmp slt i64 %data, 0 + %all_bits_except_low_nbits = shl i32 -1, %nbits + %magic = select i1 %should_signext, i32 %all_bits_except_low_nbits, i32 0 ; has extra use + + call void @use32(i32 %low_bits_to_skip) + call void @use64(i64 %low_bits_to_skip_wide) + call void @use64(i64 %high_bits_extracted_wide) + call void @use32(i32 %high_bits_extracted) + call void @use1(i1 %should_signext) + call void @use32(i32 %all_bits_except_low_nbits) + call void @use32(i32 %magic) + + %signextended = add i32 %magic, %high_bits_extracted + ret i32 %signextended +} + +define i32 @t10_preserve_exact(i32 %data, i32 %nbits) { +; CHECK-LABEL: @t10_preserve_exact( +; CHECK-NEXT: [[LOW_BITS_TO_SKIP:%.*]] = sub i32 32, [[NBITS:%.*]] +; CHECK-NEXT: [[HIGH_BITS_EXTRACTED:%.*]] = lshr exact i32 [[DATA:%.*]], [[LOW_BITS_TO_SKIP]] +; CHECK-NEXT: [[SHOULD_SIGNEXT:%.*]] = icmp slt i32 [[DATA]], 0 +; CHECK-NEXT: [[ALL_BITS_EXCEPT_LOW_NBITS:%.*]] = shl i32 -1, [[NBITS]] +; CHECK-NEXT: [[MAGIC:%.*]] = select i1 [[SHOULD_SIGNEXT]], i32 [[ALL_BITS_EXCEPT_LOW_NBITS]], i32 0 +; CHECK-NEXT: call void @use32(i32 [[LOW_BITS_TO_SKIP]]) +; CHECK-NEXT: call void @use32(i32 [[HIGH_BITS_EXTRACTED]]) +; CHECK-NEXT: call void @use1(i1 [[SHOULD_SIGNEXT]]) +; CHECK-NEXT: call void @use32(i32 [[ALL_BITS_EXCEPT_LOW_NBITS]]) +; CHECK-NEXT: call void @use32(i32 [[MAGIC]]) +; CHECK-NEXT: [[SIGNEXTENDED:%.*]] = add i32 [[HIGH_BITS_EXTRACTED]], [[MAGIC]] +; CHECK-NEXT: ret i32 [[SIGNEXTENDED]] +; + %low_bits_to_skip = sub i32 32, %nbits + %high_bits_extracted = lshr exact i32 %data, %low_bits_to_skip + %should_signext = icmp slt i32 %data, 0 + %all_bits_except_low_nbits = shl i32 -1, %nbits + %magic = select i1 %should_signext, i32 %all_bits_except_low_nbits, i32 0 + + call void @use32(i32 %low_bits_to_skip) + call void @use32(i32 %high_bits_extracted) + call void @use1(i1 %should_signext) + call void @use32(i32 %all_bits_except_low_nbits) + call void @use32(i32 %magic) + + %signextended = add i32 %high_bits_extracted, %magic + ret i32 %signextended +} + +define i32 @t11_different_zext_of_shamt(i32 %data, i8 %nbits) { +; CHECK-LABEL: @t11_different_zext_of_shamt( +; CHECK-NEXT: [[NBITS_16BIT:%.*]] = zext i8 [[NBITS:%.*]] to i16 +; CHECK-NEXT: [[LOW_BITS_TO_SKIP:%.*]] = sub nsw i16 32, [[NBITS_16BIT]] +; CHECK-NEXT: [[LOW_BITS_TO_SKIP_32:%.*]] = zext i16 [[LOW_BITS_TO_SKIP]] to i32 +; CHECK-NEXT: [[HIGH_BITS_EXTRACTED:%.*]] = lshr i32 [[DATA:%.*]], [[LOW_BITS_TO_SKIP_32]] +; CHECK-NEXT: [[SHOULD_SIGNEXT:%.*]] = icmp slt i32 [[DATA]], 0 +; CHECK-NEXT: [[NBITS_32BIT:%.*]] = zext i8 [[NBITS]] to i32 +; CHECK-NEXT: [[ALL_BITS_EXCEPT_LOW_NBITS:%.*]] = shl i32 -1, [[NBITS_32BIT]] +; CHECK-NEXT: [[MAGIC:%.*]] = select i1 [[SHOULD_SIGNEXT]], i32 [[ALL_BITS_EXCEPT_LOW_NBITS]], i32 0 +; CHECK-NEXT: call void @use16(i16 [[NBITS_16BIT]]) +; CHECK-NEXT: call void @use16(i16 [[LOW_BITS_TO_SKIP]]) +; CHECK-NEXT: call void @use32(i32 [[LOW_BITS_TO_SKIP_32]]) +; CHECK-NEXT: call void @use32(i32 [[HIGH_BITS_EXTRACTED]]) +; CHECK-NEXT: call void @use1(i1 [[SHOULD_SIGNEXT]]) +; CHECK-NEXT: call void @use32(i32 [[NBITS_32BIT]]) +; CHECK-NEXT: call void @use32(i32 [[ALL_BITS_EXCEPT_LOW_NBITS]]) +; CHECK-NEXT: call void @use32(i32 [[MAGIC]]) +; CHECK-NEXT: [[SIGNEXTENDED:%.*]] = add i32 [[HIGH_BITS_EXTRACTED]], [[MAGIC]] +; CHECK-NEXT: ret i32 [[SIGNEXTENDED]] +; + %nbits_16bit = zext i8 %nbits to i16 + %low_bits_to_skip = sub i16 32, %nbits_16bit + %low_bits_to_skip_32 = zext i16 %low_bits_to_skip to i32 + %high_bits_extracted = lshr i32 %data, %low_bits_to_skip_32 + %should_signext = icmp slt i32 %data, 0 + %nbits_32bit = zext i8 %nbits to i32 + %all_bits_except_low_nbits = shl i32 -1, %nbits_32bit + %magic = select i1 %should_signext, i32 %all_bits_except_low_nbits, i32 0 + + call void @use16(i16 %nbits_16bit) + call void @use16(i16 %low_bits_to_skip) + call void @use32(i32 %low_bits_to_skip_32) + call void @use32(i32 %high_bits_extracted) + call void @use1(i1 %should_signext) + call void @use32(i32 %nbits_32bit) + call void @use32(i32 %all_bits_except_low_nbits) + call void @use32(i32 %magic) + + %signextended = add i32 %high_bits_extracted, %magic + ret i32 %signextended +} + +define i32 @t12_add_sext_of_magic(i32 %data, i8 %nbits) { +; CHECK-LABEL: @t12_add_sext_of_magic( +; CHECK-NEXT: [[NBITS_32BIT:%.*]] = zext i8 [[NBITS:%.*]] to i32 +; CHECK-NEXT: [[LOW_BITS_TO_SKIP:%.*]] = sub nsw i32 32, [[NBITS_32BIT]] +; CHECK-NEXT: [[HIGH_BITS_EXTRACTED:%.*]] = lshr i32 [[DATA:%.*]], [[LOW_BITS_TO_SKIP]] +; CHECK-NEXT: [[SHOULD_SIGNEXT:%.*]] = icmp slt i32 [[DATA]], 0 +; CHECK-NEXT: [[NBITS_16BIT:%.*]] = zext i8 [[NBITS]] to i16 +; CHECK-NEXT: [[ALL_BITS_EXCEPT_LOW_NBITS:%.*]] = shl i16 -1, [[NBITS_16BIT]] +; CHECK-NEXT: [[MAGIC:%.*]] = select i1 [[SHOULD_SIGNEXT]], i16 [[ALL_BITS_EXCEPT_LOW_NBITS]], i16 0 +; CHECK-NEXT: [[MAGIC_WIDE:%.*]] = sext i16 [[MAGIC]] to i32 +; CHECK-NEXT: call void @use32(i32 [[NBITS_32BIT]]) +; CHECK-NEXT: call void @use32(i32 [[LOW_BITS_TO_SKIP]]) +; CHECK-NEXT: call void @use32(i32 [[HIGH_BITS_EXTRACTED]]) +; CHECK-NEXT: call void @use1(i1 [[SHOULD_SIGNEXT]]) +; CHECK-NEXT: call void @use16(i16 [[NBITS_16BIT]]) +; CHECK-NEXT: call void @use16(i16 [[ALL_BITS_EXCEPT_LOW_NBITS]]) +; CHECK-NEXT: call void @use16(i16 [[MAGIC]]) +; CHECK-NEXT: call void @use32(i32 [[MAGIC_WIDE]]) +; CHECK-NEXT: [[SIGNEXTENDED:%.*]] = add i32 [[HIGH_BITS_EXTRACTED]], [[MAGIC_WIDE]] +; CHECK-NEXT: ret i32 [[SIGNEXTENDED]] +; + %nbits_32bit = zext i8 %nbits to i32 + %low_bits_to_skip = sub i32 32, %nbits_32bit + %high_bits_extracted = lshr i32 %data, %low_bits_to_skip + %should_signext = icmp slt i32 %data, 0 + %nbits_16bit = zext i8 %nbits to i16 + %all_bits_except_low_nbits = shl i16 -1, %nbits_16bit + %magic = select i1 %should_signext, i16 %all_bits_except_low_nbits, i16 0 + %magic_wide = sext i16 %magic to i32 + + call void @use32(i32 %nbits_32bit) + call void @use32(i32 %low_bits_to_skip) + call void @use32(i32 %high_bits_extracted) + call void @use1(i1 %should_signext) + call void @use16(i16 %nbits_16bit) + call void @use16(i16 %all_bits_except_low_nbits) + call void @use16(i16 %magic) + call void @use32(i32 %magic_wide) + + %signextended = add i32 %high_bits_extracted, %magic_wide + ret i32 %signextended +} + +define i32 @t13_sub_zext_of_magic(i32 %data, i8 %nbits) { +; CHECK-LABEL: @t13_sub_zext_of_magic( +; CHECK-NEXT: [[NBITS_32BIT:%.*]] = zext i8 [[NBITS:%.*]] to i32 +; CHECK-NEXT: [[LOW_BITS_TO_SKIP:%.*]] = sub nsw i32 32, [[NBITS_32BIT]] +; CHECK-NEXT: [[HIGH_BITS_EXTRACTED:%.*]] = lshr i32 [[DATA:%.*]], [[LOW_BITS_TO_SKIP]] +; CHECK-NEXT: [[SHOULD_SIGNEXT:%.*]] = icmp slt i32 [[DATA]], 0 +; CHECK-NEXT: [[NBITS_16BIT:%.*]] = zext i8 [[NBITS]] to i16 +; CHECK-NEXT: [[ALL_BITS_EXCEPT_LOW_NBITS:%.*]] = shl i16 1, [[NBITS_16BIT]] +; CHECK-NEXT: [[MAGIC:%.*]] = select i1 [[SHOULD_SIGNEXT]], i16 [[ALL_BITS_EXCEPT_LOW_NBITS]], i16 0 +; CHECK-NEXT: [[MAGIC_WIDE:%.*]] = zext i16 [[MAGIC]] to i32 +; CHECK-NEXT: call void @use32(i32 [[NBITS_32BIT]]) +; CHECK-NEXT: call void @use32(i32 [[LOW_BITS_TO_SKIP]]) +; CHECK-NEXT: call void @use32(i32 [[HIGH_BITS_EXTRACTED]]) +; CHECK-NEXT: call void @use1(i1 [[SHOULD_SIGNEXT]]) +; CHECK-NEXT: call void @use16(i16 [[NBITS_16BIT]]) +; CHECK-NEXT: call void @use16(i16 [[ALL_BITS_EXCEPT_LOW_NBITS]]) +; CHECK-NEXT: call void @use16(i16 [[MAGIC]]) +; CHECK-NEXT: call void @use32(i32 [[MAGIC_WIDE]]) +; CHECK-NEXT: [[SIGNEXTENDED:%.*]] = sub i32 [[HIGH_BITS_EXTRACTED]], [[MAGIC_WIDE]] +; CHECK-NEXT: ret i32 [[SIGNEXTENDED]] +; + %nbits_32bit = zext i8 %nbits to i32 + %low_bits_to_skip = sub i32 32, %nbits_32bit + %high_bits_extracted = lshr i32 %data, %low_bits_to_skip + %should_signext = icmp slt i32 %data, 0 + %nbits_16bit = zext i8 %nbits to i16 + %all_bits_except_low_nbits = shl i16 1, %nbits_16bit + %magic = select i1 %should_signext, i16 %all_bits_except_low_nbits, i16 0 + %magic_wide = zext i16 %magic to i32 + + call void @use32(i32 %nbits_32bit) + call void @use32(i32 %low_bits_to_skip) + call void @use32(i32 %high_bits_extracted) + call void @use1(i1 %should_signext) + call void @use16(i16 %nbits_16bit) + call void @use16(i16 %all_bits_except_low_nbits) + call void @use16(i16 %magic) + call void @use32(i32 %magic_wide) + + %signextended = sub i32 %high_bits_extracted, %magic_wide + ret i32 %signextended +} + +define i32 @t14_add_sext_of_shl(i32 %data, i8 %nbits) { +; CHECK-LABEL: @t14_add_sext_of_shl( +; CHECK-NEXT: [[NBITS_32BIT:%.*]] = zext i8 [[NBITS:%.*]] to i32 +; CHECK-NEXT: [[LOW_BITS_TO_SKIP:%.*]] = sub nsw i32 32, [[NBITS_32BIT]] +; CHECK-NEXT: [[HIGH_BITS_EXTRACTED:%.*]] = lshr i32 [[DATA:%.*]], [[LOW_BITS_TO_SKIP]] +; CHECK-NEXT: [[SHOULD_SIGNEXT:%.*]] = icmp slt i32 [[DATA]], 0 +; CHECK-NEXT: [[NBITS_16BIT:%.*]] = zext i8 [[NBITS]] to i16 +; CHECK-NEXT: [[ALL_BITS_EXCEPT_LOW_NBITS:%.*]] = shl i16 -1, [[NBITS_16BIT]] +; CHECK-NEXT: [[ALL_BITS_EXCEPT_LOW_NBITS_WIDE:%.*]] = sext i16 [[ALL_BITS_EXCEPT_LOW_NBITS]] to i32 +; CHECK-NEXT: [[MAGIC:%.*]] = select i1 [[SHOULD_SIGNEXT]], i32 [[ALL_BITS_EXCEPT_LOW_NBITS_WIDE]], i32 0 +; CHECK-NEXT: call void @use32(i32 [[NBITS_32BIT]]) +; CHECK-NEXT: call void @use32(i32 [[LOW_BITS_TO_SKIP]]) +; CHECK-NEXT: call void @use32(i32 [[HIGH_BITS_EXTRACTED]]) +; CHECK-NEXT: call void @use1(i1 [[SHOULD_SIGNEXT]]) +; CHECK-NEXT: call void @use16(i16 [[NBITS_16BIT]]) +; CHECK-NEXT: call void @use16(i16 [[ALL_BITS_EXCEPT_LOW_NBITS]]) +; CHECK-NEXT: call void @use32(i32 [[ALL_BITS_EXCEPT_LOW_NBITS_WIDE]]) +; CHECK-NEXT: call void @use32(i32 [[MAGIC]]) +; CHECK-NEXT: [[SIGNEXTENDED:%.*]] = add i32 [[HIGH_BITS_EXTRACTED]], [[MAGIC]] +; CHECK-NEXT: ret i32 [[SIGNEXTENDED]] +; + %nbits_32bit = zext i8 %nbits to i32 + %low_bits_to_skip = sub i32 32, %nbits_32bit + %high_bits_extracted = lshr i32 %data, %low_bits_to_skip + %should_signext = icmp slt i32 %data, 0 + %nbits_16bit = zext i8 %nbits to i16 + %all_bits_except_low_nbits = shl i16 -1, %nbits_16bit + %all_bits_except_low_nbits_wide = sext i16 %all_bits_except_low_nbits to i32 + %magic = select i1 %should_signext, i32 %all_bits_except_low_nbits_wide, i32 0 + + call void @use32(i32 %nbits_32bit) + call void @use32(i32 %low_bits_to_skip) + call void @use32(i32 %high_bits_extracted) + call void @use1(i1 %should_signext) + call void @use16(i16 %nbits_16bit) + call void @use16(i16 %all_bits_except_low_nbits) + call void @use32(i32 %all_bits_except_low_nbits_wide) + call void @use32(i32 %magic) + + %signextended = add i32 %high_bits_extracted, %magic + ret i32 %signextended +} + +define i32 @t15_sub_zext_of_shl(i32 %data, i8 %nbits) { +; CHECK-LABEL: @t15_sub_zext_of_shl( +; CHECK-NEXT: [[NBITS_32BIT:%.*]] = zext i8 [[NBITS:%.*]] to i32 +; CHECK-NEXT: [[LOW_BITS_TO_SKIP:%.*]] = sub nsw i32 32, [[NBITS_32BIT]] +; CHECK-NEXT: [[HIGH_BITS_EXTRACTED:%.*]] = lshr i32 [[DATA:%.*]], [[LOW_BITS_TO_SKIP]] +; CHECK-NEXT: [[SHOULD_SIGNEXT:%.*]] = icmp slt i32 [[DATA]], 0 +; CHECK-NEXT: [[NBITS_16BIT:%.*]] = zext i8 [[NBITS]] to i16 +; CHECK-NEXT: [[ALL_BITS_EXCEPT_LOW_NBITS:%.*]] = shl i16 1, [[NBITS_16BIT]] +; CHECK-NEXT: [[ALL_BITS_EXCEPT_LOW_NBITS_WIDE:%.*]] = zext i16 [[ALL_BITS_EXCEPT_LOW_NBITS]] to i32 +; CHECK-NEXT: [[MAGIC:%.*]] = select i1 [[SHOULD_SIGNEXT]], i32 [[ALL_BITS_EXCEPT_LOW_NBITS_WIDE]], i32 0 +; CHECK-NEXT: call void @use32(i32 [[NBITS_32BIT]]) +; CHECK-NEXT: call void @use32(i32 [[LOW_BITS_TO_SKIP]]) +; CHECK-NEXT: call void @use32(i32 [[HIGH_BITS_EXTRACTED]]) +; CHECK-NEXT: call void @use1(i1 [[SHOULD_SIGNEXT]]) +; CHECK-NEXT: call void @use16(i16 [[NBITS_16BIT]]) +; CHECK-NEXT: call void @use16(i16 [[ALL_BITS_EXCEPT_LOW_NBITS]]) +; CHECK-NEXT: call void @use32(i32 [[ALL_BITS_EXCEPT_LOW_NBITS_WIDE]]) +; CHECK-NEXT: call void @use32(i32 [[MAGIC]]) +; CHECK-NEXT: [[SIGNEXTENDED:%.*]] = sub i32 [[HIGH_BITS_EXTRACTED]], [[MAGIC]] +; CHECK-NEXT: ret i32 [[SIGNEXTENDED]] +; + %nbits_32bit = zext i8 %nbits to i32 + %low_bits_to_skip = sub i32 32, %nbits_32bit + %high_bits_extracted = lshr i32 %data, %low_bits_to_skip + %should_signext = icmp slt i32 %data, 0 + %nbits_16bit = zext i8 %nbits to i16 + %all_bits_except_low_nbits = shl i16 1, %nbits_16bit + %all_bits_except_low_nbits_wide = zext i16 %all_bits_except_low_nbits to i32 + %magic = select i1 %should_signext, i32 %all_bits_except_low_nbits_wide, i32 0 + + call void @use32(i32 %nbits_32bit) + call void @use32(i32 %low_bits_to_skip) + call void @use32(i32 %high_bits_extracted) + call void @use1(i1 %should_signext) + call void @use16(i16 %nbits_16bit) + call void @use16(i16 %all_bits_except_low_nbits) + call void @use32(i32 %all_bits_except_low_nbits_wide) + call void @use32(i32 %magic) + + %signextended = sub i32 %high_bits_extracted, %magic + ret i32 %signextended +} + +; Negative tests. + +define i32 @n16(i32 %data, i32 %nbits) { +; CHECK-LABEL: @n16( +; CHECK-NEXT: [[LOW_BITS_TO_SKIP:%.*]] = sub i32 31, [[NBITS:%.*]] +; CHECK-NEXT: [[HIGH_BITS_EXTRACTED:%.*]] = lshr i32 [[DATA:%.*]], [[LOW_BITS_TO_SKIP]] +; CHECK-NEXT: [[SHOULD_SIGNEXT:%.*]] = icmp slt i32 [[DATA]], 0 +; CHECK-NEXT: [[ALL_BITS_EXCEPT_LOW_NBITS:%.*]] = shl i32 -1, [[NBITS]] +; CHECK-NEXT: [[MAGIC:%.*]] = select i1 [[SHOULD_SIGNEXT]], i32 [[ALL_BITS_EXCEPT_LOW_NBITS]], i32 0 +; CHECK-NEXT: call void @use32(i32 [[LOW_BITS_TO_SKIP]]) +; CHECK-NEXT: call void @use32(i32 [[HIGH_BITS_EXTRACTED]]) +; CHECK-NEXT: call void @use1(i1 [[SHOULD_SIGNEXT]]) +; CHECK-NEXT: call void @use32(i32 [[ALL_BITS_EXCEPT_LOW_NBITS]]) +; CHECK-NEXT: call void @use32(i32 [[MAGIC]]) +; CHECK-NEXT: [[SIGNEXTENDED:%.*]] = add i32 [[HIGH_BITS_EXTRACTED]], [[MAGIC]] +; CHECK-NEXT: ret i32 [[SIGNEXTENDED]] +; + %low_bits_to_skip = sub i32 31, %nbits ; not 32 + %high_bits_extracted = lshr i32 %data, %low_bits_to_skip + %should_signext = icmp slt i32 %data, 0 + %all_bits_except_low_nbits = shl i32 -1, %nbits + %magic = select i1 %should_signext, i32 %all_bits_except_low_nbits, i32 0 + + call void @use32(i32 %low_bits_to_skip) + call void @use32(i32 %high_bits_extracted) + call void @use1(i1 %should_signext) + call void @use32(i32 %all_bits_except_low_nbits) + call void @use32(i32 %magic) + + %signextended = add i32 %high_bits_extracted, %magic + ret i32 %signextended +} + +define i32 @n17_add(i32 %data, i32 %nbits) { +; CHECK-LABEL: @n17_add( +; CHECK-NEXT: [[LOW_BITS_TO_SKIP:%.*]] = sub i32 32, [[NBITS:%.*]] +; CHECK-NEXT: [[HIGH_BITS_EXTRACTED:%.*]] = lshr i32 [[DATA:%.*]], [[LOW_BITS_TO_SKIP]] +; CHECK-NEXT: [[SHOULD_SIGNEXT:%.*]] = icmp slt i32 [[DATA]], 0 +; CHECK-NEXT: [[ALL_BITS_EXCEPT_LOW_NBITS:%.*]] = shl i32 1, [[NBITS]] +; CHECK-NEXT: [[MAGIC:%.*]] = select i1 [[SHOULD_SIGNEXT]], i32 [[ALL_BITS_EXCEPT_LOW_NBITS]], i32 0 +; CHECK-NEXT: call void @use32(i32 [[LOW_BITS_TO_SKIP]]) +; CHECK-NEXT: call void @use32(i32 [[HIGH_BITS_EXTRACTED]]) +; CHECK-NEXT: call void @use1(i1 [[SHOULD_SIGNEXT]]) +; CHECK-NEXT: call void @use32(i32 [[ALL_BITS_EXCEPT_LOW_NBITS]]) +; CHECK-NEXT: call void @use32(i32 [[MAGIC]]) +; CHECK-NEXT: [[SIGNEXTENDED:%.*]] = add i32 [[HIGH_BITS_EXTRACTED]], [[MAGIC]] +; CHECK-NEXT: ret i32 [[SIGNEXTENDED]] +; + %low_bits_to_skip = sub i32 32, %nbits + %high_bits_extracted = lshr i32 %data, %low_bits_to_skip + %should_signext = icmp slt i32 %data, 0 + %all_bits_except_low_nbits = shl i32 1, %nbits ; not -1 + %magic = select i1 %should_signext, i32 %all_bits_except_low_nbits, i32 0 + + call void @use32(i32 %low_bits_to_skip) + call void @use32(i32 %high_bits_extracted) + call void @use1(i1 %should_signext) + call void @use32(i32 %all_bits_except_low_nbits) + call void @use32(i32 %magic) + + %signextended = add i32 %high_bits_extracted, %magic + ret i32 %signextended +} + +define i32 @n18(i32 %data, i32 %nbits) { +; CHECK-LABEL: @n18( +; CHECK-NEXT: [[LOW_BITS_TO_SKIP:%.*]] = sub i32 32, [[NBITS:%.*]] +; CHECK-NEXT: [[HIGH_BITS_EXTRACTED:%.*]] = lshr i32 [[DATA:%.*]], [[LOW_BITS_TO_SKIP]] +; CHECK-NEXT: [[SHOULD_SIGNEXT:%.*]] = icmp slt i32 [[DATA]], 0 +; CHECK-NEXT: [[ALL_BITS_EXCEPT_LOW_NBITS:%.*]] = shl i32 -1, [[NBITS]] +; CHECK-NEXT: [[MAGIC:%.*]] = select i1 [[SHOULD_SIGNEXT]], i32 0, i32 [[ALL_BITS_EXCEPT_LOW_NBITS]] +; CHECK-NEXT: call void @use32(i32 [[LOW_BITS_TO_SKIP]]) +; CHECK-NEXT: call void @use32(i32 [[HIGH_BITS_EXTRACTED]]) +; CHECK-NEXT: call void @use1(i1 [[SHOULD_SIGNEXT]]) +; CHECK-NEXT: call void @use32(i32 [[ALL_BITS_EXCEPT_LOW_NBITS]]) +; CHECK-NEXT: call void @use32(i32 [[MAGIC]]) +; CHECK-NEXT: [[SIGNEXTENDED:%.*]] = add i32 [[HIGH_BITS_EXTRACTED]], [[MAGIC]] +; CHECK-NEXT: ret i32 [[SIGNEXTENDED]] +; + %low_bits_to_skip = sub i32 32, %nbits + %high_bits_extracted = lshr i32 %data, %low_bits_to_skip + %should_signext = icmp slt i32 %data, 0 + %all_bits_except_low_nbits = shl i32 -1, %nbits + %magic = select i1 %should_signext, i32 0, i32 %all_bits_except_low_nbits ; wrong order + + call void @use32(i32 %low_bits_to_skip) + call void @use32(i32 %high_bits_extracted) + call void @use1(i1 %should_signext) + call void @use32(i32 %all_bits_except_low_nbits) + call void @use32(i32 %magic) + + %signextended = add i32 %high_bits_extracted, %magic + ret i32 %signextended +} + +define i32 @n19(i32 %data1, i32 %data2, i32 %nbits) { +; CHECK-LABEL: @n19( +; CHECK-NEXT: [[LOW_BITS_TO_SKIP:%.*]] = sub i32 32, [[NBITS:%.*]] +; CHECK-NEXT: [[HIGH_BITS_EXTRACTED:%.*]] = lshr i32 [[DATA1:%.*]], [[LOW_BITS_TO_SKIP]] +; CHECK-NEXT: [[SHOULD_SIGNEXT:%.*]] = icmp slt i32 [[DATA2:%.*]], 0 +; CHECK-NEXT: [[ALL_BITS_EXCEPT_LOW_NBITS:%.*]] = shl i32 -1, [[NBITS]] +; CHECK-NEXT: [[MAGIC:%.*]] = select i1 [[SHOULD_SIGNEXT]], i32 [[ALL_BITS_EXCEPT_LOW_NBITS]], i32 0 +; CHECK-NEXT: call void @use32(i32 [[LOW_BITS_TO_SKIP]]) +; CHECK-NEXT: call void @use32(i32 [[HIGH_BITS_EXTRACTED]]) +; CHECK-NEXT: call void @use1(i1 [[SHOULD_SIGNEXT]]) +; CHECK-NEXT: call void @use32(i32 [[ALL_BITS_EXCEPT_LOW_NBITS]]) +; CHECK-NEXT: call void @use32(i32 [[MAGIC]]) +; CHECK-NEXT: [[SIGNEXTENDED:%.*]] = add i32 [[HIGH_BITS_EXTRACTED]], [[MAGIC]] +; CHECK-NEXT: ret i32 [[SIGNEXTENDED]] +; + %low_bits_to_skip = sub i32 32, %nbits + %high_bits_extracted = lshr i32 %data1, %low_bits_to_skip ; not %data2 + %should_signext = icmp slt i32 %data2, 0 ; not %data1 + %all_bits_except_low_nbits = shl i32 -1, %nbits + %magic = select i1 %should_signext, i32 %all_bits_except_low_nbits, i32 0 + + call void @use32(i32 %low_bits_to_skip) + call void @use32(i32 %high_bits_extracted) + call void @use1(i1 %should_signext) + call void @use32(i32 %all_bits_except_low_nbits) + call void @use32(i32 %magic) + + %signextended = add i32 %high_bits_extracted, %magic + ret i32 %signextended +} + +define i32 @n20(i32 %data, i32 %nbits1, i32 %nbits2) { +; CHECK-LABEL: @n20( +; CHECK-NEXT: [[LOW_BITS_TO_SKIP:%.*]] = sub i32 32, [[NBITS1:%.*]] +; CHECK-NEXT: [[HIGH_BITS_EXTRACTED:%.*]] = lshr i32 [[DATA:%.*]], [[LOW_BITS_TO_SKIP]] +; CHECK-NEXT: [[SHOULD_SIGNEXT:%.*]] = icmp slt i32 [[DATA]], 0 +; CHECK-NEXT: [[ALL_BITS_EXCEPT_LOW_NBITS:%.*]] = shl i32 -1, [[NBITS2:%.*]] +; CHECK-NEXT: [[MAGIC:%.*]] = select i1 [[SHOULD_SIGNEXT]], i32 [[ALL_BITS_EXCEPT_LOW_NBITS]], i32 0 +; CHECK-NEXT: call void @use32(i32 [[LOW_BITS_TO_SKIP]]) +; CHECK-NEXT: call void @use32(i32 [[HIGH_BITS_EXTRACTED]]) +; CHECK-NEXT: call void @use1(i1 [[SHOULD_SIGNEXT]]) +; CHECK-NEXT: call void @use32(i32 [[ALL_BITS_EXCEPT_LOW_NBITS]]) +; CHECK-NEXT: call void @use32(i32 [[MAGIC]]) +; CHECK-NEXT: [[SIGNEXTENDED:%.*]] = add i32 [[HIGH_BITS_EXTRACTED]], [[MAGIC]] +; CHECK-NEXT: ret i32 [[SIGNEXTENDED]] +; + %low_bits_to_skip = sub i32 32, %nbits1 ; not %nbits2 + %high_bits_extracted = lshr i32 %data, %low_bits_to_skip + %should_signext = icmp slt i32 %data, 0 + %all_bits_except_low_nbits = shl i32 -1, %nbits2 ; not %nbits1 + %magic = select i1 %should_signext, i32 %all_bits_except_low_nbits, i32 0 + + call void @use32(i32 %low_bits_to_skip) + call void @use32(i32 %high_bits_extracted) + call void @use1(i1 %should_signext) + call void @use32(i32 %all_bits_except_low_nbits) + call void @use32(i32 %magic) + + %signextended = add i32 %high_bits_extracted, %magic + ret i32 %signextended +} + +define i32 @n21(i32 %data, i32 %nbits) { +; CHECK-LABEL: @n21( +; CHECK-NEXT: [[LOW_BITS_TO_SKIP:%.*]] = sub i32 32, [[NBITS:%.*]] +; CHECK-NEXT: [[HIGH_BITS_EXTRACTED:%.*]] = lshr i32 [[DATA:%.*]], [[LOW_BITS_TO_SKIP]] +; CHECK-NEXT: [[SHOULD_SIGNEXT:%.*]] = icmp sgt i32 [[DATA]], 0 +; CHECK-NEXT: [[ALL_BITS_EXCEPT_LOW_NBITS:%.*]] = shl i32 -1, [[NBITS]] +; CHECK-NEXT: [[MAGIC:%.*]] = select i1 [[SHOULD_SIGNEXT]], i32 [[ALL_BITS_EXCEPT_LOW_NBITS]], i32 0 +; CHECK-NEXT: call void @use32(i32 [[LOW_BITS_TO_SKIP]]) +; CHECK-NEXT: call void @use32(i32 [[HIGH_BITS_EXTRACTED]]) +; CHECK-NEXT: call void @use1(i1 [[SHOULD_SIGNEXT]]) +; CHECK-NEXT: call void @use32(i32 [[ALL_BITS_EXCEPT_LOW_NBITS]]) +; CHECK-NEXT: call void @use32(i32 [[MAGIC]]) +; CHECK-NEXT: [[SIGNEXTENDED:%.*]] = add i32 [[HIGH_BITS_EXTRACTED]], [[MAGIC]] +; CHECK-NEXT: ret i32 [[SIGNEXTENDED]] +; + %low_bits_to_skip = sub i32 32, %nbits + %high_bits_extracted = lshr i32 %data, %low_bits_to_skip + %should_signext = icmp sgt i32 %data, 0 ; this isn't a sign bit test + %all_bits_except_low_nbits = shl i32 -1, %nbits + %magic = select i1 %should_signext, i32 %all_bits_except_low_nbits, i32 0 + + call void @use32(i32 %low_bits_to_skip) + call void @use32(i32 %high_bits_extracted) + call void @use1(i1 %should_signext) + call void @use32(i32 %all_bits_except_low_nbits) + call void @use32(i32 %magic) + + %signextended = add i32 %high_bits_extracted, %magic + ret i32 %signextended +} + +define i32 @n22(i64 %data, i32 %nbits) { +; CHECK-LABEL: @n22( +; CHECK-NEXT: [[LOW_BITS_TO_SKIP:%.*]] = sub i32 63, [[NBITS:%.*]] +; CHECK-NEXT: [[LOW_BITS_TO_SKIP_WIDE:%.*]] = zext i32 [[LOW_BITS_TO_SKIP]] to i64 +; CHECK-NEXT: [[HIGH_BITS_EXTRACTED_WIDE:%.*]] = lshr i64 [[DATA:%.*]], [[LOW_BITS_TO_SKIP_WIDE]] +; CHECK-NEXT: [[HIGH_BITS_EXTRACTED:%.*]] = trunc i64 [[HIGH_BITS_EXTRACTED_WIDE]] to i32 +; CHECK-NEXT: [[SHOULD_SIGNEXT:%.*]] = icmp slt i64 [[DATA]], 0 +; CHECK-NEXT: [[ALL_BITS_EXCEPT_LOW_NBITS:%.*]] = shl i32 -1, [[NBITS]] +; CHECK-NEXT: [[MAGIC:%.*]] = select i1 [[SHOULD_SIGNEXT]], i32 [[ALL_BITS_EXCEPT_LOW_NBITS]], i32 0 +; CHECK-NEXT: call void @use32(i32 [[LOW_BITS_TO_SKIP]]) +; CHECK-NEXT: call void @use64(i64 [[LOW_BITS_TO_SKIP_WIDE]]) +; CHECK-NEXT: call void @use64(i64 [[HIGH_BITS_EXTRACTED_WIDE]]) +; CHECK-NEXT: call void @use32(i32 [[HIGH_BITS_EXTRACTED]]) +; CHECK-NEXT: call void @use1(i1 [[SHOULD_SIGNEXT]]) +; CHECK-NEXT: call void @use32(i32 [[ALL_BITS_EXCEPT_LOW_NBITS]]) +; CHECK-NEXT: call void @use32(i32 [[MAGIC]]) +; CHECK-NEXT: [[SIGNEXTENDED:%.*]] = add i32 [[MAGIC]], [[HIGH_BITS_EXTRACTED]] +; CHECK-NEXT: ret i32 [[SIGNEXTENDED]] +; + %low_bits_to_skip = sub i32 63, %nbits ; not 64 + %low_bits_to_skip_wide = zext i32 %low_bits_to_skip to i64 + %high_bits_extracted_wide = lshr i64 %data, %low_bits_to_skip_wide + %high_bits_extracted = trunc i64 %high_bits_extracted_wide to i32 + %should_signext = icmp slt i64 %data, 0 + %all_bits_except_low_nbits = shl i32 -1, %nbits + %magic = select i1 %should_signext, i32 %all_bits_except_low_nbits, i32 0 + + call void @use32(i32 %low_bits_to_skip) + call void @use64(i64 %low_bits_to_skip_wide) + call void @use64(i64 %high_bits_extracted_wide) + call void @use32(i32 %high_bits_extracted) + call void @use1(i1 %should_signext) + call void @use32(i32 %all_bits_except_low_nbits) + call void @use32(i32 %magic) + + %signextended = add i32 %magic, %high_bits_extracted + ret i32 %signextended +} + +define i32 @n23(i32 %data, i32 %nbits) { +; CHECK-LABEL: @n23( +; CHECK-NEXT: [[LOW_BITS_TO_SKIP:%.*]] = sub i32 32, [[NBITS:%.*]] +; CHECK-NEXT: [[HIGH_BITS_EXTRACTED:%.*]] = ashr i32 [[DATA:%.*]], [[LOW_BITS_TO_SKIP]] +; CHECK-NEXT: [[SHOULD_SIGNEXT:%.*]] = icmp slt i32 [[DATA]], 0 +; CHECK-NEXT: [[ALL_BITS_EXCEPT_LOW_NBITS:%.*]] = shl i32 -1, [[NBITS]] +; CHECK-NEXT: [[MAGIC:%.*]] = select i1 [[SHOULD_SIGNEXT]], i32 [[ALL_BITS_EXCEPT_LOW_NBITS]], i32 0 +; CHECK-NEXT: call void @use32(i32 [[LOW_BITS_TO_SKIP]]) +; CHECK-NEXT: call void @use32(i32 [[HIGH_BITS_EXTRACTED]]) +; CHECK-NEXT: call void @use1(i1 [[SHOULD_SIGNEXT]]) +; CHECK-NEXT: call void @use32(i32 [[ALL_BITS_EXCEPT_LOW_NBITS]]) +; CHECK-NEXT: call void @use32(i32 [[MAGIC]]) +; CHECK-NEXT: [[SIGNEXTENDED:%.*]] = add i32 [[HIGH_BITS_EXTRACTED]], [[MAGIC]] +; CHECK-NEXT: ret i32 [[SIGNEXTENDED]] +; + %low_bits_to_skip = sub i32 32, %nbits + %high_bits_extracted = ashr i32 %data, %low_bits_to_skip ; not `lshr` + %should_signext = icmp slt i32 %data, 0 + %all_bits_except_low_nbits = shl i32 -1, %nbits + %magic = select i1 %should_signext, i32 %all_bits_except_low_nbits, i32 0 + + call void @use32(i32 %low_bits_to_skip) + call void @use32(i32 %high_bits_extracted) + call void @use1(i1 %should_signext) + call void @use32(i32 %all_bits_except_low_nbits) + call void @use32(i32 %magic) + + %signextended = add i32 %high_bits_extracted, %magic + ret i32 %signextended +} + +define i32 @n24(i32 %data, i32 %nbits) { +; CHECK-LABEL: @n24( +; CHECK-NEXT: [[LOW_BITS_TO_SKIP:%.*]] = sub i32 32, [[NBITS:%.*]] +; CHECK-NEXT: [[HIGH_BITS_EXTRACTED:%.*]] = lshr i32 [[DATA:%.*]], [[LOW_BITS_TO_SKIP]] +; CHECK-NEXT: [[SHOULD_SIGNEXT:%.*]] = icmp slt i32 [[DATA]], 0 +; CHECK-NEXT: [[HIGHER_BIT_AFTER_SIGNBIT:%.*]] = shl i32 1, [[NBITS]] +; CHECK-NEXT: [[MAGIC:%.*]] = select i1 [[SHOULD_SIGNEXT]], i32 [[HIGHER_BIT_AFTER_SIGNBIT]], i32 0 +; CHECK-NEXT: call void @use32(i32 [[LOW_BITS_TO_SKIP]]) +; CHECK-NEXT: call void @use32(i32 [[HIGH_BITS_EXTRACTED]]) +; CHECK-NEXT: call void @use1(i1 [[SHOULD_SIGNEXT]]) +; CHECK-NEXT: call void @use32(i32 [[HIGHER_BIT_AFTER_SIGNBIT]]) +; CHECK-NEXT: call void @use32(i32 [[MAGIC]]) +; CHECK-NEXT: [[SIGNEXTENDED:%.*]] = sub i32 [[MAGIC]], [[HIGH_BITS_EXTRACTED]] +; CHECK-NEXT: ret i32 [[SIGNEXTENDED]] +; + %low_bits_to_skip = sub i32 32, %nbits + %high_bits_extracted = lshr i32 %data, %low_bits_to_skip + %should_signext = icmp slt i32 %data, 0 + %higher_bit_after_signbit = shl i32 1, %nbits + %magic = select i1 %should_signext, i32 %higher_bit_after_signbit, i32 0 + + call void @use32(i32 %low_bits_to_skip) + call void @use32(i32 %high_bits_extracted) + call void @use1(i1 %should_signext) + call void @use32(i32 %higher_bit_after_signbit) + call void @use32(i32 %magic) + + %signextended = sub i32 %magic, %high_bits_extracted ; wrong order; `sub` is not commutative + ret i32 %signextended +} + +define i32 @n25_sub(i32 %data, i32 %nbits) { +; CHECK-LABEL: @n25_sub( +; CHECK-NEXT: [[LOW_BITS_TO_SKIP:%.*]] = sub i32 32, [[NBITS:%.*]] +; CHECK-NEXT: [[HIGH_BITS_EXTRACTED:%.*]] = lshr i32 [[DATA:%.*]], [[LOW_BITS_TO_SKIP]] +; CHECK-NEXT: [[SHOULD_SIGNEXT:%.*]] = icmp slt i32 [[DATA]], 0 +; CHECK-NEXT: [[HIGHER_BIT_AFTER_SIGNBIT:%.*]] = shl i32 -1, [[NBITS]] +; CHECK-NEXT: [[MAGIC:%.*]] = select i1 [[SHOULD_SIGNEXT]], i32 [[HIGHER_BIT_AFTER_SIGNBIT]], i32 0 +; CHECK-NEXT: call void @use32(i32 [[LOW_BITS_TO_SKIP]]) +; CHECK-NEXT: call void @use32(i32 [[HIGH_BITS_EXTRACTED]]) +; CHECK-NEXT: call void @use1(i1 [[SHOULD_SIGNEXT]]) +; CHECK-NEXT: call void @use32(i32 [[HIGHER_BIT_AFTER_SIGNBIT]]) +; CHECK-NEXT: call void @use32(i32 [[MAGIC]]) +; CHECK-NEXT: [[SIGNEXTENDED:%.*]] = sub i32 [[HIGH_BITS_EXTRACTED]], [[MAGIC]] +; CHECK-NEXT: ret i32 [[SIGNEXTENDED]] +; + %low_bits_to_skip = sub i32 32, %nbits + %high_bits_extracted = lshr i32 %data, %low_bits_to_skip + %should_signext = icmp slt i32 %data, 0 + %higher_bit_after_signbit = shl i32 -1, %nbits ; not 1 + %magic = select i1 %should_signext, i32 %higher_bit_after_signbit, i32 0 + + call void @use32(i32 %low_bits_to_skip) + call void @use32(i32 %high_bits_extracted) + call void @use1(i1 %should_signext) + call void @use32(i32 %higher_bit_after_signbit) + call void @use32(i32 %magic) + + %signextended = sub i32 %high_bits_extracted, %magic + ret i32 %signextended +} + +define i32 @n26(i32 %data, i32 %nbits) { +; CHECK-LABEL: @n26( +; CHECK-NEXT: [[LOW_BITS_TO_SKIP:%.*]] = sub i32 32, [[NBITS:%.*]] +; CHECK-NEXT: [[HIGH_BITS_EXTRACTED:%.*]] = lshr i32 [[DATA:%.*]], [[LOW_BITS_TO_SKIP]] +; CHECK-NEXT: [[SHOULD_SIGNEXT:%.*]] = icmp slt i32 [[DATA]], 0 +; CHECK-NEXT: [[ALL_BITS_EXCEPT_LOW_NBITS:%.*]] = shl i32 -1, [[NBITS]] +; CHECK-NEXT: [[MAGIC:%.*]] = select i1 [[SHOULD_SIGNEXT]], i32 [[ALL_BITS_EXCEPT_LOW_NBITS]], i32 -1 +; CHECK-NEXT: call void @use32(i32 [[LOW_BITS_TO_SKIP]]) +; CHECK-NEXT: call void @use32(i32 [[HIGH_BITS_EXTRACTED]]) +; CHECK-NEXT: call void @use1(i1 [[SHOULD_SIGNEXT]]) +; CHECK-NEXT: call void @use32(i32 [[ALL_BITS_EXCEPT_LOW_NBITS]]) +; CHECK-NEXT: call void @use32(i32 [[MAGIC]]) +; CHECK-NEXT: [[SIGNEXTENDED:%.*]] = add i32 [[HIGH_BITS_EXTRACTED]], [[MAGIC]] +; CHECK-NEXT: ret i32 [[SIGNEXTENDED]] +; + %low_bits_to_skip = sub i32 32, %nbits + %high_bits_extracted = lshr i32 %data, %low_bits_to_skip + %should_signext = icmp slt i32 %data, 0 + %all_bits_except_low_nbits = shl i32 -1, %nbits + %magic = select i1 %should_signext, i32 %all_bits_except_low_nbits, i32 -1 ; not 0 + + call void @use32(i32 %low_bits_to_skip) + call void @use32(i32 %high_bits_extracted) + call void @use1(i1 %should_signext) + call void @use32(i32 %all_bits_except_low_nbits) + call void @use32(i32 %magic) + + %signextended = add i32 %high_bits_extracted, %magic + ret i32 %signextended +} + +define i32 @n27_add_zext_of_magic(i32 %data, i8 %nbits) { +; CHECK-LABEL: @n27_add_zext_of_magic( +; CHECK-NEXT: [[NBITS_32BIT:%.*]] = zext i8 [[NBITS:%.*]] to i32 +; CHECK-NEXT: [[LOW_BITS_TO_SKIP:%.*]] = sub nsw i32 32, [[NBITS_32BIT]] +; CHECK-NEXT: [[HIGH_BITS_EXTRACTED:%.*]] = lshr i32 [[DATA:%.*]], [[LOW_BITS_TO_SKIP]] +; CHECK-NEXT: [[SHOULD_SIGNEXT:%.*]] = icmp slt i32 [[DATA]], 0 +; CHECK-NEXT: [[NBITS_16BIT:%.*]] = zext i8 [[NBITS]] to i16 +; CHECK-NEXT: [[ALL_BITS_EXCEPT_LOW_NBITS:%.*]] = shl i16 -1, [[NBITS_16BIT]] +; CHECK-NEXT: [[MAGIC:%.*]] = select i1 [[SHOULD_SIGNEXT]], i16 [[ALL_BITS_EXCEPT_LOW_NBITS]], i16 0 +; CHECK-NEXT: [[MAGIC_WIDE:%.*]] = zext i16 [[MAGIC]] to i32 +; CHECK-NEXT: call void @use32(i32 [[NBITS_32BIT]]) +; CHECK-NEXT: call void @use32(i32 [[LOW_BITS_TO_SKIP]]) +; CHECK-NEXT: call void @use32(i32 [[HIGH_BITS_EXTRACTED]]) +; CHECK-NEXT: call void @use1(i1 [[SHOULD_SIGNEXT]]) +; CHECK-NEXT: call void @use16(i16 [[NBITS_16BIT]]) +; CHECK-NEXT: call void @use16(i16 [[ALL_BITS_EXCEPT_LOW_NBITS]]) +; CHECK-NEXT: call void @use16(i16 [[MAGIC]]) +; CHECK-NEXT: call void @use32(i32 [[MAGIC_WIDE]]) +; CHECK-NEXT: [[SIGNEXTENDED:%.*]] = add i32 [[HIGH_BITS_EXTRACTED]], [[MAGIC_WIDE]] +; CHECK-NEXT: ret i32 [[SIGNEXTENDED]] +; + %nbits_32bit = zext i8 %nbits to i32 + %low_bits_to_skip = sub i32 32, %nbits_32bit + %high_bits_extracted = lshr i32 %data, %low_bits_to_skip + %should_signext = icmp slt i32 %data, 0 + %nbits_16bit = zext i8 %nbits to i16 + %all_bits_except_low_nbits = shl i16 -1, %nbits_16bit + %magic = select i1 %should_signext, i16 %all_bits_except_low_nbits, i16 0 + %magic_wide = zext i16 %magic to i32 ; not sext + + call void @use32(i32 %nbits_32bit) + call void @use32(i32 %low_bits_to_skip) + call void @use32(i32 %high_bits_extracted) + call void @use1(i1 %should_signext) + call void @use16(i16 %nbits_16bit) + call void @use16(i16 %all_bits_except_low_nbits) + call void @use16(i16 %magic) + call void @use32(i32 %magic_wide) + + %signextended = add i32 %high_bits_extracted, %magic_wide + ret i32 %signextended +} + +define i32 @n28_sub_sext_of_magic(i32 %data, i8 %nbits) { +; CHECK-LABEL: @n28_sub_sext_of_magic( +; CHECK-NEXT: [[NBITS_32BIT:%.*]] = zext i8 [[NBITS:%.*]] to i32 +; CHECK-NEXT: [[LOW_BITS_TO_SKIP:%.*]] = sub nsw i32 32, [[NBITS_32BIT]] +; CHECK-NEXT: [[HIGH_BITS_EXTRACTED:%.*]] = lshr i32 [[DATA:%.*]], [[LOW_BITS_TO_SKIP]] +; CHECK-NEXT: [[SHOULD_SIGNEXT:%.*]] = icmp slt i32 [[DATA]], 0 +; CHECK-NEXT: [[NBITS_16BIT:%.*]] = zext i8 [[NBITS]] to i16 +; CHECK-NEXT: [[ALL_BITS_EXCEPT_LOW_NBITS:%.*]] = shl i16 1, [[NBITS_16BIT]] +; CHECK-NEXT: [[MAGIC:%.*]] = select i1 [[SHOULD_SIGNEXT]], i16 [[ALL_BITS_EXCEPT_LOW_NBITS]], i16 0 +; CHECK-NEXT: [[MAGIC_WIDE:%.*]] = sext i16 [[MAGIC]] to i32 +; CHECK-NEXT: call void @use32(i32 [[NBITS_32BIT]]) +; CHECK-NEXT: call void @use32(i32 [[LOW_BITS_TO_SKIP]]) +; CHECK-NEXT: call void @use32(i32 [[HIGH_BITS_EXTRACTED]]) +; CHECK-NEXT: call void @use1(i1 [[SHOULD_SIGNEXT]]) +; CHECK-NEXT: call void @use16(i16 [[NBITS_16BIT]]) +; CHECK-NEXT: call void @use16(i16 [[ALL_BITS_EXCEPT_LOW_NBITS]]) +; CHECK-NEXT: call void @use16(i16 [[MAGIC]]) +; CHECK-NEXT: call void @use32(i32 [[MAGIC_WIDE]]) +; CHECK-NEXT: [[SIGNEXTENDED:%.*]] = sub i32 [[HIGH_BITS_EXTRACTED]], [[MAGIC_WIDE]] +; CHECK-NEXT: ret i32 [[SIGNEXTENDED]] +; + %nbits_32bit = zext i8 %nbits to i32 + %low_bits_to_skip = sub i32 32, %nbits_32bit + %high_bits_extracted = lshr i32 %data, %low_bits_to_skip + %should_signext = icmp slt i32 %data, 0 + %nbits_16bit = zext i8 %nbits to i16 + %all_bits_except_low_nbits = shl i16 1, %nbits_16bit + %magic = select i1 %should_signext, i16 %all_bits_except_low_nbits, i16 0 + %magic_wide = sext i16 %magic to i32 ; not zext + + call void @use32(i32 %nbits_32bit) + call void @use32(i32 %low_bits_to_skip) + call void @use32(i32 %high_bits_extracted) + call void @use1(i1 %should_signext) + call void @use16(i16 %nbits_16bit) + call void @use16(i16 %all_bits_except_low_nbits) + call void @use16(i16 %magic) + call void @use32(i32 %magic_wide) + + %signextended = sub i32 %high_bits_extracted, %magic_wide + ret i32 %signextended +}