| //===- llvm/unittests/Target/DirectX/PointerTypeAnalysisTests.cpp ---------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "DirectXTargetMachine.h" |
| #include "llvm/Analysis/DXILResource.h" |
| #include "llvm/AsmParser/Parser.h" |
| #include "llvm/CodeGen/CommandFlags.h" |
| #include "llvm/IR/Instructions.h" |
| #include "llvm/IR/IntrinsicsDirectX.h" |
| #include "llvm/IR/LLVMContext.h" |
| #include "llvm/IR/Module.h" |
| #include "llvm/IR/Type.h" |
| #include "llvm/Passes/PassBuilder.h" |
| #include "llvm/Support/Casting.h" |
| #include "llvm/Support/SourceMgr.h" |
| |
| #include "gtest/gtest.h" |
| |
| using namespace llvm; |
| using namespace llvm::dxil; |
| |
| namespace { |
| class UniqueResourceFromUseTest : public testing::Test { |
| protected: |
| PassBuilder *PB; |
| ModuleAnalysisManager *MAM; |
| LLVMContext *Context; |
| virtual void SetUp() { |
| Context = new LLVMContext(); |
| MAM = new ModuleAnalysisManager(); |
| PB = new PassBuilder(); |
| PB->registerModuleAnalyses(*MAM); |
| MAM->registerPass([&] { return DXILResourceTypeAnalysis(); }); |
| MAM->registerPass([&] { return DXILResourceAnalysis(); }); |
| } |
| |
| std::unique_ptr<Module> parseAsm(StringRef Asm) { |
| SMDiagnostic Error; |
| std::unique_ptr<Module> M = parseAssemblyString(Asm, Error, *Context); |
| EXPECT_TRUE(M) << "Bad assembly?: " << Error.getMessage(); |
| return M; |
| } |
| |
| virtual void TearDown() { |
| delete PB; |
| delete MAM; |
| delete Context; |
| } |
| }; |
| |
| // Test that several calls to decrement on the same resource don't raise a |
| // Diagnositic and resolves to a single decrement entry |
| TEST_F(UniqueResourceFromUseTest, TestResourceCounterDecrement) { |
| StringRef Assembly = R"( |
| define void @main() { |
| entry: |
| %handle = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding(i32 1, i32 2, i32 3, i32 4, i1 false) |
| call i32 @llvm.dx.resource.updatecounter(target("dx.RawBuffer", float, 1, 0) %handle, i8 -1) |
| call i32 @llvm.dx.resource.updatecounter(target("dx.RawBuffer", float, 1, 0) %handle, i8 -1) |
| call i32 @llvm.dx.resource.updatecounter(target("dx.RawBuffer", float, 1, 0) %handle, i8 -1) |
| ret void |
| } |
| )"; |
| |
| auto M = parseAsm(Assembly); |
| |
| DXILResourceMap &DRM = MAM->getResult<DXILResourceAnalysis>(*M); |
| |
| for (const Function &F : M->functions()) { |
| if (F.getIntrinsicID() != Intrinsic::dx_resource_handlefrombinding) |
| continue; |
| |
| for (const User *U : F.users()) { |
| const CallInst *CI = cast<CallInst>(U); |
| const auto *const Binding = DRM.find(CI); |
| ASSERT_EQ(Binding->CounterDirection, ResourceCounterDirection::Decrement); |
| } |
| } |
| } |
| |
| // Test that several calls to increment on the same resource don't raise a |
| // Diagnositic and resolves to a single increment entry |
| TEST_F(UniqueResourceFromUseTest, TestResourceCounterIncrement) { |
| StringRef Assembly = R"( |
| define void @main() { |
| entry: |
| %handle = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding(i32 1, i32 2, i32 3, i32 4, i1 false) |
| call i32 @llvm.dx.resource.updatecounter(target("dx.RawBuffer", float, 1, 0) %handle, i8 1) |
| call i32 @llvm.dx.resource.updatecounter(target("dx.RawBuffer", float, 1, 0) %handle, i8 1) |
| call i32 @llvm.dx.resource.updatecounter(target("dx.RawBuffer", float, 1, 0) %handle, i8 1) |
| ret void |
| } |
| )"; |
| |
| auto M = parseAsm(Assembly); |
| |
| DXILResourceMap &DRM = MAM->getResult<DXILResourceAnalysis>(*M); |
| |
| for (const Function &F : M->functions()) { |
| if (F.getIntrinsicID() != Intrinsic::dx_resource_handlefrombinding) |
| continue; |
| |
| for (const User *U : F.users()) { |
| const CallInst *CI = cast<CallInst>(U); |
| const auto *const Binding = DRM.find(CI); |
| ASSERT_EQ(Binding->CounterDirection, ResourceCounterDirection::Increment); |
| } |
| } |
| } |
| |
| // Test that looking up a resource that doesn't have the counter updated |
| // resoves to unknown |
| TEST_F(UniqueResourceFromUseTest, TestResourceCounterUnknown) { |
| StringRef Assembly = R"( |
| define void @main() { |
| entry: |
| %handle = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding(i32 1, i32 2, i32 3, i32 4, i1 false) |
| ret void |
| } |
| )"; |
| |
| auto M = parseAsm(Assembly); |
| |
| DXILResourceMap &DRM = MAM->getResult<DXILResourceAnalysis>(*M); |
| |
| for (const Function &F : M->functions()) { |
| if (F.getIntrinsicID() != Intrinsic::dx_resource_handlefrombinding) |
| continue; |
| |
| for (const User *U : F.users()) { |
| const CallInst *CI = cast<CallInst>(U); |
| const auto *const Binding = DRM.find(CI); |
| ASSERT_EQ(Binding->CounterDirection, ResourceCounterDirection::Unknown); |
| } |
| } |
| } |
| |
| // Test that multiple different resources with unique incs/decs aren't |
| // marked invalid |
| TEST_F(UniqueResourceFromUseTest, TestResourceCounterMultiple) { |
| StringRef Assembly = R"( |
| define void @main() { |
| entry: |
| %handle1 = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding(i32 1, i32 2, i32 3, i32 4, i1 false) |
| %handle2 = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding(i32 4, i32 3, i32 2, i32 1, i1 false) |
| call i32 @llvm.dx.resource.updatecounter(target("dx.RawBuffer", float, 1, 0) %handle1, i8 -1) |
| call i32 @llvm.dx.resource.updatecounter(target("dx.RawBuffer", float, 1, 0) %handle2, i8 1) |
| ret void |
| } |
| )"; |
| |
| auto M = parseAsm(Assembly); |
| |
| DXILResourceMap &DRM = MAM->getResult<DXILResourceAnalysis>(*M); |
| |
| ResourceCounterDirection Dirs[2] = {ResourceCounterDirection::Decrement, |
| ResourceCounterDirection::Increment}; |
| ResourceCounterDirection *Dir = Dirs; |
| |
| for (const Function &F : M->functions()) { |
| if (F.getIntrinsicID() != Intrinsic::dx_resource_handlefrombinding) |
| continue; |
| |
| uint32_t ExpectedDirsIndex = 0; |
| for (const User *U : F.users()) { |
| const CallInst *CI = cast<CallInst>(U); |
| const auto *const Binding = DRM.find(CI); |
| ASSERT_TRUE(ExpectedDirsIndex < 2); |
| ASSERT_EQ(Binding->CounterDirection, Dir[ExpectedDirsIndex]); |
| ExpectedDirsIndex++; |
| } |
| } |
| } |
| |
| // Test that single different resources with unique incs/decs is marked invalid |
| TEST_F(UniqueResourceFromUseTest, TestResourceCounterInvalid) { |
| StringRef Assembly = R"( |
| define void @main() { |
| entry: |
| %handle = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding(i32 1, i32 2, i32 3, i32 4, i1 false) |
| call i32 @llvm.dx.resource.updatecounter(target("dx.RawBuffer", float, 1, 0) %handle, i8 -1) |
| call i32 @llvm.dx.resource.updatecounter(target("dx.RawBuffer", float, 1, 0) %handle, i8 1) |
| ret void |
| } |
| )"; |
| |
| auto M = parseAsm(Assembly); |
| |
| DXILResourceMap &DRM = MAM->getResult<DXILResourceAnalysis>(*M); |
| |
| for (const Function &F : M->functions()) { |
| if (F.getIntrinsicID() != Intrinsic::dx_resource_handlefrombinding) |
| continue; |
| |
| for (const User *U : F.users()) { |
| const CallInst *CI = cast<CallInst>(U); |
| const auto *const Binding = DRM.find(CI); |
| ASSERT_EQ(Binding->CounterDirection, ResourceCounterDirection::Invalid); |
| } |
| } |
| } |
| |
| } // namespace |