Files
clang-p2996/llvm/test/Transforms/PhaseOrdering/rotate.ll
Sanjay Patel 200885e654 [AggressiveInstCombine] convert rotate with guard branch into funnel shift (PR34924)
Now, that we have funnel shift intrinsics, it should be safe to convert this form of rotate to it. 
In the worst case (a target that doesn't have rotate instructions), we will expand this into a 
branch-less sequence of ALU ops (neg/and/and/lshr/shl/or) in the backend, so it's still very 
likely to be a perf improvement over the original code.

The motivating source code pattern for this is shown in:
https://bugs.llvm.org/show_bug.cgi?id=34924

Background:
I looked at several different options before deciding where to try this - instcombine, simplifycfg, 
CGP - because it doesn't fit cleanly anywhere AFAIK.

The backend (CGP, SDAG, GlobalIsel?) is too late for what we're trying to accomplish. We want to 
have the IR converted before we reach things like vectorization because the reduced code can make a 
loop much simpler to transform.

Technically, this could be included in instcombine, but it's a large pattern match that includes 
control-flow, so it just felt wrong to stuff into there (although I have a draft of that patch). 
Similarly, this could be part of simplifycfg, but all of this pattern matching is a stretch.

So we're left with our relatively new dumping ground for homeless transforms: aggressive-instcombine. 
This only runs at -O3, but that seems like a reasonable limitation given that source code has many 
options to avoid this pattern (including the recently added clang intrinsics for rotates).

I'm including a PhaseOrdering test because we require the teamwork of 3 passes (aggressive-instcombine, 
instcombine, simplifycfg) to get this into the minimal IR form that we want. That test shows a bug
with the new pass manager that's independent of this change (but it will be masked if we canonicalize
harder to funnel shift intrinsics in instcombine).

Differential Revision: https://reviews.llvm.org/D55604

llvm-svn: 349396
2018-12-17 21:14:51 +00:00

41 lines
1.3 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -O3 -S < %s | FileCheck %s --check-prefixes=ANY,OLDPM
; RUN: opt -passes='default<O3>' -S < %s | FileCheck %s --check-prefixes=ANY,NEWPM
; This should become a single funnel shift through a combination
; of aggressive-instcombine, simplifycfg, and instcombine.
; https://bugs.llvm.org/show_bug.cgi?id=34924
define i32 @rotl(i32 %a, i32 %b) {
; OLDPM-LABEL: @rotl(
; OLDPM-NEXT: entry:
; OLDPM-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.fshl.i32(i32 [[A:%.*]], i32 [[A]], i32 [[B:%.*]])
; OLDPM-NEXT: ret i32 [[TMP0]]
;
; NEWPM-LABEL: @rotl(
; NEWPM-NEXT: entry:
; NEWPM-NEXT: [[TMP0:%.*]] = sub i32 0, [[B:%.*]]
; NEWPM-NEXT: [[TMP1:%.*]] = and i32 [[B]], 31
; NEWPM-NEXT: [[TMP2:%.*]] = and i32 [[TMP0]], 31
; NEWPM-NEXT: [[TMP3:%.*]] = lshr i32 [[A:%.*]], [[TMP2]]
; NEWPM-NEXT: [[TMP4:%.*]] = shl i32 [[A]], [[TMP1]]
; NEWPM-NEXT: [[SPEC_SELECT:%.*]] = or i32 [[TMP3]], [[TMP4]]
; NEWPM-NEXT: ret i32 [[SPEC_SELECT]]
;
entry:
%cmp = icmp eq i32 %b, 0
br i1 %cmp, label %end, label %rotbb
rotbb:
%sub = sub i32 32, %b
%shr = lshr i32 %a, %sub
%shl = shl i32 %a, %b
%or = or i32 %shr, %shl
br label %end
end:
%cond = phi i32 [ %or, %rotbb ], [ %a, %entry ]
ret i32 %cond
}