Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
7 changes: 5 additions & 2 deletions llvm/include/llvm/Analysis/DXILResource.h
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,9 @@ class ResourceInfo {
return std::tie(RecordID, Space, LowerBound, Size) <
std::tie(RHS.RecordID, RHS.Space, RHS.LowerBound, RHS.Size);
}
bool overlapsWith(const ResourceBinding &RHS) const {
return Space == RHS.Space && LowerBound + Size - 1 >= RHS.LowerBound;
}
};

private:
Expand Down Expand Up @@ -394,8 +397,8 @@ class ResourceInfo {
getAnnotateProps(Module &M, dxil::ResourceTypeInfo &RTI) const;

bool operator==(const ResourceInfo &RHS) const {
return std::tie(Binding, HandleTy, Symbol) ==
std::tie(RHS.Binding, RHS.HandleTy, RHS.Symbol);
return std::tie(Binding, HandleTy, Symbol, Name) ==
std::tie(RHS.Binding, RHS.HandleTy, RHS.Symbol, RHS.Name);
}
bool operator!=(const ResourceInfo &RHS) const { return !(*this == RHS); }
bool operator<(const ResourceInfo &RHS) const {
Expand Down
59 changes: 51 additions & 8 deletions llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "DXILPostOptimizationValidation.h"
#include "DXILShaderFlags.h"
#include "DirectX.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Analysis/DXILMetadataAnalysis.h"
#include "llvm/Analysis/DXILResource.h"
#include "llvm/IR/DiagnosticInfo.h"
Expand Down Expand Up @@ -50,15 +51,55 @@ static void reportInvalidDirection(Module &M, DXILResourceMap &DRM) {
}
}

} // namespace
static void reportOverlappingError(Module &M, ResourceInfo R1,
ResourceInfo R2) {
SmallString<64> Message;
raw_svector_ostream OS(Message);
OS << "resource " << R1.getName() << " at register "
<< R1.getBinding().LowerBound << " overlaps with resource " << R2.getName()
<< " at register " << R2.getBinding().LowerBound << ", space "
<< R2.getBinding().Space;
M.getContext().diagnose(DiagnosticInfoGeneric(Message));
}

PreservedAnalyses
DXILPostOptimizationValidation::run(Module &M, ModuleAnalysisManager &MAM) {
DXILResourceMap &DRM = MAM.getResult<DXILResourceAnalysis>(M);
static void reportOverlappingBinding(Module &M, DXILResourceMap &DRM) {
if (DRM.empty())
return;

for (auto ResList :
{DRM.srvs(), DRM.uavs(), DRM.cbuffers(), DRM.samplers()}) {
if (ResList.empty())
continue;
const ResourceInfo *PrevRI = &*ResList.begin();
for (auto *I = ResList.begin() + 1; I != ResList.end(); ++I) {
const ResourceInfo *RI = &*I;
if (PrevRI->getBinding().overlapsWith(RI->getBinding())) {
reportOverlappingError(M, *PrevRI, *RI);
continue;
}
PrevRI = RI;
}
}
}

static void reportErrors(Module &M, DXILResourceMap &DRM,
DXILResourceBindingInfo &DRBI) {
if (DRM.hasInvalidCounterDirection())
reportInvalidDirection(M, DRM);

if (DRBI.hasOverlappingBinding())
reportOverlappingBinding(M, DRM);

assert(!DRBI.hasImplicitBinding() && "implicit bindings should be handled in "
"DXILResourceImplicitBinding pass");
}
} // namespace

PreservedAnalyses
DXILPostOptimizationValidation::run(Module &M, ModuleAnalysisManager &MAM) {
DXILResourceMap &DRM = MAM.getResult<DXILResourceAnalysis>(M);
DXILResourceBindingInfo &DRBI = MAM.getResult<DXILResourceBindingAnalysis>(M);
reportErrors(M, DRM, DRBI);
return PreservedAnalyses::all();
}

Expand All @@ -68,10 +109,9 @@ class DXILPostOptimizationValidationLegacy : public ModulePass {
bool runOnModule(Module &M) override {
DXILResourceMap &DRM =
getAnalysis<DXILResourceWrapperPass>().getResourceMap();

if (DRM.hasInvalidCounterDirection())
reportInvalidDirection(M, DRM);

DXILResourceBindingInfo &DRBI =
getAnalysis<DXILResourceBindingWrapperPass>().getBindingInfo();
reportErrors(M, DRM, DRBI);
return false;
}
StringRef getPassName() const override {
Expand All @@ -82,7 +122,9 @@ class DXILPostOptimizationValidationLegacy : public ModulePass {
static char ID; // Pass identification.
void getAnalysisUsage(llvm::AnalysisUsage &AU) const override {
AU.addRequired<DXILResourceWrapperPass>();
AU.addRequired<DXILResourceBindingWrapperPass>();
AU.addPreserved<DXILResourceWrapperPass>();
AU.addPreserved<DXILResourceBindingWrapperPass>();
AU.addPreserved<DXILMetadataAnalysisWrapperPass>();
AU.addPreserved<ShaderFlagsAnalysisWrapper>();
}
Expand All @@ -92,6 +134,7 @@ char DXILPostOptimizationValidationLegacy::ID = 0;

INITIALIZE_PASS_BEGIN(DXILPostOptimizationValidationLegacy, DEBUG_TYPE,
"DXIL Post Optimization Validation", false, false)
INITIALIZE_PASS_DEPENDENCY(DXILResourceBindingWrapperPass)
INITIALIZE_PASS_DEPENDENCY(DXILResourceTypeWrapperPass)
INITIALIZE_PASS_DEPENDENCY(DXILResourceWrapperPass)
INITIALIZE_PASS_END(DXILPostOptimizationValidationLegacy, DEBUG_TYPE,
Expand Down
17 changes: 17 additions & 0 deletions llvm/test/CodeGen/DirectX/Binding/binding-overlap-1.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
; RUN: not opt -S -passes='dxil-post-optimization-validation' -mtriple=dxil-pc-shadermodel6.3-library %s 2>&1 | FileCheck %s

; Check overlap error for two resource arrays.

; CHECK: error: resource A at register 0 overlaps with resource B at register 5, space 0

@A.str = private unnamed_addr constant [2 x i8] c"A\00", align 1
@B.str = private unnamed_addr constant [2 x i8] c"B\00", align 1

define void @test_overlapping() {
entry:
; RWBuffer<float> A[10] : register(u0);
; RWBuffer<float> B[10] : register(u5);
%h1 = call target("dx.TypedBuffer", float, 1, 0, 0) @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 10, i32 4, i1 false, ptr @A.str)
%h2 = call target("dx.TypedBuffer", float, 1, 0, 0) @llvm.dx.resource.handlefrombinding(i32 0, i32 5, i32 10, i32 4, i1 false, ptr @B.str)
ret void
}
17 changes: 17 additions & 0 deletions llvm/test/CodeGen/DirectX/Binding/binding-overlap-2.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
; RUN: not opt -S -passes='dxil-post-optimization-validation' -mtriple=dxil-pc-shadermodel6.3-library %s 2>&1 | FileCheck %s

; Check overlap error for two resources with identical binding

; CHECK: error: resource R at register 5 overlaps with resource S at register 5, space 10

@R.str = private unnamed_addr constant [2 x i8] c"R\00", align 1
@S.str = private unnamed_addr constant [2 x i8] c"S\00", align 1

define void @test_overlapping() {
entry:
; RWBuffer<float> R : register(u5, space10);
; RWBuffer<float> S : register(u5, space10);
%h1 = call target("dx.TypedBuffer", float, 1, 0, 0) @llvm.dx.resource.handlefrombinding(i32 10, i32 5, i32 1, i32 0, i1 false, ptr @R.str)
%h2 = call target("dx.TypedBuffer", float, 1, 0, 0) @llvm.dx.resource.handlefrombinding(i32 10, i32 5, i32 1, i32 0, i1 false, ptr @S.str)
ret void
}
44 changes: 44 additions & 0 deletions llvm/test/CodeGen/DirectX/Binding/binding-overlap-3.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
; Use llc for this test so that we don't abort after the first error.
; RUN: not llc %s -o /dev/null 2>&1 | FileCheck %s

; Check multiple overlap errors.
; Also check different resource class with same binding values is ok (no error expected).

target triple = "dxil-pc-shadermodel6.3-library"

; CHECK: error: resource C at register 0 overlaps with resource A at register 5, space 0
; CHECK: error: resource C at register 0 overlaps with resource B at register 9, space 0

@A.str = private unnamed_addr constant [2 x i8] c"A\00", align 1
@B.str = private unnamed_addr constant [2 x i8] c"B\00", align 1
@C.str = private unnamed_addr constant [2 x i8] c"C\00", align 1
@S.str = private unnamed_addr constant [2 x i8] c"S\00", align 1

; Fake globals to store handles in; this is to make sure the handlefrombinding calls
; are not optimized away by llc.
@One = internal global { target("dx.RawBuffer", float, 0, 0) } poison, align 4
@Two = internal global { target("dx.RawBuffer", float, 0, 0) } poison, align 4
@Three = internal global { target("dx.RawBuffer", float, 0, 0) } poison, align 4
@Four = internal global { target("dx.TypedBuffer", float, 1, 0, 0) } poison, align 4

define void @test_overlapping() "hlsl.export" {
entry:
; StructuredBuffer<float> A : register(t5);
; StructuredBuffer<float> B : register(t9);
; StructuredBuffer<float> C[10] : register(t0);
; RWBuffer<float> S[10] : register(u0);

%h1 = call target("dx.RawBuffer", float, 0, 0) @llvm.dx.resource.handlefrombinding(i32 0, i32 5, i32 1, i32 0, i1 false, ptr @A.str)
store target("dx.RawBuffer", float, 0, 0) %h1, ptr @One, align 4

%h2 = call target("dx.RawBuffer", float, 0, 0) @llvm.dx.resource.handlefrombinding(i32 0, i32 9, i32 1, i32 0, i1 false, ptr @B.str)
store target("dx.RawBuffer", float, 0, 0) %h2, ptr @Two, align 4

%h3 = call target("dx.RawBuffer", float, 0, 0) @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 10, i32 4, i1 false, ptr @C.str)
store target("dx.RawBuffer", float, 0, 0) %h3, ptr @Three, align 4

%h4 = call target("dx.TypedBuffer", float, 1, 0, 0) @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 false, ptr @S.str)
store target("dx.TypedBuffer", float, 1, 0, 0) %h4, ptr @Four, align 4

ret void
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ define <4 x float> @multicomponent() #0 {
; CHECK: Function onecomponent : 0x00000000
define float @onecomponent() #0 {
%res = call target("dx.TypedBuffer", float, 1, 0, 0)
@llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 false, ptr null)
@llvm.dx.resource.handlefrombinding(i32 0, i32 1, i32 1, i32 0, i1 false, ptr null)
%load = call {float, i1} @llvm.dx.resource.load.typedbuffer(
target("dx.TypedBuffer", float, 1, 0, 0) %res, i32 0)
%val = extractvalue {float, i1} %load, 0
Expand All @@ -36,7 +36,7 @@ define float @onecomponent() #0 {
; CHECK: Function noload : 0x00000000
define void @noload(<4 x float> %val) #0 {
%res = call target("dx.TypedBuffer", <4 x float>, 1, 0, 0)
@llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 false, ptr null)
@llvm.dx.resource.handlefrombinding(i32 0, i32 2, i32 1, i32 0, i1 false, ptr null)
call void @llvm.dx.resource.store.typedbuffer(
target("dx.TypedBuffer", <4 x float>, 1, 0, 0) %res, i32 0,
<4 x float> %val)
Expand Down
Loading