The idea behind this canonicalization is that it allows us to handle less patterns, because we know that some will be canonicalized away. This is indeed very useful to e.g. know that constants are always on the right. However, this is only useful if the canonicalization is actually reliable. This is the case for constants, but not for arguments: Moving these to the right makes it look like the "more complex" expression is guaranteed to be on the left, but this is not actually the case in practice. It fails as soon as you replace the argument with another instruction. The end result is that it looks like things correctly work in tests, while they actually don't. We use the "thwart complexity-based canonicalization" trick to handle this in tests, but it's often a challenge for new contributors to get this right, and based on the regressions this PR originally exposed, we clearly don't get this right in many cases. For this reason, I think that it's better to remove this complexity canonicalization. It will make it much easier to write tests for commuted cases and make sure that they are handled.
807 lines
26 KiB
LLVM
807 lines
26 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
|
; This test makes sure that these instructions are properly eliminated.
|
|
;
|
|
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
|
|
|
|
declare void @use(i8)
|
|
|
|
define i32 @shl_C1_add_A_C2_i32(i16 %A) {
|
|
; CHECK-LABEL: @shl_C1_add_A_C2_i32(
|
|
; CHECK-NEXT: [[B:%.*]] = zext nneg i16 [[A:%.*]] to i32
|
|
; CHECK-NEXT: [[D:%.*]] = shl i32 192, [[B]]
|
|
; CHECK-NEXT: ret i32 [[D]]
|
|
;
|
|
%B = zext i16 %A to i32
|
|
%C = add i32 %B, 5
|
|
%D = shl i32 6, %C
|
|
ret i32 %D
|
|
}
|
|
|
|
define i32 @ashr_C1_add_A_C2_i32(i32 %A) {
|
|
; CHECK-LABEL: @ashr_C1_add_A_C2_i32(
|
|
; CHECK-NEXT: ret i32 0
|
|
;
|
|
%B = and i32 %A, 65535
|
|
%C = add i32 %B, 5
|
|
%D = ashr i32 6, %C
|
|
ret i32 %D
|
|
}
|
|
|
|
define i32 @lshr_C1_add_A_C2_i32(i32 %A) {
|
|
; CHECK-LABEL: @lshr_C1_add_A_C2_i32(
|
|
; CHECK-NEXT: [[B:%.*]] = and i32 [[A:%.*]], 65535
|
|
; CHECK-NEXT: [[D:%.*]] = shl i32 192, [[B]]
|
|
; CHECK-NEXT: ret i32 [[D]]
|
|
;
|
|
%B = and i32 %A, 65535
|
|
%C = add i32 %B, 5
|
|
%D = shl i32 6, %C
|
|
ret i32 %D
|
|
}
|
|
|
|
define <4 x i32> @shl_C1_add_A_C2_v4i32(<4 x i16> %A) {
|
|
; CHECK-LABEL: @shl_C1_add_A_C2_v4i32(
|
|
; CHECK-NEXT: [[B:%.*]] = zext nneg <4 x i16> [[A:%.*]] to <4 x i32>
|
|
; CHECK-NEXT: [[D:%.*]] = shl <4 x i32> <i32 6, i32 4, i32 poison, i32 -458752>, [[B]]
|
|
; CHECK-NEXT: ret <4 x i32> [[D]]
|
|
;
|
|
%B = zext <4 x i16> %A to <4 x i32>
|
|
%C = add <4 x i32> %B, <i32 0, i32 1, i32 50, i32 16>
|
|
%D = shl <4 x i32> <i32 6, i32 2, i32 1, i32 -7>, %C
|
|
ret <4 x i32> %D
|
|
}
|
|
|
|
define <4 x i32> @ashr_C1_add_A_C2_v4i32(<4 x i32> %A) {
|
|
; CHECK-LABEL: @ashr_C1_add_A_C2_v4i32(
|
|
; CHECK-NEXT: [[B:%.*]] = and <4 x i32> [[A:%.*]], <i32 0, i32 15, i32 255, i32 65535>
|
|
; CHECK-NEXT: [[D:%.*]] = ashr <4 x i32> <i32 6, i32 1, i32 poison, i32 -1>, [[B]]
|
|
; CHECK-NEXT: ret <4 x i32> [[D]]
|
|
;
|
|
%B = and <4 x i32> %A, <i32 0, i32 15, i32 255, i32 65535>
|
|
%C = add <4 x i32> %B, <i32 0, i32 1, i32 50, i32 16>
|
|
%D = ashr <4 x i32> <i32 6, i32 2, i32 1, i32 -7>, %C
|
|
ret <4 x i32> %D
|
|
}
|
|
|
|
define <4 x i32> @lshr_C1_add_A_C2_v4i32(<4 x i32> %A) {
|
|
; CHECK-LABEL: @lshr_C1_add_A_C2_v4i32(
|
|
; CHECK-NEXT: [[B:%.*]] = and <4 x i32> [[A:%.*]], <i32 0, i32 15, i32 255, i32 65535>
|
|
; CHECK-NEXT: [[D:%.*]] = lshr <4 x i32> <i32 6, i32 1, i32 poison, i32 65535>, [[B]]
|
|
; CHECK-NEXT: ret <4 x i32> [[D]]
|
|
;
|
|
%B = and <4 x i32> %A, <i32 0, i32 15, i32 255, i32 65535>
|
|
%C = add <4 x i32> %B, <i32 0, i32 1, i32 50, i32 16>
|
|
%D = lshr <4 x i32> <i32 6, i32 2, i32 1, i32 -7>, %C
|
|
ret <4 x i32> %D
|
|
}
|
|
|
|
define <4 x i32> @shl_C1_add_A_C2_v4i32_splat(i16 %I) {
|
|
; CHECK-LABEL: @shl_C1_add_A_C2_v4i32_splat(
|
|
; CHECK-NEXT: [[A:%.*]] = zext i16 [[I:%.*]] to i32
|
|
; CHECK-NEXT: [[B:%.*]] = insertelement <4 x i32> poison, i32 [[A]], i64 0
|
|
; CHECK-NEXT: [[C:%.*]] = shufflevector <4 x i32> [[B]], <4 x i32> poison, <4 x i32> zeroinitializer
|
|
; CHECK-NEXT: [[E:%.*]] = shl <4 x i32> <i32 6, i32 4, i32 poison, i32 -458752>, [[C]]
|
|
; CHECK-NEXT: ret <4 x i32> [[E]]
|
|
;
|
|
%A = zext i16 %I to i32
|
|
%B = insertelement <4 x i32> undef, i32 %A, i32 0
|
|
%C = shufflevector <4 x i32> %B, <4 x i32> undef, <4 x i32> zeroinitializer
|
|
%D = add <4 x i32> %C, <i32 0, i32 1, i32 50, i32 16>
|
|
%E = shl <4 x i32> <i32 6, i32 2, i32 1, i32 -7>, %D
|
|
ret <4 x i32> %E
|
|
}
|
|
|
|
define <4 x i32> @ashr_C1_add_A_C2_v4i32_splat(i16 %I) {
|
|
; CHECK-LABEL: @ashr_C1_add_A_C2_v4i32_splat(
|
|
; CHECK-NEXT: [[A:%.*]] = zext i16 [[I:%.*]] to i32
|
|
; CHECK-NEXT: [[B:%.*]] = insertelement <4 x i32> poison, i32 [[A]], i64 0
|
|
; CHECK-NEXT: [[C:%.*]] = shufflevector <4 x i32> [[B]], <4 x i32> poison, <4 x i32> zeroinitializer
|
|
; CHECK-NEXT: [[E:%.*]] = ashr <4 x i32> <i32 6, i32 1, i32 poison, i32 -1>, [[C]]
|
|
; CHECK-NEXT: ret <4 x i32> [[E]]
|
|
;
|
|
%A = zext i16 %I to i32
|
|
%B = insertelement <4 x i32> undef, i32 %A, i32 0
|
|
%C = shufflevector <4 x i32> %B, <4 x i32> undef, <4 x i32> zeroinitializer
|
|
%D = add <4 x i32> %C, <i32 0, i32 1, i32 50, i32 16>
|
|
%E = ashr <4 x i32> <i32 6, i32 2, i32 1, i32 -7>, %D
|
|
ret <4 x i32> %E
|
|
}
|
|
|
|
define <4 x i32> @lshr_C1_add_A_C2_v4i32_splat(i16 %I) {
|
|
; CHECK-LABEL: @lshr_C1_add_A_C2_v4i32_splat(
|
|
; CHECK-NEXT: [[A:%.*]] = zext i16 [[I:%.*]] to i32
|
|
; CHECK-NEXT: [[B:%.*]] = insertelement <4 x i32> poison, i32 [[A]], i64 0
|
|
; CHECK-NEXT: [[C:%.*]] = shufflevector <4 x i32> [[B]], <4 x i32> poison, <4 x i32> zeroinitializer
|
|
; CHECK-NEXT: [[E:%.*]] = lshr <4 x i32> <i32 6, i32 1, i32 poison, i32 65535>, [[C]]
|
|
; CHECK-NEXT: ret <4 x i32> [[E]]
|
|
;
|
|
%A = zext i16 %I to i32
|
|
%B = insertelement <4 x i32> undef, i32 %A, i32 0
|
|
%C = shufflevector <4 x i32> %B, <4 x i32> undef, <4 x i32> zeroinitializer
|
|
%D = add <4 x i32> %C, <i32 0, i32 1, i32 50, i32 16>
|
|
%E = lshr <4 x i32> <i32 6, i32 2, i32 1, i32 -7>, %D
|
|
ret <4 x i32> %E
|
|
}
|
|
|
|
define i32 @shl_add_nuw(i32 %x) {
|
|
; CHECK-LABEL: @shl_add_nuw(
|
|
; CHECK-NEXT: [[R:%.*]] = shl i32 192, [[X:%.*]]
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%a = add nuw i32 %x, 5
|
|
%r = shl i32 6, %a
|
|
ret i32 %r
|
|
}
|
|
|
|
; vectors with arbitrary constants work too
|
|
|
|
define <2 x i12> @lshr_add_nuw(<2 x i12> %x) {
|
|
; CHECK-LABEL: @lshr_add_nuw(
|
|
; CHECK-NEXT: [[R:%.*]] = lshr <2 x i12> <i12 0, i12 21>, [[X:%.*]]
|
|
; CHECK-NEXT: ret <2 x i12> [[R]]
|
|
;
|
|
%a = add nuw <2 x i12> %x, <i12 5, i12 1>
|
|
%r = lshr <2 x i12> <i12 6, i12 42>, %a
|
|
ret <2 x i12> %r
|
|
}
|
|
|
|
; extra use is ok and in this case the result can be simplified to a constant
|
|
|
|
define i32 @ashr_add_nuw(i32 %x, ptr %p) {
|
|
; CHECK-LABEL: @ashr_add_nuw(
|
|
; CHECK-NEXT: [[A:%.*]] = add nuw i32 [[X:%.*]], 5
|
|
; CHECK-NEXT: store i32 [[A]], ptr [[P:%.*]], align 4
|
|
; CHECK-NEXT: ret i32 -1
|
|
;
|
|
%a = add nuw i32 %x, 5
|
|
store i32 %a, ptr %p
|
|
%r = ashr i32 -6, %a
|
|
ret i32 %r
|
|
}
|
|
|
|
; Preserve nuw and exact flags.
|
|
|
|
define i32 @shl_nuw_add_nuw(i32 %x) {
|
|
; CHECK-LABEL: @shl_nuw_add_nuw(
|
|
; CHECK-NEXT: [[R:%.*]] = shl nuw i32 2, [[X:%.*]]
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%a = add nuw i32 %x, 1
|
|
%r = shl nuw i32 1, %a
|
|
ret i32 %r
|
|
}
|
|
|
|
define i32 @shl_nsw_add_nuw(i32 %x) {
|
|
; CHECK-LABEL: @shl_nsw_add_nuw(
|
|
; CHECK-NEXT: [[R:%.*]] = shl nsw i32 -2, [[X:%.*]]
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%a = add nuw i32 %x, 1
|
|
%r = shl nsw i32 -1, %a
|
|
ret i32 %r
|
|
}
|
|
|
|
define i32 @lshr_exact_add_nuw(i32 %x) {
|
|
; CHECK-LABEL: @lshr_exact_add_nuw(
|
|
; CHECK-NEXT: [[R:%.*]] = lshr exact i32 2, [[X:%.*]]
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%a = add nuw i32 %x, 1
|
|
%r = lshr exact i32 4, %a
|
|
ret i32 %r
|
|
}
|
|
|
|
define i32 @ashr_exact_add_nuw(i32 %x) {
|
|
; CHECK-LABEL: @ashr_exact_add_nuw(
|
|
; CHECK-NEXT: [[R:%.*]] = ashr exact i32 -2, [[X:%.*]]
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%a = add nuw i32 %x, 1
|
|
%r = ashr exact i32 -4, %a
|
|
ret i32 %r
|
|
}
|
|
|
|
; negative test - must have 'nuw'
|
|
|
|
define i32 @shl_add_nsw(i32 %x) {
|
|
; CHECK-LABEL: @shl_add_nsw(
|
|
; CHECK-NEXT: [[A:%.*]] = add nsw i32 [[X:%.*]], 5
|
|
; CHECK-NEXT: [[R:%.*]] = shl i32 6, [[A]]
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%a = add nsw i32 %x, 5
|
|
%r = shl i32 6, %a
|
|
ret i32 %r
|
|
}
|
|
|
|
; offset precondition check (must be negative constant) for lshr_exact_add_negative_shift_positive
|
|
|
|
define i32 @lshr_exact_add_positive_shift_positive(i32 %x) {
|
|
; CHECK-LABEL: @lshr_exact_add_positive_shift_positive(
|
|
; CHECK-NEXT: [[A:%.*]] = add i32 [[X:%.*]], 1
|
|
; CHECK-NEXT: [[R:%.*]] = lshr exact i32 2, [[A]]
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%a = add i32 %x, 1
|
|
%r = lshr exact i32 2, %a
|
|
ret i32 %r
|
|
}
|
|
|
|
define i32 @lshr_exact_add_big_negative_offset(i32 %x) {
|
|
; CHECK-LABEL: @lshr_exact_add_big_negative_offset(
|
|
; CHECK-NEXT: [[A:%.*]] = add i32 [[X:%.*]], -33
|
|
; CHECK-NEXT: [[R:%.*]] = lshr exact i32 2, [[A]]
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%a = add i32 %x, -33
|
|
%r = lshr exact i32 2, %a
|
|
ret i32 %r
|
|
}
|
|
|
|
; leading zeros for shifted constant precondition check for lshr_exact_add_negative_shift_positive
|
|
|
|
define i32 @lshr_exact_add_negative_shift_negative(i32 %x) {
|
|
; CHECK-LABEL: @lshr_exact_add_negative_shift_negative(
|
|
; CHECK-NEXT: [[A:%.*]] = add i32 [[X:%.*]], -1
|
|
; CHECK-NEXT: [[R:%.*]] = lshr exact i32 -2, [[A]]
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%a = add i32 %x, -1
|
|
%r = lshr exact i32 -2, %a
|
|
ret i32 %r
|
|
}
|
|
|
|
; exact precondition check for lshr_exact_add_negative_shift_positive
|
|
|
|
define i32 @lshr_add_negative_shift_no_exact(i32 %x) {
|
|
; CHECK-LABEL: @lshr_add_negative_shift_no_exact(
|
|
; CHECK-NEXT: [[A:%.*]] = add i32 [[X:%.*]], -1
|
|
; CHECK-NEXT: [[R:%.*]] = lshr i32 2, [[A]]
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%a = add i32 %x, -1
|
|
%r = lshr i32 2, %a
|
|
ret i32 %r
|
|
}
|
|
|
|
define i32 @lshr_exact_add_negative_shift_positive(i32 %x) {
|
|
; CHECK-LABEL: @lshr_exact_add_negative_shift_positive(
|
|
; CHECK-NEXT: [[R:%.*]] = lshr exact i32 4, [[X:%.*]]
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%a = add i32 %x, -1
|
|
%r = lshr exact i32 2, %a
|
|
ret i32 %r
|
|
}
|
|
|
|
define i8 @lshr_exact_add_negative_shift_positive_extra_use(i8 %x) {
|
|
; CHECK-LABEL: @lshr_exact_add_negative_shift_positive_extra_use(
|
|
; CHECK-NEXT: [[A:%.*]] = add i8 [[X:%.*]], -1
|
|
; CHECK-NEXT: call void @use(i8 [[A]])
|
|
; CHECK-NEXT: [[R:%.*]] = lshr exact i8 -128, [[X]]
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%a = add i8 %x, -1
|
|
call void @use(i8 %a)
|
|
%r = lshr exact i8 64, %a
|
|
ret i8 %r
|
|
}
|
|
|
|
define <2 x i9> @lshr_exact_add_negative_shift_positive_vec(<2 x i9> %x) {
|
|
; CHECK-LABEL: @lshr_exact_add_negative_shift_positive_vec(
|
|
; CHECK-NEXT: [[R:%.*]] = lshr exact <2 x i9> <i9 -256, i9 -256>, [[X:%.*]]
|
|
; CHECK-NEXT: ret <2 x i9> [[R]]
|
|
;
|
|
%a = add <2 x i9> %x, <i9 -7, i9 -7>
|
|
%r = lshr exact <2 x i9> <i9 2, i9 2>, %a
|
|
ret <2 x i9> %r
|
|
}
|
|
|
|
; not enough leading zeros in shift constant
|
|
|
|
define <2 x i9> @lshr_exact_add_negative_shift_lzcnt(<2 x i9> %x) {
|
|
; CHECK-LABEL: @lshr_exact_add_negative_shift_lzcnt(
|
|
; CHECK-NEXT: [[A:%.*]] = add <2 x i9> [[X:%.*]], <i9 -7, i9 -7>
|
|
; CHECK-NEXT: [[R:%.*]] = lshr exact <2 x i9> <i9 4, i9 4>, [[A]]
|
|
; CHECK-NEXT: ret <2 x i9> [[R]]
|
|
;
|
|
%a = add <2 x i9> %x, <i9 -7, i9 -7>
|
|
%r = lshr exact <2 x i9> <i9 4, i9 4>, %a
|
|
ret <2 x i9> %r
|
|
}
|
|
|
|
; leading ones precondition check for ashr_exact_add_negative_shift_[positive,negative]
|
|
|
|
define i8 @ashr_exact_add_negative_shift_no_trailing_zeros(i8 %x) {
|
|
; CHECK-LABEL: @ashr_exact_add_negative_shift_no_trailing_zeros(
|
|
; CHECK-NEXT: [[A:%.*]] = add i8 [[X:%.*]], -4
|
|
; CHECK-NEXT: [[R:%.*]] = ashr exact i8 -112, [[A]]
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%a = add i8 %x, -4
|
|
%r = ashr exact i8 -112, %a ; 0b1001_0000
|
|
ret i8 %r
|
|
}
|
|
|
|
define i32 @ashr_exact_add_big_negative_offset(i32 %x) {
|
|
; CHECK-LABEL: @ashr_exact_add_big_negative_offset(
|
|
; CHECK-NEXT: [[A:%.*]] = add i32 [[X:%.*]], -33
|
|
; CHECK-NEXT: [[R:%.*]] = ashr exact i32 -2, [[A]]
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%a = add i32 %x, -33
|
|
%r = ashr exact i32 -2, %a
|
|
ret i32 %r
|
|
}
|
|
|
|
; exact precondition check for ashr_exact_add_negative_shift_[positive,negative]
|
|
|
|
define i32 @ashr_add_negative_shift_no_exact(i32 %x) {
|
|
; CHECK-LABEL: @ashr_add_negative_shift_no_exact(
|
|
; CHECK-NEXT: [[A:%.*]] = add i32 [[X:%.*]], -1
|
|
; CHECK-NEXT: [[R:%.*]] = ashr i32 -2, [[A]]
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%a = add i32 %x, -1
|
|
%r = ashr i32 -2, %a
|
|
ret i32 %r
|
|
}
|
|
|
|
define i32 @ashr_exact_add_negative_shift_negative(i32 %x) {
|
|
; CHECK-LABEL: @ashr_exact_add_negative_shift_negative(
|
|
; CHECK-NEXT: [[R:%.*]] = ashr exact i32 -4, [[X:%.*]]
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%a = add i32 %x, -1
|
|
%r = ashr exact i32 -2, %a
|
|
ret i32 %r
|
|
}
|
|
|
|
define i8 @ashr_exact_add_negative_shift_negative_extra_use(i8 %x) {
|
|
; CHECK-LABEL: @ashr_exact_add_negative_shift_negative_extra_use(
|
|
; CHECK-NEXT: [[A:%.*]] = add i8 [[X:%.*]], -2
|
|
; CHECK-NEXT: call void @use(i8 [[A]])
|
|
; CHECK-NEXT: [[R:%.*]] = ashr exact i8 -128, [[X]]
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%a = add i8 %x, -2
|
|
call void @use(i8 %a)
|
|
%r = ashr exact i8 -32, %a
|
|
ret i8 %r
|
|
}
|
|
|
|
define <2 x i7> @ashr_exact_add_negative_shift_negative_vec(<2 x i7> %x) {
|
|
; CHECK-LABEL: @ashr_exact_add_negative_shift_negative_vec(
|
|
; CHECK-NEXT: [[R:%.*]] = ashr exact <2 x i7> <i7 -64, i7 -64>, [[X:%.*]]
|
|
; CHECK-NEXT: ret <2 x i7> [[R]]
|
|
;
|
|
%a = add <2 x i7> %x, <i7 -5, i7 -5>
|
|
%r = ashr exact <2 x i7> <i7 -2, i7 -2>, %a
|
|
ret <2 x i7> %r
|
|
}
|
|
|
|
; not enough leading ones in shift constant
|
|
|
|
define <2 x i7> @ashr_exact_add_negative_leading_ones_vec(<2 x i7> %x) {
|
|
; CHECK-LABEL: @ashr_exact_add_negative_leading_ones_vec(
|
|
; CHECK-NEXT: [[A:%.*]] = add <2 x i7> [[X:%.*]], <i7 -5, i7 -5>
|
|
; CHECK-NEXT: [[R:%.*]] = ashr exact <2 x i7> <i7 -4, i7 -4>, [[A]]
|
|
; CHECK-NEXT: ret <2 x i7> [[R]]
|
|
;
|
|
%a = add <2 x i7> %x, <i7 -5, i7 -5>
|
|
%r = ashr exact <2 x i7> <i7 -4, i7 -4>, %a
|
|
ret <2 x i7> %r
|
|
}
|
|
|
|
; PR54890
|
|
|
|
define i32 @shl_nsw_add_negative(i32 %x) {
|
|
; CHECK-LABEL: @shl_nsw_add_negative(
|
|
; CHECK-NEXT: [[R:%.*]] = shl nuw i32 1, [[X:%.*]]
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%a = add i32 %x, -1
|
|
%r = shl nsw i32 2, %a
|
|
ret i32 %r
|
|
}
|
|
|
|
; vectors and extra uses are allowed
|
|
; nuw propagates to the new shift
|
|
|
|
define <2 x i8> @shl_nuw_add_negative_splat_uses(<2 x i8> %x, ptr %p) {
|
|
; CHECK-LABEL: @shl_nuw_add_negative_splat_uses(
|
|
; CHECK-NEXT: [[A:%.*]] = add <2 x i8> [[X:%.*]], <i8 -2, i8 -2>
|
|
; CHECK-NEXT: store <2 x i8> [[A]], ptr [[P:%.*]], align 2
|
|
; CHECK-NEXT: [[R:%.*]] = shl nuw <2 x i8> <i8 3, i8 3>, [[X]]
|
|
; CHECK-NEXT: ret <2 x i8> [[R]]
|
|
;
|
|
%a = add <2 x i8> %x, <i8 -2, i8 -2>
|
|
store <2 x i8> %a, ptr %p
|
|
%r = shl nuw <2 x i8> <i8 12, i8 12>, %a
|
|
ret <2 x i8> %r
|
|
}
|
|
|
|
; negative test - shift constant must have enough trailing zeros to allow the pre-shift
|
|
|
|
define i32 @shl_nsw_add_negative_invalid_constant(i32 %x) {
|
|
; CHECK-LABEL: @shl_nsw_add_negative_invalid_constant(
|
|
; CHECK-NEXT: [[A:%.*]] = add i32 [[X:%.*]], -2
|
|
; CHECK-NEXT: [[R:%.*]] = shl nsw i32 2, [[A]]
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%a = add i32 %x, -2
|
|
%r = shl nsw i32 2, %a
|
|
ret i32 %r
|
|
}
|
|
|
|
; negative test - the offset constant must be negative
|
|
|
|
define i32 @shl_nsw_add_positive_invalid_constant(i32 %x) {
|
|
; CHECK-LABEL: @shl_nsw_add_positive_invalid_constant(
|
|
; CHECK-NEXT: [[A:%.*]] = add i32 [[X:%.*]], 2
|
|
; CHECK-NEXT: [[R:%.*]] = shl nsw i32 4, [[A]]
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%a = add i32 %x, 2
|
|
%r = shl nsw i32 4, %a
|
|
ret i32 %r
|
|
}
|
|
|
|
; negative test - a large shift must be detected without crashing
|
|
|
|
define i32 @shl_nsw_add_negative_invalid_constant2(i32 %x) {
|
|
; CHECK-LABEL: @shl_nsw_add_negative_invalid_constant2(
|
|
; CHECK-NEXT: [[A:%.*]] = add i32 [[X:%.*]], -33
|
|
; CHECK-NEXT: [[R:%.*]] = shl nsw i32 2, [[A]]
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%a = add i32 %x, -33
|
|
%r = shl nsw i32 2, %a
|
|
ret i32 %r
|
|
}
|
|
|
|
; negative test - currently transformed to 'xor' before we see it,
|
|
; but INT_MIN should be handled too
|
|
|
|
define i4 @shl_nsw_add_negative_invalid_constant3(i4 %x) {
|
|
; CHECK-LABEL: @shl_nsw_add_negative_invalid_constant3(
|
|
; CHECK-NEXT: [[A:%.*]] = xor i4 [[X:%.*]], -8
|
|
; CHECK-NEXT: [[R:%.*]] = shl nsw i4 2, [[A]]
|
|
; CHECK-NEXT: ret i4 [[R]]
|
|
;
|
|
%a = add i4 %x, 8
|
|
%r = shl nsw i4 2, %a
|
|
ret i4 %r
|
|
}
|
|
|
|
define i2 @lshr_2_add_zext_basic(i1 %a, i1 %b) {
|
|
; CHECK-LABEL: @lshr_2_add_zext_basic(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = and i1 [[A:%.*]], [[B:%.*]]
|
|
; CHECK-NEXT: [[LSHR:%.*]] = zext i1 [[TMP1]] to i2
|
|
; CHECK-NEXT: ret i2 [[LSHR]]
|
|
;
|
|
%zext.a = zext i1 %a to i2
|
|
%zext.b = zext i1 %b to i2
|
|
%add = add i2 %zext.a, %zext.b
|
|
%lshr = lshr i2 %add, 1
|
|
ret i2 %lshr
|
|
}
|
|
|
|
define i2 @ashr_2_add_zext_basic(i1 %a, i1 %b) {
|
|
; CHECK-LABEL: @ashr_2_add_zext_basic(
|
|
; CHECK-NEXT: [[ZEXT_A:%.*]] = zext i1 [[A:%.*]] to i2
|
|
; CHECK-NEXT: [[ZEXT_B:%.*]] = zext i1 [[B:%.*]] to i2
|
|
; CHECK-NEXT: [[ADD:%.*]] = add nuw i2 [[ZEXT_A]], [[ZEXT_B]]
|
|
; CHECK-NEXT: [[LSHR:%.*]] = ashr i2 [[ADD]], 1
|
|
; CHECK-NEXT: ret i2 [[LSHR]]
|
|
;
|
|
%zext.a = zext i1 %a to i2
|
|
%zext.b = zext i1 %b to i2
|
|
%add = add i2 %zext.a, %zext.b
|
|
%lshr = ashr i2 %add, 1
|
|
ret i2 %lshr
|
|
}
|
|
|
|
define i32 @lshr_16_add_zext_basic(i16 %a, i16 %b) {
|
|
; CHECK-LABEL: @lshr_16_add_zext_basic(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i16 [[A:%.*]], -1
|
|
; CHECK-NEXT: [[ADD_NARROWED_OVERFLOW:%.*]] = icmp ugt i16 [[B:%.*]], [[TMP1]]
|
|
; CHECK-NEXT: [[LSHR:%.*]] = zext i1 [[ADD_NARROWED_OVERFLOW]] to i32
|
|
; CHECK-NEXT: ret i32 [[LSHR]]
|
|
;
|
|
%zext.a = zext i16 %a to i32
|
|
%zext.b = zext i16 %b to i32
|
|
%add = add i32 %zext.a, %zext.b
|
|
%lshr = lshr i32 %add, 16
|
|
ret i32 %lshr
|
|
}
|
|
|
|
define i32 @lshr_16_add_zext_basic_multiuse(i16 %a, i16 %b) {
|
|
; CHECK-LABEL: @lshr_16_add_zext_basic_multiuse(
|
|
; CHECK-NEXT: [[ZEXT_A:%.*]] = zext i16 [[A:%.*]] to i32
|
|
; CHECK-NEXT: [[ZEXT_B:%.*]] = zext i16 [[B:%.*]] to i32
|
|
; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i32 [[ZEXT_A]], [[ZEXT_B]]
|
|
; CHECK-NEXT: [[LSHR:%.*]] = lshr i32 [[ADD]], 16
|
|
; CHECK-NEXT: [[OTHERUSE:%.*]] = or i32 [[LSHR]], [[ZEXT_A]]
|
|
; CHECK-NEXT: ret i32 [[OTHERUSE]]
|
|
;
|
|
%zext.a = zext i16 %a to i32
|
|
%zext.b = zext i16 %b to i32
|
|
%add = add i32 %zext.a, %zext.b
|
|
%lshr = lshr i32 %add, 16
|
|
%otheruse = or i32 %lshr, %zext.a
|
|
ret i32 %otheruse
|
|
}
|
|
|
|
define i32 @lshr_16_add_known_16_leading_zeroes(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: @lshr_16_add_known_16_leading_zeroes(
|
|
; CHECK-NEXT: [[A16:%.*]] = and i32 [[A:%.*]], 65535
|
|
; CHECK-NEXT: [[B16:%.*]] = and i32 [[B:%.*]], 65535
|
|
; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i32 [[A16]], [[B16]]
|
|
; CHECK-NEXT: [[LSHR:%.*]] = lshr i32 [[ADD]], 16
|
|
; CHECK-NEXT: ret i32 [[LSHR]]
|
|
;
|
|
%a16 = and i32 %a, 65535 ; 0x65535
|
|
%b16 = and i32 %b, 65535 ; 0x65535
|
|
%add = add i32 %a16, %b16
|
|
%lshr = lshr i32 %add, 16
|
|
ret i32 %lshr
|
|
}
|
|
|
|
define i32 @lshr_16_add_not_known_16_leading_zeroes(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: @lshr_16_add_not_known_16_leading_zeroes(
|
|
; CHECK-NEXT: [[A16:%.*]] = and i32 [[A:%.*]], 131071
|
|
; CHECK-NEXT: [[B16:%.*]] = and i32 [[B:%.*]], 65535
|
|
; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i32 [[A16]], [[B16]]
|
|
; CHECK-NEXT: [[LSHR:%.*]] = lshr i32 [[ADD]], 16
|
|
; CHECK-NEXT: ret i32 [[LSHR]]
|
|
;
|
|
%a16 = and i32 %a, 131071 ; 0x1FFFF
|
|
%b16 = and i32 %b, 65535 ; 0x65535
|
|
%add = add i32 %a16, %b16
|
|
%lshr = lshr i32 %add, 16
|
|
ret i32 %lshr
|
|
}
|
|
|
|
define i64 @lshr_32_add_zext_basic(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: @lshr_32_add_zext_basic(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[A:%.*]], -1
|
|
; CHECK-NEXT: [[ADD_NARROWED_OVERFLOW:%.*]] = icmp ugt i32 [[B:%.*]], [[TMP1]]
|
|
; CHECK-NEXT: [[LSHR:%.*]] = zext i1 [[ADD_NARROWED_OVERFLOW]] to i64
|
|
; CHECK-NEXT: ret i64 [[LSHR]]
|
|
;
|
|
%zext.a = zext i32 %a to i64
|
|
%zext.b = zext i32 %b to i64
|
|
%add = add i64 %zext.a, %zext.b
|
|
%lshr = lshr i64 %add, 32
|
|
ret i64 %lshr
|
|
}
|
|
|
|
define i64 @lshr_32_add_zext_basic_multiuse(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: @lshr_32_add_zext_basic_multiuse(
|
|
; CHECK-NEXT: [[ZEXT_A:%.*]] = zext i32 [[A:%.*]] to i64
|
|
; CHECK-NEXT: [[ZEXT_B:%.*]] = zext i32 [[B:%.*]] to i64
|
|
; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i64 [[ZEXT_A]], [[ZEXT_B]]
|
|
; CHECK-NEXT: [[LSHR:%.*]] = lshr i64 [[ADD]], 32
|
|
; CHECK-NEXT: [[OTHERUSE:%.*]] = or i64 [[LSHR]], [[ZEXT_B]]
|
|
; CHECK-NEXT: ret i64 [[OTHERUSE]]
|
|
;
|
|
%zext.a = zext i32 %a to i64
|
|
%zext.b = zext i32 %b to i64
|
|
%add = add i64 %zext.a, %zext.b
|
|
%lshr = lshr i64 %add, 32
|
|
%otheruse = or i64 %lshr, %zext.b
|
|
ret i64 %otheruse
|
|
}
|
|
|
|
define i64 @lshr_31_i32_add_zext_basic(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: @lshr_31_i32_add_zext_basic(
|
|
; CHECK-NEXT: [[ZEXT_A:%.*]] = zext i32 [[A:%.*]] to i64
|
|
; CHECK-NEXT: [[ZEXT_B:%.*]] = zext i32 [[B:%.*]] to i64
|
|
; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i64 [[ZEXT_A]], [[ZEXT_B]]
|
|
; CHECK-NEXT: [[LSHR:%.*]] = lshr i64 [[ADD]], 31
|
|
; CHECK-NEXT: ret i64 [[LSHR]]
|
|
;
|
|
%zext.a = zext i32 %a to i64
|
|
%zext.b = zext i32 %b to i64
|
|
%add = add i64 %zext.a, %zext.b
|
|
%lshr = lshr i64 %add, 31
|
|
ret i64 %lshr
|
|
}
|
|
|
|
define i64 @lshr_33_i32_add_zext_basic(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: @lshr_33_i32_add_zext_basic(
|
|
; CHECK-NEXT: ret i64 0
|
|
;
|
|
%zext.a = zext i32 %a to i64
|
|
%zext.b = zext i32 %b to i64
|
|
%add = add i64 %zext.a, %zext.b
|
|
%lshr = lshr i64 %add, 33
|
|
ret i64 %lshr
|
|
}
|
|
|
|
define i64 @lshr_16_to_64_add_zext_basic(i16 %a, i16 %b) {
|
|
; CHECK-LABEL: @lshr_16_to_64_add_zext_basic(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i16 [[A:%.*]], -1
|
|
; CHECK-NEXT: [[ADD_NARROWED_OVERFLOW:%.*]] = icmp ugt i16 [[B:%.*]], [[TMP1]]
|
|
; CHECK-NEXT: [[LSHR:%.*]] = zext i1 [[ADD_NARROWED_OVERFLOW]] to i64
|
|
; CHECK-NEXT: ret i64 [[LSHR]]
|
|
;
|
|
%zext.a = zext i16 %a to i64
|
|
%zext.b = zext i16 %b to i64
|
|
%add = add i64 %zext.a, %zext.b
|
|
%lshr = lshr i64 %add, 16
|
|
ret i64 %lshr
|
|
}
|
|
|
|
define i64 @lshr_32_add_known_32_leading_zeroes(i64 %a, i64 %b) {
|
|
; CHECK-LABEL: @lshr_32_add_known_32_leading_zeroes(
|
|
; CHECK-NEXT: [[A32:%.*]] = and i64 [[A:%.*]], 4294967295
|
|
; CHECK-NEXT: [[B32:%.*]] = and i64 [[B:%.*]], 4294967295
|
|
; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i64 [[A32]], [[B32]]
|
|
; CHECK-NEXT: [[LSHR:%.*]] = lshr i64 [[ADD]], 32
|
|
; CHECK-NEXT: ret i64 [[LSHR]]
|
|
;
|
|
%a32 = and i64 %a, 4294967295 ; 0xFFFFFFFF
|
|
%b32 = and i64 %b, 4294967295 ; 0xFFFFFFFF
|
|
%add = add i64 %a32, %b32
|
|
%lshr = lshr i64 %add, 32
|
|
ret i64 %lshr
|
|
}
|
|
|
|
define i64 @lshr_32_add_not_known_32_leading_zeroes(i64 %a, i64 %b) {
|
|
;
|
|
; CHECK-LABEL: @lshr_32_add_not_known_32_leading_zeroes(
|
|
; CHECK-NEXT: [[A32:%.*]] = and i64 [[A:%.*]], 8589934591
|
|
; CHECK-NEXT: [[B32:%.*]] = and i64 [[B:%.*]], 4294967295
|
|
; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i64 [[A32]], [[B32]]
|
|
; CHECK-NEXT: [[LSHR:%.*]] = lshr i64 [[ADD]], 32
|
|
; CHECK-NEXT: ret i64 [[LSHR]]
|
|
;
|
|
%a32 = and i64 %a, 8589934591 ; 0x1FFFFFFFF
|
|
%b32 = and i64 %b, 4294967295 ; 0xFFFFFFFF
|
|
%add = add i64 %a32, %b32
|
|
%lshr = lshr i64 %add, 32
|
|
ret i64 %lshr
|
|
}
|
|
|
|
define i32 @ashr_16_add_zext_basic(i16 %a, i16 %b) {
|
|
; CHECK-LABEL: @ashr_16_add_zext_basic(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i16 [[A:%.*]], -1
|
|
; CHECK-NEXT: [[ADD_NARROWED_OVERFLOW:%.*]] = icmp ugt i16 [[B:%.*]], [[TMP1]]
|
|
; CHECK-NEXT: [[LSHR:%.*]] = zext i1 [[ADD_NARROWED_OVERFLOW]] to i32
|
|
; CHECK-NEXT: ret i32 [[LSHR]]
|
|
;
|
|
%zext.a = zext i16 %a to i32
|
|
%zext.b = zext i16 %b to i32
|
|
%add = add i32 %zext.a, %zext.b
|
|
%lshr = lshr i32 %add, 16
|
|
ret i32 %lshr
|
|
}
|
|
|
|
define i64 @ashr_32_add_zext_basic(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: @ashr_32_add_zext_basic(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[A:%.*]], -1
|
|
; CHECK-NEXT: [[ADD_NARROWED_OVERFLOW:%.*]] = icmp ugt i32 [[B:%.*]], [[TMP1]]
|
|
; CHECK-NEXT: [[LSHR:%.*]] = zext i1 [[ADD_NARROWED_OVERFLOW]] to i64
|
|
; CHECK-NEXT: ret i64 [[LSHR]]
|
|
;
|
|
%zext.a = zext i32 %a to i64
|
|
%zext.b = zext i32 %b to i64
|
|
%add = add i64 %zext.a, %zext.b
|
|
%lshr = ashr i64 %add, 32
|
|
ret i64 %lshr
|
|
}
|
|
|
|
define i64 @ashr_16_to_64_add_zext_basic(i16 %a, i16 %b) {
|
|
; CHECK-LABEL: @ashr_16_to_64_add_zext_basic(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i16 [[A:%.*]], -1
|
|
; CHECK-NEXT: [[ADD_NARROWED_OVERFLOW:%.*]] = icmp ugt i16 [[B:%.*]], [[TMP1]]
|
|
; CHECK-NEXT: [[LSHR:%.*]] = zext i1 [[ADD_NARROWED_OVERFLOW]] to i64
|
|
; CHECK-NEXT: ret i64 [[LSHR]]
|
|
;
|
|
%zext.a = zext i16 %a to i64
|
|
%zext.b = zext i16 %b to i64
|
|
%add = add i64 %zext.a, %zext.b
|
|
%lshr = ashr i64 %add, 16
|
|
ret i64 %lshr
|
|
}
|
|
|
|
define i32 @lshr_32_add_zext_trunc(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: @lshr_32_add_zext_trunc(
|
|
; CHECK-NEXT: [[ADD_NARROWED:%.*]] = add i32 [[A:%.*]], [[B:%.*]]
|
|
; CHECK-NEXT: [[ADD_NARROWED_OVERFLOW:%.*]] = icmp ult i32 [[ADD_NARROWED]], [[A]]
|
|
; CHECK-NEXT: [[TRUNC_SHR:%.*]] = zext i1 [[ADD_NARROWED_OVERFLOW]] to i32
|
|
; CHECK-NEXT: [[RET:%.*]] = add i32 [[ADD_NARROWED]], [[TRUNC_SHR]]
|
|
; CHECK-NEXT: ret i32 [[RET]]
|
|
;
|
|
%zext.a = zext i32 %a to i64
|
|
%zext.b = zext i32 %b to i64
|
|
%add = add i64 %zext.a, %zext.b
|
|
%trunc.add = trunc i64 %add to i32
|
|
%shr = lshr i64 %add, 32
|
|
%trunc.shr = trunc i64 %shr to i32
|
|
%ret = add i32 %trunc.add, %trunc.shr
|
|
ret i32 %ret
|
|
}
|
|
|
|
define <3 x i32> @add3_i96(<3 x i32> %0, <3 x i32> %1) {
|
|
; CHECK-LABEL: @add3_i96(
|
|
; CHECK-NEXT: [[TMP3:%.*]] = extractelement <3 x i32> [[TMP0:%.*]], i64 0
|
|
; CHECK-NEXT: [[TMP4:%.*]] = extractelement <3 x i32> [[TMP1:%.*]], i64 0
|
|
; CHECK-NEXT: [[ADD_NARROWED:%.*]] = add i32 [[TMP4]], [[TMP3]]
|
|
; CHECK-NEXT: [[ADD_NARROWED_OVERFLOW:%.*]] = icmp ult i32 [[ADD_NARROWED]], [[TMP4]]
|
|
; CHECK-NEXT: [[TMP5:%.*]] = extractelement <3 x i32> [[TMP0]], i64 1
|
|
; CHECK-NEXT: [[TMP6:%.*]] = zext i32 [[TMP5]] to i64
|
|
; CHECK-NEXT: [[TMP7:%.*]] = extractelement <3 x i32> [[TMP1]], i64 1
|
|
; CHECK-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i64
|
|
; CHECK-NEXT: [[TMP9:%.*]] = add nuw nsw i64 [[TMP8]], [[TMP6]]
|
|
; CHECK-NEXT: [[TMP10:%.*]] = zext i1 [[ADD_NARROWED_OVERFLOW]] to i64
|
|
; CHECK-NEXT: [[TMP11:%.*]] = add nuw nsw i64 [[TMP9]], [[TMP10]]
|
|
; CHECK-NEXT: [[TMP12:%.*]] = extractelement <3 x i32> [[TMP0]], i64 2
|
|
; CHECK-NEXT: [[TMP13:%.*]] = extractelement <3 x i32> [[TMP1]], i64 2
|
|
; CHECK-NEXT: [[TMP14:%.*]] = add i32 [[TMP13]], [[TMP12]]
|
|
; CHECK-NEXT: [[TMP15:%.*]] = lshr i64 [[TMP11]], 32
|
|
; CHECK-NEXT: [[TMP16:%.*]] = trunc nuw nsw i64 [[TMP15]] to i32
|
|
; CHECK-NEXT: [[TMP17:%.*]] = add i32 [[TMP14]], [[TMP16]]
|
|
; CHECK-NEXT: [[TMP18:%.*]] = insertelement <3 x i32> poison, i32 [[ADD_NARROWED]], i64 0
|
|
; CHECK-NEXT: [[TMP19:%.*]] = trunc i64 [[TMP11]] to i32
|
|
; CHECK-NEXT: [[TMP20:%.*]] = insertelement <3 x i32> [[TMP18]], i32 [[TMP19]], i64 1
|
|
; CHECK-NEXT: [[TMP21:%.*]] = insertelement <3 x i32> [[TMP20]], i32 [[TMP17]], i64 2
|
|
; CHECK-NEXT: ret <3 x i32> [[TMP21]]
|
|
;
|
|
%3 = extractelement <3 x i32> %0, i64 0
|
|
%4 = zext i32 %3 to i64
|
|
%5 = extractelement <3 x i32> %1, i64 0
|
|
%6 = zext i32 %5 to i64
|
|
%7 = add nuw nsw i64 %6, %4
|
|
%8 = extractelement <3 x i32> %0, i64 1
|
|
%9 = zext i32 %8 to i64
|
|
%10 = extractelement <3 x i32> %1, i64 1
|
|
%11 = zext i32 %10 to i64
|
|
%12 = add nuw nsw i64 %11, %9
|
|
%13 = lshr i64 %7, 32
|
|
%14 = add nuw nsw i64 %12, %13
|
|
%15 = extractelement <3 x i32> %0, i64 2
|
|
%16 = extractelement <3 x i32> %1, i64 2
|
|
%17 = add i32 %16, %15
|
|
%18 = lshr i64 %14, 32
|
|
%19 = trunc i64 %18 to i32
|
|
%20 = add i32 %17, %19
|
|
%21 = trunc i64 %7 to i32
|
|
%22 = insertelement <3 x i32> undef, i32 %21, i32 0
|
|
%23 = trunc i64 %14 to i32
|
|
%24 = insertelement <3 x i32> %22, i32 %23, i32 1
|
|
%25 = insertelement <3 x i32> %24, i32 %20, i32 2
|
|
ret <3 x i32> %25
|
|
}
|
|
|
|
define i8 @shl_fold_or_disjoint_cnt(i8 %x) {
|
|
; CHECK-LABEL: @shl_fold_or_disjoint_cnt(
|
|
; CHECK-NEXT: [[R:%.*]] = shl i8 16, [[X:%.*]]
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%a = or disjoint i8 %x, 3
|
|
%r = shl i8 2, %a
|
|
ret i8 %r
|
|
}
|
|
|
|
define <2 x i8> @ashr_fold_or_disjoint_cnt(<2 x i8> %x) {
|
|
; CHECK-LABEL: @ashr_fold_or_disjoint_cnt(
|
|
; CHECK-NEXT: [[R:%.*]] = lshr <2 x i8> <i8 0, i8 1>, [[X:%.*]]
|
|
; CHECK-NEXT: ret <2 x i8> [[R]]
|
|
;
|
|
%a = or disjoint <2 x i8> %x, <i8 3, i8 1>
|
|
%r = ashr <2 x i8> <i8 2, i8 3>, %a
|
|
ret <2 x i8> %r
|
|
}
|
|
|
|
define <2 x i8> @lshr_fold_or_disjoint_cnt_out_of_bounds(<2 x i8> %x) {
|
|
; CHECK-LABEL: @lshr_fold_or_disjoint_cnt_out_of_bounds(
|
|
; CHECK-NEXT: ret <2 x i8> zeroinitializer
|
|
;
|
|
%a = or disjoint <2 x i8> %x, <i8 3, i8 8>
|
|
%r = lshr <2 x i8> <i8 2, i8 3>, %a
|
|
ret <2 x i8> %r
|
|
}
|