Files
clang-p2996/llvm/test/Transforms/InstCombine/shift-shift.ll
Sanjay Patel 3fabd98e5b [InstCombine] fold (trunc (X>>C1)) << C to shift+mask directly
This is no-externally-visible-functional-difference-intended.
That is, the test diffs show identical instructions other than
name changes (those are included specifically to verify the logic).

The existing transforms created extra instructions and relied
on subsequent folds to get to the final result, but that could
conflict with other transforms like the proposed D110170 (and
caused that patch to be reverted twice so far because of infinite
combine loops).
2021-10-01 14:22:44 -04:00

275 lines
7.2 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -instcombine -S | FileCheck %s
declare void @use8(i8)
declare void @use32(i32)
; These would crash if we didn't check for a negative shift.
; https://llvm.org/bugs/show_bug.cgi?id=12967
define void @pr12967() {
; CHECK-LABEL: @pr12967(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: br label [[LOOP]]
;
entry:
br label %loop
loop:
%c = phi i32 [ %shl, %loop ], [ undef, %entry ]
%shr = shl i32 %c, 7
%shl = lshr i32 %shr, -2
br label %loop
}
; https://llvm.org/bugs/show_bug.cgi?id=26760
define void @pr26760() {
; CHECK-LABEL: @pr26760(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: br label [[LOOP]]
;
entry:
br label %loop
loop:
%c = phi i32 [ %shl, %loop ], [ undef, %entry ]
%shr = lshr i32 %c, 7
%shl = shl i32 %shr, -2
br label %loop
}
; Converting the 2 shifts to SHL 6 without the AND is wrong.
; https://llvm.org/bugs/show_bug.cgi?id=8547
define i32 @pr8547(i32* %g) {
; CHECK-LABEL: @pr8547(
; CHECK-NEXT: codeRepl:
; CHECK-NEXT: br label [[FOR_COND:%.*]]
; CHECK: for.cond:
; CHECK-NEXT: [[STOREMERGE:%.*]] = phi i32 [ 0, [[CODEREPL:%.*]] ], [ 5, [[FOR_COND]] ]
; CHECK-NEXT: store i32 [[STOREMERGE]], i32* [[G:%.*]], align 4
; CHECK-NEXT: [[TMP0:%.*]] = shl nuw nsw i32 [[STOREMERGE]], 6
; CHECK-NEXT: [[CONV2:%.*]] = and i32 [[TMP0]], 64
; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[CONV2]], 0
; CHECK-NEXT: br i1 [[TOBOOL]], label [[FOR_COND]], label [[CODEREPL2:%.*]]
; CHECK: codeRepl2:
; CHECK-NEXT: ret i32 [[CONV2]]
;
codeRepl:
br label %for.cond
for.cond:
%storemerge = phi i32 [ 0, %codeRepl ], [ 5, %for.cond ]
store i32 %storemerge, i32* %g, align 4
%shl = shl i32 %storemerge, 30
%conv2 = lshr i32 %shl, 24
%tobool = icmp eq i32 %conv2, 0
br i1 %tobool, label %for.cond, label %codeRepl2
codeRepl2:
ret i32 %conv2
}
; Two same direction shifts that add up to more than the bitwidth should get
; folded to zero.
define i32 @shl_shl(i32 %A) {
; CHECK-LABEL: @shl_shl(
; CHECK-NEXT: ret i32 0
;
%B = shl i32 %A, 6
%C = shl i32 %B, 28
ret i32 %C
}
define <2 x i33> @shl_shl_splat_vec(<2 x i33> %A) {
; CHECK-LABEL: @shl_shl_splat_vec(
; CHECK-NEXT: ret <2 x i33> zeroinitializer
;
%B = shl <2 x i33> %A, <i33 5, i33 5>
%C = shl <2 x i33> %B, <i33 28, i33 28>
ret <2 x i33> %C
}
; FIXME
define <2 x i33> @shl_shl_vec(<2 x i33> %A) {
; CHECK-LABEL: @shl_shl_vec(
; CHECK-NEXT: [[B:%.*]] = shl <2 x i33> [[A:%.*]], <i33 6, i33 5>
; CHECK-NEXT: [[C:%.*]] = shl <2 x i33> [[B]], <i33 27, i33 28>
; CHECK-NEXT: ret <2 x i33> [[C]]
;
%B = shl <2 x i33> %A, <i33 6, i33 5>
%C = shl <2 x i33> %B, <i33 27, i33 28>
ret <2 x i33> %C
}
define i232 @lshr_lshr(i232 %A) {
; CHECK-LABEL: @lshr_lshr(
; CHECK-NEXT: ret i232 0
;
%B = lshr i232 %A, 231
%C = lshr i232 %B, 1
ret i232 %C
}
define <2 x i32> @lshr_lshr_splat_vec(<2 x i32> %A) {
; CHECK-LABEL: @lshr_lshr_splat_vec(
; CHECK-NEXT: ret <2 x i32> zeroinitializer
;
%B = lshr <2 x i32> %A, <i32 28, i32 28>
%C = lshr <2 x i32> %B, <i32 4, i32 4>
ret <2 x i32> %C
}
define <2 x i32> @lshr_lshr_vec(<2 x i32> %A) {
; CHECK-LABEL: @lshr_lshr_vec(
; CHECK-NEXT: ret <2 x i32> zeroinitializer
;
%B = lshr <2 x i32> %A, <i32 29, i32 28>
%C = lshr <2 x i32> %B, <i32 4, i32 5>
ret <2 x i32> %C
}
define i8 @shl_trunc_bigger_lshr(i32 %x) {
; CHECK-LABEL: @shl_trunc_bigger_lshr(
; CHECK-NEXT: [[SH_DIFF:%.*]] = lshr i32 [[X:%.*]], 2
; CHECK-NEXT: [[TR_SH_DIFF:%.*]] = trunc i32 [[SH_DIFF]] to i8
; CHECK-NEXT: [[LT:%.*]] = and i8 [[TR_SH_DIFF]], -8
; CHECK-NEXT: ret i8 [[LT]]
;
%rt = lshr i32 %x, 5
%tr = trunc i32 %rt to i8
%lt = shl i8 %tr, 3
ret i8 %lt
}
define i8 @shl_trunc_smaller_lshr(i32 %x) {
; CHECK-LABEL: @shl_trunc_smaller_lshr(
; CHECK-NEXT: [[X_TR:%.*]] = trunc i32 [[X:%.*]] to i8
; CHECK-NEXT: [[TR_SH_DIFF:%.*]] = shl i8 [[X_TR]], 2
; CHECK-NEXT: [[LT:%.*]] = and i8 [[TR_SH_DIFF]], -32
; CHECK-NEXT: ret i8 [[LT]]
;
%rt = lshr i32 %x, 3
%tr = trunc i32 %rt to i8
%lt = shl i8 %tr, 5
ret i8 %lt
}
define i24 @shl_trunc_bigger_ashr(i32 %x) {
; CHECK-LABEL: @shl_trunc_bigger_ashr(
; CHECK-NEXT: [[SH_DIFF:%.*]] = ashr i32 [[X:%.*]], 9
; CHECK-NEXT: [[TR_SH_DIFF:%.*]] = trunc i32 [[SH_DIFF]] to i24
; CHECK-NEXT: [[LT:%.*]] = and i24 [[TR_SH_DIFF]], -8
; CHECK-NEXT: ret i24 [[LT]]
;
%rt = ashr i32 %x, 12
%tr = trunc i32 %rt to i24
%lt = shl i24 %tr, 3
ret i24 %lt
}
define i24 @shl_trunc_smaller_ashr(i32 %x) {
; CHECK-LABEL: @shl_trunc_smaller_ashr(
; CHECK-NEXT: [[X_TR:%.*]] = trunc i32 [[X:%.*]] to i24
; CHECK-NEXT: [[TR_SH_DIFF:%.*]] = shl i24 [[X_TR]], 3
; CHECK-NEXT: [[LT:%.*]] = and i24 [[TR_SH_DIFF]], -8192
; CHECK-NEXT: ret i24 [[LT]]
;
%rt = ashr i32 %x, 10
%tr = trunc i32 %rt to i24
%lt = shl i24 %tr, 13
ret i24 %lt
}
define i8 @shl_trunc_bigger_shl(i32 %x) {
; CHECK-LABEL: @shl_trunc_bigger_shl(
; CHECK-NEXT: [[X_TR:%.*]] = trunc i32 [[X:%.*]] to i8
; CHECK-NEXT: [[TR:%.*]] = shl i8 [[X_TR]], 6
; CHECK-NEXT: ret i8 [[TR]]
;
%rt = shl i32 %x, 4
%tr = trunc i32 %rt to i8
%lt = shl i8 %tr, 2
ret i8 %lt
}
define i8 @shl_trunc_smaller_shl(i32 %x) {
; CHECK-LABEL: @shl_trunc_smaller_shl(
; CHECK-NEXT: [[X_TR:%.*]] = trunc i32 [[X:%.*]] to i8
; CHECK-NEXT: [[TR:%.*]] = shl i8 [[X_TR]], 6
; CHECK-NEXT: ret i8 [[TR]]
;
%rt = shl i32 %x, 2
%tr = trunc i32 %rt to i8
%lt = shl i8 %tr, 4
ret i8 %lt
}
define i8 @shl_trunc_bigger_lshr_use1(i32 %x) {
; CHECK-LABEL: @shl_trunc_bigger_lshr_use1(
; CHECK-NEXT: [[RT:%.*]] = lshr i32 [[X:%.*]], 5
; CHECK-NEXT: call void @use32(i32 [[RT]])
; CHECK-NEXT: [[TR:%.*]] = trunc i32 [[RT]] to i8
; CHECK-NEXT: [[LT:%.*]] = shl i8 [[TR]], 3
; CHECK-NEXT: ret i8 [[LT]]
;
%rt = lshr i32 %x, 5
call void @use32(i32 %rt)
%tr = trunc i32 %rt to i8
%lt = shl i8 %tr, 3
ret i8 %lt
}
define i8 @shl_trunc_smaller_lshr_use1(i32 %x) {
; CHECK-LABEL: @shl_trunc_smaller_lshr_use1(
; CHECK-NEXT: [[RT:%.*]] = lshr i32 [[X:%.*]], 3
; CHECK-NEXT: call void @use32(i32 [[RT]])
; CHECK-NEXT: [[TR:%.*]] = trunc i32 [[RT]] to i8
; CHECK-NEXT: [[LT:%.*]] = shl i8 [[TR]], 5
; CHECK-NEXT: ret i8 [[LT]]
;
%rt = lshr i32 %x, 3
call void @use32(i32 %rt)
%tr = trunc i32 %rt to i8
%lt = shl i8 %tr, 5
ret i8 %lt
}
define i8 @shl_trunc_bigger_lshr_use2(i32 %x) {
; CHECK-LABEL: @shl_trunc_bigger_lshr_use2(
; CHECK-NEXT: [[RT:%.*]] = lshr i32 [[X:%.*]], 5
; CHECK-NEXT: [[TR:%.*]] = trunc i32 [[RT]] to i8
; CHECK-NEXT: call void @use8(i8 [[TR]])
; CHECK-NEXT: [[LT:%.*]] = shl i8 [[TR]], 3
; CHECK-NEXT: ret i8 [[LT]]
;
%rt = lshr i32 %x, 5
%tr = trunc i32 %rt to i8
call void @use8(i8 %tr)
%lt = shl i8 %tr, 3
ret i8 %lt
}
define i8 @shl_trunc_smaller_lshr_use2(i32 %x) {
; CHECK-LABEL: @shl_trunc_smaller_lshr_use2(
; CHECK-NEXT: [[RT:%.*]] = lshr i32 [[X:%.*]], 3
; CHECK-NEXT: [[TR:%.*]] = trunc i32 [[RT]] to i8
; CHECK-NEXT: call void @use8(i8 [[TR]])
; CHECK-NEXT: [[LT:%.*]] = shl i8 [[TR]], 5
; CHECK-NEXT: ret i8 [[LT]]
;
%rt = lshr i32 %x, 3
%tr = trunc i32 %rt to i8
call void @use8(i8 %tr)
%lt = shl i8 %tr, 5
ret i8 %lt
}