Skip to content

Commit 54e9d07

Browse files
author
Leon Clark
committed
Move transform to VectorCombine and update tests.
1 parent d294e75 commit 54e9d07

File tree

6 files changed

+116
-112
lines changed

6 files changed

+116
-112
lines changed

llvm/lib/Transforms/AggressiveInstCombine/AggressiveInstCombine.cpp

Lines changed: 0 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -915,94 +915,6 @@ static bool foldPatternedLoads(Instruction &I, const DataLayout &DL) {
915915
return true;
916916
}
917917

918-
// If `I` is a load instruction, used only by shufflevector instructions with
919-
// poison values, attempt to shrink the load to only the lanes being used.
920-
static bool shrinkLoadsForBroadcast(Instruction &I) {
921-
auto *OldLoad = dyn_cast<LoadInst>(&I);
922-
if (!OldLoad || !OldLoad->isSimple())
923-
return false;
924-
925-
auto *VecTy = dyn_cast<FixedVectorType>(I.getType());
926-
if (!VecTy)
927-
return false;
928-
929-
auto IsPoisonOrUndef = [](Value *V) -> bool {
930-
if (auto *C = dyn_cast<Constant>(V)) {
931-
return isa<PoisonValue>(C) || isa<UndefValue>(C);
932-
}
933-
return false;
934-
};
935-
936-
using IndexRange = std::pair<unsigned, unsigned>;
937-
auto GetIndexRangeInShuffles = [&]() -> std::optional<IndexRange> {
938-
auto OutputRange = IndexRange(VecTy->getNumElements(), 0u);
939-
for (auto &Use : I.uses()) {
940-
// All uses must be ShuffleVector instructions.
941-
auto *Shuffle = dyn_cast<ShuffleVectorInst>(Use.getUser());
942-
if (!Shuffle)
943-
return {};
944-
945-
// Get index range for value.
946-
auto *Op0 = Shuffle->getOperand(0u);
947-
auto *Op1 = Shuffle->getOperand(1u);
948-
if (!IsPoisonOrUndef(Op1))
949-
return {};
950-
951-
// Find the min and max indices used by the ShuffleVector instruction.
952-
auto Mask = Shuffle->getShuffleMask();
953-
auto *Op0Ty = cast<FixedVectorType>(Op0->getType());
954-
auto NumElems = Op0Ty->getNumElements();
955-
956-
for (unsigned Index : Mask) {
957-
if (Index < NumElems) {
958-
OutputRange.first = std::min(Index, OutputRange.first);
959-
OutputRange.second = std::max(Index, OutputRange.second);
960-
}
961-
}
962-
}
963-
return OutputRange;
964-
};
965-
966-
if (auto Indices = GetIndexRangeInShuffles()) {
967-
auto OldSize = VecTy->getNumElements();
968-
auto NewSize = Indices->second + 1u;
969-
970-
if (NewSize < OldSize) {
971-
auto Builder = IRBuilder(&I);
972-
Builder.SetCurrentDebugLocation(I.getDebugLoc());
973-
974-
// Create new load of smaller vector.
975-
auto *ElemTy = VecTy->getElementType();
976-
auto *NewVecTy = FixedVectorType::get(ElemTy, NewSize);
977-
auto *NewLoad = cast<LoadInst>(
978-
Builder.CreateLoad(NewVecTy, OldLoad->getPointerOperand()));
979-
NewLoad->copyMetadata(I);
980-
981-
// Replace all users.
982-
auto OldShuffles = SmallVector<ShuffleVectorInst *, 4u>{};
983-
for (auto &Use : I.uses()) {
984-
auto *Shuffle = cast<ShuffleVectorInst>(Use.getUser());
985-
986-
Builder.SetInsertPoint(Shuffle);
987-
Builder.SetCurrentDebugLocation(Shuffle->getDebugLoc());
988-
auto *NewShuffle = Builder.CreateShuffleVector(
989-
NewLoad, PoisonValue::get(NewVecTy), Shuffle->getShuffleMask());
990-
991-
Shuffle->replaceAllUsesWith(NewShuffle);
992-
OldShuffles.push_back(Shuffle);
993-
}
994-
995-
// Erase old users.
996-
for (auto *Shuffle : OldShuffles)
997-
Shuffle->eraseFromParent();
998-
999-
I.eraseFromParent();
1000-
return true;
1001-
}
1002-
}
1003-
return false;
1004-
}
1005-
1006918
namespace {
1007919
class StrNCmpInliner {
1008920
public:
@@ -1339,7 +1251,6 @@ static bool foldUnusualPatterns(Function &F, DominatorTree &DT,
13391251
MadeChange |= tryToRecognizeTableBasedCttz(I);
13401252
MadeChange |= foldConsecutiveLoads(I, DL, TTI, AA, DT);
13411253
MadeChange |= foldPatternedLoads(I, DL);
1342-
MadeChange |= shrinkLoadsForBroadcast(I);
13431254
// NOTE: This function introduces erasing of the instruction `I`, so it
13441255
// needs to be called at the end of this sequence, otherwise we may make
13451256
// bugs.

llvm/lib/Transforms/Vectorize/VectorCombine.cpp

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ class VectorCombine {
129129
bool foldSelectShuffle(Instruction &I, bool FromReduction = false);
130130
bool foldInterleaveIntrinsics(Instruction &I);
131131
bool shrinkType(Instruction &I);
132+
bool shrinkLoadForShuffles(Instruction &I);
132133

133134
void replaceValue(Value &Old, Value &New) {
134135
LLVM_DEBUG(dbgs() << "VC: Replacing: " << Old << '\n');
@@ -3398,6 +3399,101 @@ bool VectorCombine::foldInterleaveIntrinsics(Instruction &I) {
33983399
return true;
33993400
}
34003401

3402+
// If `I` is a load instruction, used only by shufflevector instructions with
3403+
// poison values, attempt to shrink the load to only the lanes being used.
3404+
bool VectorCombine::shrinkLoadForShuffles(Instruction &I) {
3405+
auto *OldLoad = dyn_cast<LoadInst>(&I);
3406+
if (!OldLoad || !OldLoad->isSimple())
3407+
return false;
3408+
3409+
auto *VecTy = dyn_cast<FixedVectorType>(I.getType());
3410+
if (!VecTy)
3411+
return false;
3412+
3413+
auto IsPoisonOrUndef = [](Value *V) -> bool {
3414+
if (auto *C = dyn_cast<Constant>(V)) {
3415+
return isa<PoisonValue>(C) || isa<UndefValue>(C);
3416+
}
3417+
return false;
3418+
};
3419+
3420+
using IndexRange = std::pair<int, int>;
3421+
auto GetIndexRangeInShuffles = [&]() -> std::optional<IndexRange> {
3422+
auto OutputRange = IndexRange(VecTy->getNumElements(), -1);
3423+
for (auto &Use : I.uses()) {
3424+
// All uses must be ShuffleVector instructions.
3425+
auto *Shuffle = dyn_cast<ShuffleVectorInst>(Use.getUser());
3426+
if (!Shuffle)
3427+
return {};
3428+
3429+
// Get index range for value.
3430+
auto *Op0 = Shuffle->getOperand(0u);
3431+
auto *Op1 = Shuffle->getOperand(1u);
3432+
if (!IsPoisonOrUndef(Op1))
3433+
return {};
3434+
3435+
// Find the min and max indices used by the ShuffleVector instruction.
3436+
auto Mask = Shuffle->getShuffleMask();
3437+
auto *Op0Ty = cast<FixedVectorType>(Op0->getType());
3438+
auto NumElems = int(Op0Ty->getNumElements());
3439+
3440+
for (auto Index : Mask) {
3441+
if (Index >= 0 && Index < NumElems) {
3442+
OutputRange.first = std::min(Index, OutputRange.first);
3443+
OutputRange.second = std::max(Index, OutputRange.second);
3444+
}
3445+
}
3446+
3447+
if (OutputRange.second < OutputRange.first)
3448+
return {};
3449+
}
3450+
return OutputRange;
3451+
};
3452+
3453+
if (auto Indices = GetIndexRangeInShuffles()) {
3454+
auto OldSize = VecTy->getNumElements();
3455+
auto NewSize = Indices->second + 1u;
3456+
3457+
if (NewSize < OldSize) {
3458+
auto Builder = IRBuilder(&I);
3459+
Builder.SetCurrentDebugLocation(I.getDebugLoc());
3460+
3461+
// Create new load of smaller vector.
3462+
auto *ElemTy = VecTy->getElementType();
3463+
auto *NewVecTy = FixedVectorType::get(ElemTy, NewSize);
3464+
auto *NewLoad = cast<LoadInst>(
3465+
Builder.CreateLoad(NewVecTy, OldLoad->getPointerOperand()));
3466+
NewLoad->copyMetadata(I);
3467+
3468+
// Compare cost of old and new loads.
3469+
auto OldCost = TTI.getMemoryOpCost(
3470+
Instruction::Load, OldLoad->getType(), OldLoad->getAlign(),
3471+
OldLoad->getPointerAddressSpace(), CostKind);
3472+
auto NewCost = TTI.getMemoryOpCost(
3473+
Instruction::Load, NewLoad->getType(), NewLoad->getAlign(),
3474+
NewLoad->getPointerAddressSpace(), CostKind);
3475+
3476+
if (OldCost < NewCost || !NewCost.isValid())
3477+
return false;
3478+
3479+
// Replace all users.
3480+
for (auto &Use : I.uses()) {
3481+
auto *Shuffle = cast<ShuffleVectorInst>(Use.getUser());
3482+
3483+
Builder.SetInsertPoint(Shuffle);
3484+
Builder.SetCurrentDebugLocation(Shuffle->getDebugLoc());
3485+
auto *NewShuffle = Builder.CreateShuffleVector(
3486+
NewLoad, PoisonValue::get(NewVecTy), Shuffle->getShuffleMask());
3487+
3488+
replaceValue(*Shuffle, *NewShuffle);
3489+
}
3490+
3491+
return true;
3492+
}
3493+
}
3494+
return false;
3495+
}
3496+
34013497
/// This is the entry point for all transforms. Pass manager differences are
34023498
/// handled in the callers of this function.
34033499
bool VectorCombine::run() {
@@ -3475,6 +3571,9 @@ bool VectorCombine::run() {
34753571
case Instruction::BitCast:
34763572
MadeChange |= foldBitcastShuffle(I);
34773573
break;
3574+
case Instruction::Load:
3575+
MadeChange |= shrinkLoadForShuffles(I);
3576+
break;
34783577
default:
34793578
MadeChange |= shrinkType(I);
34803579
break;

llvm/test/Transforms/PhaseOrdering/X86/vec-load-combine.ll

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@ $getAt = comdat any
1111

1212
define dso_local noundef <4 x float> @ConvertVectors_ByRef(ptr noundef nonnull align 16 dereferenceable(16) %0) #0 {
1313
; SSE-LABEL: @ConvertVectors_ByRef(
14-
; SSE-NEXT: [[TMP2:%.*]] = load <4 x float>, ptr [[TMP0:%.*]], align 16
15-
; SSE-NEXT: [[TMP3:%.*]] = shufflevector <4 x float> [[TMP2]], <4 x float> poison, <4 x i32> <i32 0, i32 1, i32 2, i32 2>
14+
; SSE-NEXT: [[TMP2:%.*]] = load <3 x float>, ptr [[TMP0:%.*]], align 16
15+
; SSE-NEXT: [[TMP3:%.*]] = shufflevector <3 x float> [[TMP2]], <3 x float> poison, <4 x i32> <i32 0, i32 1, i32 2, i32 2>
1616
; SSE-NEXT: ret <4 x float> [[TMP3]]
1717
;
1818
; AVX-LABEL: @ConvertVectors_ByRef(
19-
; AVX-NEXT: [[TMP2:%.*]] = load <4 x float>, ptr [[TMP0:%.*]], align 16
20-
; AVX-NEXT: [[TMP3:%.*]] = shufflevector <4 x float> [[TMP2]], <4 x float> poison, <4 x i32> <i32 0, i32 1, i32 2, i32 2>
19+
; AVX-NEXT: [[TMP2:%.*]] = load <3 x float>, ptr [[TMP0:%.*]], align 16
20+
; AVX-NEXT: [[TMP3:%.*]] = shufflevector <3 x float> [[TMP2]], <3 x float> poison, <4 x i32> <i32 0, i32 1, i32 2, i32 2>
2121
; AVX-NEXT: ret <4 x float> [[TMP3]]
2222
;
2323
%2 = alloca ptr, align 8

llvm/test/Transforms/VectorCombine/X86/load-widening.ll

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ define <8 x float> @load_v2f32_v8f32(ptr dereferenceable(32) %p) {
336336

337337
define <4 x i32> @load_v2i32_v4i32(ptr dereferenceable(16) %p) {
338338
; CHECK-LABEL: @load_v2i32_v4i32(
339-
; CHECK-NEXT: [[S:%.*]] = load <4 x i32>, ptr [[P:%.*]], align 1
339+
; CHECK-NEXT: [[S:%.*]] = load <4 x i32>, ptr [[P:%.*]], align 4
340340
; CHECK-NEXT: ret <4 x i32> [[S]]
341341
;
342342
%l = load <2 x i32>, ptr %p, align 1
@@ -443,8 +443,8 @@ define <8 x float> @load_v2f32_v8f32_hwasan(ptr dereferenceable(32) %p) sanitize
443443

444444
define <4 x i32> @load_v2i32_v4i32_asan(ptr dereferenceable(16) %p) sanitize_address {
445445
; CHECK-LABEL: @load_v2i32_v4i32_asan(
446-
; CHECK-NEXT: [[L:%.*]] = load <2 x i32>, ptr [[P:%.*]], align 1
447-
; CHECK-NEXT: [[S:%.*]] = shufflevector <2 x i32> [[L]], <2 x i32> poison, <4 x i32> <i32 0, i32 poison, i32 poison, i32 poison>
446+
; CHECK-NEXT: [[TMP1:%.*]] = load <1 x i32>, ptr [[P:%.*]], align 4
447+
; CHECK-NEXT: [[S:%.*]] = shufflevector <1 x i32> [[TMP1]], <1 x i32> poison, <4 x i32> <i32 0, i32 poison, i32 poison, i32 poison>
448448
; CHECK-NEXT: ret <4 x i32> [[S]]
449449
;
450450
%l = load <2 x i32>, ptr %p, align 1

llvm/test/Transforms/VectorCombine/X86/shuffle-of-shuffles.ll

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -47,21 +47,12 @@ define <8 x i32> @concat_extract_subvectors_poison(<8 x i32> %x) {
4747
; broadcast loads are free on AVX (and blends are much cheap than general 2-operand shuffles)
4848

4949
define <4 x double> @blend_broadcasts_v4f64(ptr %p0, ptr %p1) {
50-
; SSE-LABEL: define <4 x double> @blend_broadcasts_v4f64(
51-
; SSE-SAME: ptr [[P0:%.*]], ptr [[P1:%.*]]) #[[ATTR0]] {
52-
; SSE-NEXT: [[LD0:%.*]] = load <4 x double>, ptr [[P0]], align 32
53-
; SSE-NEXT: [[LD1:%.*]] = load <4 x double>, ptr [[P1]], align 32
54-
; SSE-NEXT: [[BLEND:%.*]] = shufflevector <4 x double> [[LD0]], <4 x double> [[LD1]], <4 x i32> <i32 0, i32 4, i32 4, i32 0>
55-
; SSE-NEXT: ret <4 x double> [[BLEND]]
56-
;
57-
; AVX-LABEL: define <4 x double> @blend_broadcasts_v4f64(
58-
; AVX-SAME: ptr [[P0:%.*]], ptr [[P1:%.*]]) #[[ATTR0]] {
59-
; AVX-NEXT: [[LD0:%.*]] = load <4 x double>, ptr [[P0]], align 32
60-
; AVX-NEXT: [[LD1:%.*]] = load <4 x double>, ptr [[P1]], align 32
61-
; AVX-NEXT: [[BCST0:%.*]] = shufflevector <4 x double> [[LD0]], <4 x double> undef, <4 x i32> zeroinitializer
62-
; AVX-NEXT: [[BCST1:%.*]] = shufflevector <4 x double> [[LD1]], <4 x double> undef, <4 x i32> zeroinitializer
63-
; AVX-NEXT: [[BLEND:%.*]] = shufflevector <4 x double> [[BCST0]], <4 x double> [[BCST1]], <4 x i32> <i32 0, i32 5, i32 6, i32 3>
64-
; AVX-NEXT: ret <4 x double> [[BLEND]]
50+
; CHECK-LABEL: define <4 x double> @blend_broadcasts_v4f64(
51+
; CHECK-SAME: ptr [[P0:%.*]], ptr [[P1:%.*]]) #[[ATTR0]] {
52+
; CHECK-NEXT: [[TMP1:%.*]] = load <1 x double>, ptr [[P0]], align 8
53+
; CHECK-NEXT: [[TMP2:%.*]] = load <1 x double>, ptr [[P1]], align 8
54+
; CHECK-NEXT: [[BLEND:%.*]] = shufflevector <1 x double> [[TMP1]], <1 x double> [[TMP2]], <4 x i32> <i32 0, i32 1, i32 1, i32 0>
55+
; CHECK-NEXT: ret <4 x double> [[BLEND]]
6556
;
6657
%ld0 = load <4 x double>, ptr %p0, align 32
6758
%ld1 = load <4 x double>, ptr %p1, align 32
@@ -81,3 +72,6 @@ define <2 x float> @PR86068(<2 x float> %a0, <2 x float> %a1) {
8172
%s2 = shufflevector <2 x float> %s1, <2 x float> %a0, <2 x i32> <i32 0, i32 3>
8273
ret <2 x float> %s2
8374
}
75+
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
76+
; AVX: {{.*}}
77+
; SSE: {{.*}}

llvm/test/Transforms/AggressiveInstCombine/load-shufflevector.ll renamed to llvm/test/Transforms/VectorCombine/load-shufflevector.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
2-
; RUN: opt -passes=aggressive-instcombine -S < %s | FileCheck %s
2+
; RUN: opt -passes=vector-combine -S < %s | FileCheck %s
33

44
define <8 x half> @shuffle_v4_v8f16_r0_1_volatile(ptr addrspace(1) nocapture readonly %arg0) local_unnamed_addr {
55
; CHECK-LABEL: define <8 x half> @shuffle_v4_v8f16_r0_1_volatile(

0 commit comments

Comments
 (0)