Skip to content

Commit 2a0ca17

Browse files
committed
[InstCombine] collectBitParts - add fshl/fshr handling
Pulled from D87452, this is a fixed version of the collectBitParts fshl/fshr handling which as @nikic noticed wasn't checking for different providers or had correct bit ordering (which was hid by only testing shift amounts of bitwidth/2). Differential Revision: https://reviews.llvm.org/D88292
1 parent d3f6972 commit 2a0ca17

File tree

2 files changed

+37
-12
lines changed

2 files changed

+37
-12
lines changed

llvm/lib/Transforms/Utils/Local.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2939,6 +2939,41 @@ collectBitParts(Value *V, bool MatchBSwaps, bool MatchBitReversals,
29392939
Result->Provenance[i] = BitPart::Unset;
29402940
return Result;
29412941
}
2942+
2943+
// Handle intrinsic calls.
2944+
if (auto *II = dyn_cast<IntrinsicInst>(I)) {
2945+
Intrinsic::ID IntrinsicID = II->getIntrinsicID();
2946+
2947+
// Funnel 'double' shifts take 3 operands, 2 inputs and the shift
2948+
// amount (modulo).
2949+
// fshl(X,Y,Z): (X << (Z % BW)) | (Y >> (BW - (Z % BW)))
2950+
// fshr(X,Y,Z): (X << (BW - (Z % BW))) | (Y >> (Z % BW))
2951+
const APInt *Amt;
2952+
if ((IntrinsicID == Intrinsic::fshl || IntrinsicID == Intrinsic::fshr) &&
2953+
match(II->getArgOperand(2), m_APInt(Amt))) {
2954+
2955+
// We can treat fshr as a fshl by flipping the modulo amount.
2956+
unsigned ModAmt = Amt->urem(BitWidth);
2957+
if (IntrinsicID == Intrinsic::fshr)
2958+
ModAmt = BitWidth - ModAmt;
2959+
2960+
const auto &LHS = collectBitParts(II->getArgOperand(0), MatchBSwaps,
2961+
MatchBitReversals, BPS, Depth + 1);
2962+
const auto &RHS = collectBitParts(II->getArgOperand(1), MatchBSwaps,
2963+
MatchBitReversals, BPS, Depth + 1);
2964+
2965+
// Check we have both sources and they are from the same provider.
2966+
if (!LHS || !RHS || !LHS->Provider || LHS->Provider != RHS->Provider)
2967+
return Result;
2968+
2969+
Result = BitPart(LHS->Provider, BitWidth);
2970+
for (unsigned I = 0; I < (BitWidth - ModAmt); ++I)
2971+
Result->Provenance[I + ModAmt] = LHS->Provenance[I];
2972+
for (unsigned I = 0; I < ModAmt; ++I)
2973+
Result->Provenance[I] = RHS->Provenance[I + BitWidth - ModAmt];
2974+
return Result;
2975+
}
2976+
}
29422977
}
29432978

29442979
// Okay, we got to something that isn't a shift, 'or' or 'and'. This must be

llvm/test/Transforms/InstCombine/bswap.ll

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -431,11 +431,7 @@ declare i32 @llvm.fshr.i32(i32, i32, i32)
431431

432432
define i32 @funnel_unary(i32 %abcd) {
433433
; CHECK-LABEL: @funnel_unary(
434-
; CHECK-NEXT: [[DABC:%.*]] = call i32 @llvm.fshl.i32(i32 [[ABCD:%.*]], i32 [[ABCD]], i32 24)
435-
; CHECK-NEXT: [[BCDA:%.*]] = call i32 @llvm.fshl.i32(i32 [[ABCD]], i32 [[ABCD]], i32 8)
436-
; CHECK-NEXT: [[DZBZ:%.*]] = and i32 [[DABC]], -16711936
437-
; CHECK-NEXT: [[ZCZA:%.*]] = and i32 [[BCDA]], 16711935
438-
; CHECK-NEXT: [[DCBA:%.*]] = or i32 [[DZBZ]], [[ZCZA]]
434+
; CHECK-NEXT: [[DCBA:%.*]] = call i32 @llvm.bswap.i32(i32 [[ABCD:%.*]])
439435
; CHECK-NEXT: ret i32 [[DCBA]]
440436
;
441437
%dabc = call i32 @llvm.fshl.i32(i32 %abcd, i32 %abcd, i32 24)
@@ -448,13 +444,7 @@ define i32 @funnel_unary(i32 %abcd) {
448444

449445
define i32 @funnel_binary(i32 %abcd) {
450446
; CHECK-LABEL: @funnel_binary(
451-
; CHECK-NEXT: [[CDZZ:%.*]] = shl i32 [[ABCD:%.*]], 16
452-
; CHECK-NEXT: [[DCDZ:%.*]] = call i32 @llvm.fshl.i32(i32 [[ABCD]], i32 [[CDZZ]], i32 24)
453-
; CHECK-NEXT: [[ZZAB:%.*]] = lshr i32 [[ABCD]], 16
454-
; CHECK-NEXT: [[ZABA:%.*]] = call i32 @llvm.fshl.i32(i32 [[ZZAB]], i32 [[ABCD]], i32 8)
455-
; CHECK-NEXT: [[DCZZ:%.*]] = and i32 [[DCDZ]], -65536
456-
; CHECK-NEXT: [[ZZBA:%.*]] = and i32 [[ZABA]], 65535
457-
; CHECK-NEXT: [[DCBA:%.*]] = or i32 [[DCZZ]], [[ZZBA]]
447+
; CHECK-NEXT: [[DCBA:%.*]] = call i32 @llvm.bswap.i32(i32 [[ABCD:%.*]])
458448
; CHECK-NEXT: ret i32 [[DCBA]]
459449
;
460450
%cdzz = shl i32 %abcd, 16

0 commit comments

Comments
 (0)