Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 14 additions & 7 deletions llvm/include/llvm/Analysis/IVUsers.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// Modifications (c) Copyright 2026 Advanced Micro Devices, Inc. or its
// affiliates
//
//===----------------------------------------------------------------------===//
//
// This file implements bookkeeping for "interesting" users of expressions
Expand All @@ -26,6 +29,7 @@ class AssumptionCache;
class DominatorTree;
class ScalarEvolution;
class SCEV;
class TargetTransformInfo;
class IVUsers;

/// IVStrideUse - Keep track of one use of a strided induction variable.
Expand Down Expand Up @@ -95,6 +99,7 @@ class IVUsers {
LoopInfo *LI;
DominatorTree *DT;
ScalarEvolution *SE;
const TargetTransformInfo *TTI;
SmallPtrSet<Instruction*, 16> Processed;

/// IVUses - A list of all tracked IV uses of induction variable expressions
Expand All @@ -106,12 +111,13 @@ class IVUsers {

public:
IVUsers(Loop *L, AssumptionCache *AC, LoopInfo *LI, DominatorTree *DT,
ScalarEvolution *SE);
ScalarEvolution *SE, const TargetTransformInfo *TTI = nullptr);

IVUsers(IVUsers &&X)
: L(std::move(X.L)), AC(std::move(X.AC)), DT(std::move(X.DT)),
SE(std::move(X.SE)), Processed(std::move(X.Processed)),
IVUses(std::move(X.IVUses)), EphValues(std::move(X.EphValues)) {
SE(std::move(X.SE)), TTI(std::move(X.TTI)),
Processed(std::move(X.Processed)), IVUses(std::move(X.IVUses)),
EphValues(std::move(X.EphValues)) {
for (IVStrideUse &U : IVUses)
U.Parent = this;
}
Expand All @@ -121,10 +127,11 @@ class IVUsers {

Loop *getLoop() const { return L; }

/// AddUsersIfInteresting - Inspect the specified Instruction. If it is a
/// reducible SCEV, recursively add its users to the IVUsesByStride set and
/// return true. Otherwise, return false.
bool AddUsersIfInteresting(Instruction *I);
/// Inspect the specified Instruction. If it is a reducible SCEV, recursively
/// add its users to the IVUsesByStride set and return true. Otherwise,
/// return false. If \p BypassWidthCheck is true, skip the type width
/// validation (used when the caller has already verified the type via TTI).
bool AddUsersIfInteresting(Instruction *I, bool BypassWidthCheck = false);
Comment thread
F-Stuckmann marked this conversation as resolved.

IVStrideUse &AddUser(Instruction *User, Value *Operand);

Expand Down
32 changes: 31 additions & 1 deletion llvm/include/llvm/Analysis/TargetTransformInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// Modifications (c) Copyright 2023-2024 Advanced Micro Devices, Inc. or its
// Modifications (c) Copyright 2023-2026 Advanced Micro Devices, Inc. or its
// affiliates
//
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -66,6 +66,8 @@ class SmallBitVector;
class StoreInst;
class SwitchInst;
class TargetLibraryInfo;
class TruncInst;
class GetElementPtrInst;
class Type;
class VPIntrinsic;
struct KnownBits;
Expand Down Expand Up @@ -798,6 +800,22 @@ class TargetTransformInfo {
AddressingModeKind getPreferredAddressingMode(const Loop *L,
ScalarEvolution *SE) const;

/// Return true if IVUsers() should look through the instruction to collect
/// its users instead. If true, populates GEPsToProcess with the GEP
/// instructions to process as IV users.
Copy link
Copy Markdown
Collaborator

@martien-de-jong martien-de-jong Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's just collecting interesting GEPs. This can be reflected in the name and its return value can be replaced by !GEPsToProcess.empty();

/// This is useful for targets where pointer and integer bit sizes differ
/// (e.g., 20-bit pointers with 32-bit integers), causing truncs to index
/// size that feed GEP indices.
bool shouldIVUsersLookThroughInst(
Instruction *I,
SmallVectorImpl<GetElementPtrInst *> &GEPsToProcess) const;

/// Return true if the given type is valid for IV user collection.
/// By default, only legal integer widths up to 64 bits are allowed.
/// Targets where pointer and integer bit sizes differ may override this
/// to allow index-sized integers or pointers.
bool isValidIVUserType(Type *Ty) const;

/// Return true if the target supports masked store.
bool isLegalMaskedStore(Type *DataType, Align Alignment) const;
/// Return true if the target supports masked load.
Expand Down Expand Up @@ -2009,6 +2027,10 @@ class TargetTransformInfo::Concept {
TargetLibraryInfo *LibInfo) = 0;
virtual AddressingModeKind
getPreferredAddressingMode(const Loop *L, ScalarEvolution *SE) const = 0;
virtual bool shouldIVUsersLookThroughInst(
Instruction *I,
SmallVectorImpl<GetElementPtrInst *> &GEPsToProcess) const = 0;
virtual bool isValidIVUserType(Type *Ty) const = 0;
virtual bool isLegalMaskedStore(Type *DataType, Align Alignment) = 0;
virtual bool isLegalMaskedLoad(Type *DataType, Align Alignment) = 0;
virtual bool isLegalNTStore(Type *DataType, Align Alignment) = 0;
Expand Down Expand Up @@ -2553,6 +2575,14 @@ class TargetTransformInfo::Model final : public TargetTransformInfo::Concept {
ScalarEvolution *SE) const override {
return Impl.getPreferredAddressingMode(L, SE);
}
bool shouldIVUsersLookThroughInst(
Instruction *I,
SmallVectorImpl<GetElementPtrInst *> &GEPsToProcess) const override {
return Impl.shouldIVUsersLookThroughInst(I, GEPsToProcess);
}
bool isValidIVUserType(Type *Ty) const override {
return Impl.isValidIVUserType(Ty);
}
bool isLegalMaskedStore(Type *DataType, Align Alignment) override {
return Impl.isLegalMaskedStore(DataType, Alignment);
}
Expand Down
18 changes: 17 additions & 1 deletion llvm/include/llvm/Analysis/TargetTransformInfoImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// Modifications (c) Copyright 2023-2024 Advanced Micro Devices, Inc. or its
// Modifications (c) Copyright 2023-2026 Advanced Micro Devices, Inc. or its
// affiliates
//
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -283,6 +283,22 @@ class TargetTransformInfoImplBase {
return TTI::AMK_None;
}

/// By default, do not look through instructions in IVUsers.
bool shouldIVUsersLookThroughInst(
Instruction *I,
SmallVectorImpl<GetElementPtrInst *> &GEPsToProcess) const {
return false;
}

/// By default, only legal integer widths up to 64 bits are valid for IV
/// users.
bool isValidIVUserType(Type *Ty) const {
if (!Ty->isIntegerTy() && !Ty->isPointerTy())
return false;
const unsigned Width = DL.getTypeSizeInBits(Ty);
return Width <= 64 && DL.isLegalInteger(Width);
}

bool isLegalMaskedStore(Type *DataType, Align Alignment) const {
return false;
}
Expand Down
42 changes: 34 additions & 8 deletions llvm/lib/Analysis/IVUsers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// Modifications (c) Copyright 2026 Advanced Micro Devices, Inc. or its
// affiliates
//
//===----------------------------------------------------------------------===//
//
// This file implements bookkeeping for "interesting" users of expressions
Expand All @@ -18,6 +21,7 @@
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/LoopPass.h"
#include "llvm/Analysis/ScalarEvolutionExpressions.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/IR/DataLayout.h"
Expand All @@ -35,7 +39,7 @@ AnalysisKey IVUsersAnalysis::Key;

IVUsers IVUsersAnalysis::run(Loop &L, LoopAnalysisManager &AM,
LoopStandardAnalysisResults &AR) {
return IVUsers(&L, &AR.AC, &AR.LI, &AR.DT, &AR.SE);
return IVUsers(&L, &AR.AC, &AR.LI, &AR.DT, &AR.SE, &AR.TTI);
}

char IVUsersWrapperPass::ID = 0;
Expand Down Expand Up @@ -133,7 +137,7 @@ static bool IVUseShouldUsePostIncValue(Instruction *User, Value *Operand,
/// Inspect the specified instruction. If it is a reducible SCEV, recursively
/// add its users to the IVUsesByStride set and return true. Otherwise, return
/// false.
bool IVUsers::AddUsersIfInteresting(Instruction *I) {
bool IVUsers::AddUsersIfInteresting(Instruction *I, bool BypassWidthCheck) {
const DataLayout &DL = I->getDataLayout();

// Add this IV user to the Processed set before returning false to ensure that
Expand All @@ -153,9 +157,16 @@ bool IVUsers::AddUsersIfInteresting(Instruction *I) {
// LSR is not APInt clean, do not touch integers bigger than 64-bits.
// Also avoid creating IVs of non-native types. For example, we don't want a
// 64-bit IV in 32-bit code just because the loop has one 64-bit cast.
Comment thread
F-Stuckmann marked this conversation as resolved.
uint64_t Width = SE->getTypeSizeInBits(I->getType());
if (Width > 64 || !DL.isLegalInteger(Width))
return false;
// Use TTI hook if available to allow targets where pointer and integer bit
// sizes differ (e.g., 20-bit pointers with 32-bit integers) to enable IV
// user collection for index-sized types.
if (!BypassWidthCheck) {
const uint64_t Width = SE->getTypeSizeInBits(I->getType());
const bool IsValidType = TTI ? TTI->isValidIVUserType(I->getType())
: (Width <= 64 && DL.isLegalInteger(Width));
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need the BypassWidthCheck parameter? We override it with a TTI callback.

if (!IsValidType)
return false;
}

// Don't attempt to promote ephemeral values to indvars. They will be removed
// later anyway.
Expand All @@ -170,6 +181,18 @@ bool IVUsers::AddUsersIfInteresting(Instruction *I) {
if (!isInteresting(ISE, I, L, SE, LI))
return false;

// Allow targets to look through certain instructions (e.g., truncs to index
// size on targets where pointer and integer bit sizes differ) to collect
// their users instead. This enables LSR to create pointer PHIs.
SmallVector<GetElementPtrInst *, 4> GEPsToProcess;
if (TTI && TTI->shouldIVUsersLookThroughInst(I, GEPsToProcess)) {
LLVM_DEBUG(dbgs() << "Looking through instruction: " << *I << '\n');
bool AnyInteresting = false;
for (GetElementPtrInst *GEP : GEPsToProcess)
AnyInteresting |= AddUsersIfInteresting(GEP, /*BypassWidthCheck=*/true);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we don't skip it, it will be our TTI call back doing the check. Doesn't that give sufficient tuning freedom?

return AnyInteresting;
Comment thread
F-Stuckmann marked this conversation as resolved.
}

SmallPtrSet<Instruction *, 4> UniqueUsers;
for (Use &U : I->uses()) {
Instruction *User = cast<Instruction>(U.getUser());
Expand Down Expand Up @@ -249,8 +272,8 @@ IVStrideUse &IVUsers::AddUser(Instruction *User, Value *Operand) {
}

IVUsers::IVUsers(Loop *L, AssumptionCache *AC, LoopInfo *LI, DominatorTree *DT,
ScalarEvolution *SE)
: L(L), AC(AC), LI(LI), DT(DT), SE(SE) {
ScalarEvolution *SE, const TargetTransformInfo *TTI)
: L(L), AC(AC), LI(LI), DT(DT), SE(SE), TTI(TTI) {
// Collect ephemeral values so that AddUsersIfInteresting skips them.
EphValues.clear();
CodeMetrics::collectEphemeralValues(L, AC, EphValues);
Expand Down Expand Up @@ -306,6 +329,7 @@ void IVUsersWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequired<LoopInfoWrapperPass>();
AU.addRequired<DominatorTreeWrapperPass>();
AU.addRequired<ScalarEvolutionWrapperPass>();
AU.addRequired<TargetTransformInfoWrapperPass>();
AU.setPreservesAll();
}

Expand All @@ -315,8 +339,10 @@ bool IVUsersWrapperPass::runOnLoop(Loop *L, LPPassManager &LPM) {
auto *LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
auto *DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
auto *SE = &getAnalysis<ScalarEvolutionWrapperPass>().getSE();
auto *TTI = &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(
*L->getHeader()->getParent());

IU.reset(new IVUsers(L, AC, LI, DT, SE));
IU.reset(new IVUsers(L, AC, LI, DT, SE, TTI));
return false;
}

Expand Down
11 changes: 10 additions & 1 deletion llvm/lib/Analysis/TargetTransformInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// Modifications (c) Copyright 2023-2024 Advanced Micro Devices, Inc. or its
// Modifications (c) Copyright 2023-2026 Advanced Micro Devices, Inc. or its
// affiliates
//
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -474,6 +474,15 @@ TargetTransformInfo::getPreferredAddressingMode(const Loop *L,
return TTIImpl->getPreferredAddressingMode(L, SE);
}

bool TargetTransformInfo::shouldIVUsersLookThroughInst(
Instruction *I, SmallVectorImpl<GetElementPtrInst *> &GEPsToProcess) const {
return TTIImpl->shouldIVUsersLookThroughInst(I, GEPsToProcess);
}

bool TargetTransformInfo::isValidIVUserType(Type *Ty) const {
return TTIImpl->isValidIVUserType(Ty);
}

bool TargetTransformInfo::isLegalMaskedStore(Type *DataType,
Align Alignment) const {
return TTIImpl->isLegalMaskedStore(DataType, Alignment);
Expand Down
Loading