Skip to content

Commit cdbe8d7

Browse files
krystian-andrzejewskiigcbot
authored andcommitted
Preserve bounds for laundered root indices
Extract range information from laundered integer operands before lowering root signature accesses. This keeps dynamic array bounds available when the launder carries range metadata.
1 parent ab734c7 commit cdbe8d7

3 files changed

Lines changed: 96 additions & 2 deletions

File tree

IGC/Compiler/CISACodeGen/helper.cpp

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ SPDX-License-Identifier: MIT
1414
#include "common/LLVMWarningsPush.hpp"
1515
#include "llvm/Config/llvm-config.h"
1616
#include "llvm/IR/GetElementPtrTypeIterator.h"
17+
#include <llvm/IR/ConstantRange.h>
1718
#include <llvm/IR/InstIterator.h>
1819
#include <llvm/IR/Intrinsics.h>
1920
#include <llvm/Support/KnownBits.h>
@@ -2993,4 +2994,71 @@ bool AllowRemovingUnusedImplicitLocalIDs(const CodeGenContext *ctx) {
29932994
return ctx->platform.isCoreChildOf(IGFX_XE2_HPG_CORE);
29942995
}
29952996

2997+
ExtractBoundsResult ExtractBounds(llvm::Use &U, llvm::AssumptionCache &AC, llvm::Instruction *CtxI,
2998+
bool peelLaunder /*= true*/) {
2999+
IGC_ASSERT_MESSAGE(U.get() && U.get()->getType()->isIntegerTy(), "Expecting an integer operand");
3000+
3001+
ExtractBoundsResult Result;
3002+
llvm::Value *V = U.get();
3003+
std::optional<llvm::ConstantRange> CRFromErasedLaunder;
3004+
Result.SourceValue = V;
3005+
3006+
if (peelLaunder) {
3007+
auto *MaybeLaunder = llvm::dyn_cast<GenIntrinsicInst>(V);
3008+
const bool IsLaunder = MaybeLaunder && MaybeLaunder->isGenIntrinsic(GenISAIntrinsic::GenISA_launder);
3009+
if (IsLaunder) {
3010+
llvm::Value *Operand = MaybeLaunder->getOperand(0);
3011+
Result.SourceValue = Operand;
3012+
auto *OperandTy = llvm::dyn_cast<llvm::IntegerType>(Operand->getType());
3013+
if (!OperandTy || OperandTy->getBitWidth() > 64)
3014+
return Result;
3015+
3016+
if (auto *Constant = llvm::dyn_cast<llvm::ConstantInt>(Operand)) {
3017+
MaybeLaunder->replaceAllUsesWith(Operand);
3018+
MaybeLaunder->eraseFromParent();
3019+
const uint64_t Lo = Constant->getZExtValue();
3020+
Result.Bounds = std::make_pair(Lo, Lo + 1);
3021+
return Result;
3022+
}
3023+
3024+
U.set(Operand);
3025+
3026+
if (MaybeLaunder->user_empty()) {
3027+
CRFromErasedLaunder = llvm::computeConstantRange(MaybeLaunder, /*ForSigned=*/false,
3028+
/*UseInstrInfo=*/true, &AC, CtxI,
3029+
/*DT=*/nullptr, /*Depth=*/0);
3030+
MaybeLaunder->eraseFromParent();
3031+
V = nullptr;
3032+
}
3033+
}
3034+
}
3035+
3036+
auto *Ty = llvm::dyn_cast<llvm::IntegerType>(Result.SourceValue->getType());
3037+
if (!Ty || Ty->getBitWidth() > 64 || !CtxI)
3038+
return Result;
3039+
3040+
const llvm::DataLayout &DL = CtxI->getModule()->getDataLayout();
3041+
3042+
llvm::ConstantRange CRFromOperand = llvm::computeConstantRange(
3043+
Result.SourceValue, /*ForSigned=*/false, /*UseInstrInfo=*/true, &AC, CtxI, /*DT=*/nullptr, /*Depth=*/0);
3044+
llvm::KnownBits KB = IGCLLVM::computeKnownBits(Result.SourceValue, DL, &AC, CtxI);
3045+
llvm::ConstantRange Combined = CRFromOperand.intersectWith(llvm::ConstantRange::fromKnownBits(KB, false));
3046+
3047+
if (CRFromErasedLaunder.has_value()) {
3048+
Combined = Combined.intersectWith(*CRFromErasedLaunder);
3049+
} else if (V && V != Result.SourceValue) {
3050+
llvm::ConstantRange CRFromV = llvm::computeConstantRange(V, /*ForSigned=*/false, /*UseInstrInfo=*/true, &AC, CtxI,
3051+
/*DT=*/nullptr, /*Depth=*/0);
3052+
Combined = Combined.intersectWith(CRFromV);
3053+
}
3054+
3055+
if (!Combined.isFullSet()) {
3056+
const uint64_t Lo = Combined.getUnsignedMin().getZExtValue();
3057+
const uint64_t Hi = Combined.getUnsignedMax().getZExtValue() + 1;
3058+
Result.Bounds = std::make_pair(Lo, Hi);
3059+
}
3060+
3061+
return Result;
3062+
}
3063+
29963064
} // namespace IGC

IGC/Compiler/CISACodeGen/helper.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ SPDX-License-Identifier: MIT
4242
#include "LLVM3DBuilder/MetadataBuilder.h"
4343
#include "Probe/Assertion.h"
4444
#include <functional>
45+
#include <optional>
46+
#include <utility>
4547
#include "common/ResourceAddrSpace.h"
4648

4749
typedef unsigned int uint;
@@ -590,4 +592,20 @@ bool UsedWithoutImmInMemInst(llvm::Value *v);
590592
bool AllowShortImplicitPayloadHeader(const CodeGenContext *ctx);
591593
bool AllowRemovingUnusedImplicitArguments(const CodeGenContext *ctx);
592594
bool AllowRemovingUnusedImplicitLocalIDs(const CodeGenContext *ctx);
595+
596+
struct ExtractBoundsResult {
597+
llvm::Value *SourceValue = nullptr;
598+
std::optional<std::pair<uint64_t, uint64_t>> Bounds; // [Lo, Hi), or nullopt if no useful constraint.
599+
};
600+
601+
/// Given a Use U that may reference a GenISA_launder:
602+
/// 1. Replaces U in-place with the launder's operand.
603+
/// 2. If the launder has no remaining users, erases it.
604+
/// 3. Returns the tightest [Lo, Hi) by intersecting:
605+
/// a) computeConstantRange(operand, depth=0), including assumes on the operand,
606+
/// b) ConstantRange::fromKnownBits(computeKnownBits(operand)),
607+
/// c) computeConstantRange(launder, depth=0), including assumes/range on the launder.
608+
/// If U does not reference a launder, only (a) and (b) are applied.
609+
ExtractBoundsResult ExtractBounds(llvm::Use &U, llvm::AssumptionCache &AC, llvm::Instruction *CtxI,
610+
bool peelLaunder = true);
593611
} // namespace IGC

IGC/GenISAIntrinsics/GenIntrinsicInst.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1976,8 +1976,16 @@ class LocalRootSignatureValueIntrinsic : public GenIntrinsicInst {
19761976

19771977
static inline bool classof(const Value *V) { return isa<GenIntrinsicInst>(V) && classof(cast<GenIntrinsicInst>(V)); }
19781978

1979-
Value *getByteOffset() const { return getOperand(0); }
1980-
uint32_t getRootSigSize() const { return int_cast<uint32_t>(getImm64Operand(1)); }
1979+
enum class Argument { Offset, Size, Count };
1980+
static constexpr unsigned int GetArgumentIndex(Argument arg) { return static_cast<unsigned int>(arg); }
1981+
inline llvm::Value *GetArgument(Argument arg) const { return getOperand(GetArgumentIndex(arg)); }
1982+
inline llvm::Use &GetArgumentUse(Argument arg) { return getOperandUse(GetArgumentIndex(arg)); }
1983+
inline const llvm::Use &GetArgumentUse(Argument arg) const { return getOperandUse(GetArgumentIndex(arg)); }
1984+
1985+
Value *getByteOffset() const { return GetArgument(Argument::Offset); }
1986+
llvm::Use &getByteOffsetUse() { return GetArgumentUse(Argument::Offset); }
1987+
const llvm::Use &getByteOffsetUse() const { return GetArgumentUse(Argument::Offset); }
1988+
uint32_t getRootSigSize() const { return int_cast<uint32_t>(getImm64Operand(GetArgumentIndex(Argument::Size))); }
19811989
};
19821990

19831991
class StaticConstantPatchIntrinsic : public GenIntrinsicInst {

0 commit comments

Comments
 (0)