| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py |
| ; RUN: opt < %s -passes=instcombine -S | FileCheck %s |
| |
| ; Iff we know that trunc only chops off the sign bits, |
| ; and not all of them, then we can bypass said trunc |
| ; for the purpose of sign extension. |
| |
| declare void @use8(i8) |
| declare void @use4(i4) |
| declare void @usevec(<2 x i8>) |
| |
| define i16 @t0(i8 %x) { |
| ; CHECK-LABEL: @t0( |
| ; CHECK-NEXT: [[A:%.*]] = ashr i8 [[X:%.*]], 5 |
| ; CHECK-NEXT: call void @use8(i8 [[A]]) |
| ; CHECK-NEXT: [[C:%.*]] = sext i8 [[A]] to i16 |
| ; CHECK-NEXT: ret i16 [[C]] |
| ; |
| %a = ashr i8 %x, 5 |
| call void @use8(i8 %a) |
| %b = trunc i8 %a to i4 |
| %c = sext i4 %b to i16 |
| ret i16 %c |
| } |
| |
| define i16 @t1(i8 %x) { |
| ; CHECK-LABEL: @t1( |
| ; CHECK-NEXT: [[A:%.*]] = ashr i8 [[X:%.*]], 4 |
| ; CHECK-NEXT: call void @use8(i8 [[A]]) |
| ; CHECK-NEXT: [[C:%.*]] = sext i8 [[A]] to i16 |
| ; CHECK-NEXT: ret i16 [[C]] |
| ; |
| %a = ashr i8 %x, 4 |
| call void @use8(i8 %a) |
| %b = trunc i8 %a to i4 |
| %c = sext i4 %b to i16 |
| ret i16 %c |
| } |
| |
| ; Here we don't know that %a has any sign bits from %x left |
| define i16 @n2(i8 %x) { |
| ; CHECK-LABEL: @n2( |
| ; CHECK-NEXT: [[A:%.*]] = ashr i8 [[X:%.*]], 3 |
| ; CHECK-NEXT: call void @use8(i8 [[A]]) |
| ; CHECK-NEXT: [[B:%.*]] = trunc i8 [[A]] to i4 |
| ; CHECK-NEXT: [[C:%.*]] = sext i4 [[B]] to i16 |
| ; CHECK-NEXT: ret i16 [[C]] |
| ; |
| %a = ashr i8 %x, 3 |
| call void @use8(i8 %a) |
| %b = trunc i8 %a to i4 |
| %c = sext i4 %b to i16 |
| ret i16 %c |
| } |
| |
| define <2 x i16> @t3_vec(<2 x i8> %x) { |
| ; CHECK-LABEL: @t3_vec( |
| ; CHECK-NEXT: [[A:%.*]] = ashr <2 x i8> [[X:%.*]], <i8 4, i8 4> |
| ; CHECK-NEXT: call void @usevec(<2 x i8> [[A]]) |
| ; CHECK-NEXT: [[C:%.*]] = sext <2 x i8> [[A]] to <2 x i16> |
| ; CHECK-NEXT: ret <2 x i16> [[C]] |
| ; |
| %a = ashr <2 x i8> %x, <i8 4, i8 4> |
| call void @usevec(<2 x i8> %a) |
| %b = trunc <2 x i8> %a to <2 x i4> |
| %c = sext <2 x i4> %b to <2 x i16> |
| ret <2 x i16> %c |
| } |
| |
| define <2 x i16> @t4_vec_nonsplat(<2 x i8> %x) { |
| ; CHECK-LABEL: @t4_vec_nonsplat( |
| ; CHECK-NEXT: [[A:%.*]] = ashr <2 x i8> [[X:%.*]], <i8 4, i8 3> |
| ; CHECK-NEXT: call void @usevec(<2 x i8> [[A]]) |
| ; CHECK-NEXT: [[B:%.*]] = trunc <2 x i8> [[A]] to <2 x i4> |
| ; CHECK-NEXT: [[C:%.*]] = sext <2 x i4> [[B]] to <2 x i16> |
| ; CHECK-NEXT: ret <2 x i16> [[C]] |
| ; |
| %a = ashr <2 x i8> %x, <i8 4, i8 3> |
| call void @usevec(<2 x i8> %a) |
| %b = trunc <2 x i8> %a to <2 x i4> |
| %c = sext <2 x i4> %b to <2 x i16> |
| ret <2 x i16> %c |
| } |
| |
| define i16 @t5_extrause(i8 %x) { |
| ; CHECK-LABEL: @t5_extrause( |
| ; CHECK-NEXT: [[A:%.*]] = ashr i8 [[X:%.*]], 5 |
| ; CHECK-NEXT: call void @use8(i8 [[A]]) |
| ; CHECK-NEXT: [[B:%.*]] = trunc i8 [[A]] to i4 |
| ; CHECK-NEXT: call void @use4(i4 [[B]]) |
| ; CHECK-NEXT: [[C:%.*]] = sext i8 [[A]] to i16 |
| ; CHECK-NEXT: ret i16 [[C]] |
| ; |
| %a = ashr i8 %x, 5 |
| call void @use8(i8 %a) |
| %b = trunc i8 %a to i4 |
| call void @use4(i4 %b) |
| %c = sext i4 %b to i16 |
| ret i16 %c |
| } |
| |
| define i64 @narrow_source_matching_signbits(i32 %x) { |
| ; CHECK-LABEL: @narrow_source_matching_signbits( |
| ; CHECK-NEXT: [[M:%.*]] = and i32 [[X:%.*]], 7 |
| ; CHECK-NEXT: [[A:%.*]] = shl nsw i32 -1, [[M]] |
| ; CHECK-NEXT: [[C:%.*]] = sext i32 [[A]] to i64 |
| ; CHECK-NEXT: ret i64 [[C]] |
| ; |
| %m = and i32 %x, 7 |
| %a = shl nsw i32 -1, %m |
| %b = trunc i32 %a to i8 |
| %c = sext i8 %b to i64 |
| ret i64 %c |
| } |
| |
| ; negative test - not enough sign-bits |
| |
| define i64 @narrow_source_not_matching_signbits(i32 %x) { |
| ; CHECK-LABEL: @narrow_source_not_matching_signbits( |
| ; CHECK-NEXT: [[M:%.*]] = and i32 [[X:%.*]], 8 |
| ; CHECK-NEXT: [[A:%.*]] = shl nsw i32 -1, [[M]] |
| ; CHECK-NEXT: [[B:%.*]] = trunc i32 [[A]] to i8 |
| ; CHECK-NEXT: [[C:%.*]] = sext i8 [[B]] to i64 |
| ; CHECK-NEXT: ret i64 [[C]] |
| ; |
| %m = and i32 %x, 8 |
| %a = shl nsw i32 -1, %m |
| %b = trunc i32 %a to i8 |
| %c = sext i8 %b to i64 |
| ret i64 %c |
| } |
| |
| define i24 @wide_source_matching_signbits(i32 %x) { |
| ; CHECK-LABEL: @wide_source_matching_signbits( |
| ; CHECK-NEXT: [[M:%.*]] = and i32 [[X:%.*]], 7 |
| ; CHECK-NEXT: [[A:%.*]] = shl nsw i32 -1, [[M]] |
| ; CHECK-NEXT: [[C:%.*]] = trunc i32 [[A]] to i24 |
| ; CHECK-NEXT: ret i24 [[C]] |
| ; |
| %m = and i32 %x, 7 |
| %a = shl nsw i32 -1, %m |
| %b = trunc i32 %a to i8 |
| %c = sext i8 %b to i24 |
| ret i24 %c |
| } |
| |
| ; negative test - not enough sign-bits |
| |
| define i24 @wide_source_not_matching_signbits(i32 %x) { |
| ; CHECK-LABEL: @wide_source_not_matching_signbits( |
| ; CHECK-NEXT: [[M2:%.*]] = and i32 [[X:%.*]], 8 |
| ; CHECK-NEXT: [[A:%.*]] = shl nsw i32 -1, [[M2]] |
| ; CHECK-NEXT: [[B:%.*]] = trunc i32 [[A]] to i8 |
| ; CHECK-NEXT: [[C:%.*]] = sext i8 [[B]] to i24 |
| ; CHECK-NEXT: ret i24 [[C]] |
| ; |
| %m2 = and i32 %x, 8 |
| %a = shl nsw i32 -1, %m2 |
| %b = trunc i32 %a to i8 |
| %c = sext i8 %b to i24 |
| ret i24 %c |
| } |
| |
| define i32 @same_source_matching_signbits(i32 %x) { |
| ; CHECK-LABEL: @same_source_matching_signbits( |
| ; CHECK-NEXT: [[M:%.*]] = and i32 [[X:%.*]], 7 |
| ; CHECK-NEXT: [[A:%.*]] = shl nsw i32 -1, [[M]] |
| ; CHECK-NEXT: ret i32 [[A]] |
| ; |
| %m = and i32 %x, 7 |
| %a = shl nsw i32 -1, %m |
| %b = trunc i32 %a to i8 |
| %c = sext i8 %b to i32 |
| ret i32 %c |
| } |
| |
| ; negative test - not enough sign-bits |
| |
| define i32 @same_source_not_matching_signbits(i32 %x) { |
| ; CHECK-LABEL: @same_source_not_matching_signbits( |
| ; CHECK-NEXT: [[M2:%.*]] = and i32 [[X:%.*]], 8 |
| ; CHECK-NEXT: [[TMP1:%.*]] = shl i32 -16777216, [[M2]] |
| ; CHECK-NEXT: [[C:%.*]] = ashr exact i32 [[TMP1]], 24 |
| ; CHECK-NEXT: ret i32 [[C]] |
| ; |
| %m2 = and i32 %x, 8 |
| %a = shl nsw i32 -1, %m2 |
| %b = trunc i32 %a to i8 |
| %c = sext i8 %b to i32 |
| ret i32 %c |
| } |
| |
| define i32 @same_source_matching_signbits_extra_use(i32 %x) { |
| ; CHECK-LABEL: @same_source_matching_signbits_extra_use( |
| ; CHECK-NEXT: [[M:%.*]] = and i32 [[X:%.*]], 7 |
| ; CHECK-NEXT: [[A:%.*]] = shl nsw i32 -1, [[M]] |
| ; CHECK-NEXT: [[B:%.*]] = trunc i32 [[A]] to i8 |
| ; CHECK-NEXT: call void @use8(i8 [[B]]) |
| ; CHECK-NEXT: ret i32 [[A]] |
| ; |
| %m = and i32 %x, 7 |
| %a = shl nsw i32 -1, %m |
| %b = trunc i32 %a to i8 |
| call void @use8(i8 %b) |
| %c = sext i8 %b to i32 |
| ret i32 %c |
| } |
| |
| define i32 @same_source_not_matching_signbits_extra_use(i32 %x) { |
| ; CHECK-LABEL: @same_source_not_matching_signbits_extra_use( |
| ; CHECK-NEXT: [[M2:%.*]] = and i32 [[X:%.*]], 8 |
| ; CHECK-NEXT: [[A:%.*]] = shl nsw i32 -1, [[M2]] |
| ; CHECK-NEXT: [[B:%.*]] = trunc i32 [[A]] to i8 |
| ; CHECK-NEXT: call void @use8(i8 [[B]]) |
| ; CHECK-NEXT: [[C:%.*]] = sext i8 [[B]] to i32 |
| ; CHECK-NEXT: ret i32 [[C]] |
| ; |
| %m2 = and i32 %x, 8 |
| %a = shl nsw i32 -1, %m2 |
| %b = trunc i32 %a to i8 |
| call void @use8(i8 %b) |
| %c = sext i8 %b to i32 |
| ret i32 %c |
| } |