//=== ParseHLSLRootSignatureTest.cpp - Parse Root Signature tests ---------===// // // 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 "clang/AST/ASTContext.h" #include "clang/AST/Expr.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/HeaderSearchOptions.h" #include "clang/Lex/Lexer.h" #include "clang/Lex/ModuleLoader.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/PreprocessorOptions.h" #include "clang/Lex/LexHLSLRootSignature.h" #include "clang/Parse/ParseHLSLRootSignature.h" #include "gtest/gtest.h" using namespace clang; using namespace clang::hlsl; using namespace llvm::hlsl::rootsig; namespace { using llvm::dxbc::RootSignatureVersion; // Diagnostic helper for helper tests class ExpectedDiagConsumer : public DiagnosticConsumer { virtual void anchor() {} void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) override { if (!FirstDiag || !ExpectedDiagID.has_value()) { Satisfied = false; return; } FirstDiag = false; Satisfied = ExpectedDiagID.value() == Info.getID(); } bool FirstDiag = true; bool Satisfied = false; std::optional ExpectedDiagID; public: void setNoDiag() { Satisfied = true; ExpectedDiagID = std::nullopt; } void setExpected(unsigned DiagID) { Satisfied = false; ExpectedDiagID = DiagID; } bool isSatisfied() { return Satisfied; } }; // The test fixture. class ParseHLSLRootSignatureTest : public ::testing::Test { protected: ParseHLSLRootSignatureTest() : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()), Consumer(new ExpectedDiagConsumer()), Diags(DiagID, DiagOpts, Consumer), SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions) { // This is an arbitrarily chosen target triple to create the target info. TargetOpts->Triple = "dxil"; Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts); } std::unique_ptr createPP(StringRef Source, TrivialModuleLoader &ModLoader) { std::unique_ptr Buf = llvm::MemoryBuffer::getMemBuffer(Source); SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf))); HeaderSearchOptions SearchOpts; HeaderSearch HeaderInfo(SearchOpts, SourceMgr, Diags, LangOpts, Target.get()); auto PP = std::make_unique( PPOpts, Diags, LangOpts, SourceMgr, HeaderInfo, ModLoader, /*IILookup =*/nullptr, /*OwnsHeaderSearch =*/false); PP->Initialize(*Target); PP->EnterMainSourceFile(); return PP; } std::unique_ptr createMinimalASTContext() { IdentifierTable Idents(LangOpts); SelectorTable Selectors; Builtin::Context Builtins; return std::make_unique(LangOpts, SourceMgr, Idents, Selectors, Builtins, TU_Complete); } StringLiteral *wrapSource(std::unique_ptr &Ctx, StringRef Source) { SourceLocation Locs[1] = {SourceLocation()}; return StringLiteral::Create(*Ctx, Source, StringLiteralKind::Unevaluated, false, Ctx->VoidTy, Locs); } FileSystemOptions FileMgrOpts; FileManager FileMgr; IntrusiveRefCntPtr DiagID; DiagnosticOptions DiagOpts; ExpectedDiagConsumer *Consumer; DiagnosticsEngine Diags; SourceManager SourceMgr; LangOptions LangOpts; PreprocessorOptions PPOpts; std::shared_ptr TargetOpts; IntrusiveRefCntPtr Target; }; // Valid Parser Tests TEST_F(ParseHLSLRootSignatureTest, ValidParseEmptyTest) { const llvm::StringLiteral Source = R"cc()cc"; auto Ctx = createMinimalASTContext(); StringLiteral *Signature = wrapSource(Ctx, Source); TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test no diagnostics produced Consumer->setNoDiag(); ASSERT_FALSE(Parser.parse()); ASSERT_EQ((int)Parser.getElements().size(), 0); ASSERT_TRUE(Consumer->isSatisfied()); } TEST_F(ParseHLSLRootSignatureTest, ValidParseDTClausesTest) { using llvm::dxbc::DescriptorRangeFlags; const llvm::StringLiteral Source = R"cc( DescriptorTable( CBV(b0), SRV(space = 3, offset = 32, t42, flags = 0, numDescriptors = 4), visibility = SHADER_VISIBILITY_PIXEL, Sampler(s987, space = +2, offset = DESCRIPTOR_RANGE_OFFSET_APPEND), UAV(u4294967294, numDescriptors = unbounded, flags = Descriptors_Volatile | Data_Volatile | Data_Static_While_Set_At_Execute | Data_Static | Descriptors_Static_Keeping_Buffer_Bounds_Checks ) ), DescriptorTable() )cc"; auto Ctx = createMinimalASTContext(); StringLiteral *Signature = wrapSource(Ctx, Source); TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test no diagnostics produced Consumer->setNoDiag(); ASSERT_FALSE(Parser.parse()); auto Elements = Parser.getElements(); // First Descriptor Table with 4 elements RootElement Elem = Elements[0].getElement(); ASSERT_TRUE(std::holds_alternative(Elem)); ASSERT_EQ(std::get(Elem).Type, ClauseType::CBuffer); ASSERT_EQ(std::get(Elem).Reg.ViewType, RegisterType::BReg); ASSERT_EQ(std::get(Elem).Reg.Number, 0u); ASSERT_EQ(std::get(Elem).NumDescriptors, 1u); ASSERT_EQ(std::get(Elem).Space, 0u); ASSERT_EQ(std::get(Elem).Offset, DescriptorTableOffsetAppend); ASSERT_EQ(std::get(Elem).Flags, DescriptorRangeFlags::DataStaticWhileSetAtExecute); Elem = Elements[1].getElement(); ASSERT_TRUE(std::holds_alternative(Elem)); ASSERT_EQ(std::get(Elem).Type, ClauseType::SRV); ASSERT_EQ(std::get(Elem).Reg.ViewType, RegisterType::TReg); ASSERT_EQ(std::get(Elem).Reg.Number, 42u); ASSERT_EQ(std::get(Elem).NumDescriptors, 4u); ASSERT_EQ(std::get(Elem).Space, 3u); ASSERT_EQ(std::get(Elem).Offset, 32u); ASSERT_EQ(std::get(Elem).Flags, DescriptorRangeFlags::None); Elem = Elements[2].getElement(); ASSERT_TRUE(std::holds_alternative(Elem)); ASSERT_EQ(std::get(Elem).Type, ClauseType::Sampler); ASSERT_EQ(std::get(Elem).Reg.ViewType, RegisterType::SReg); ASSERT_EQ(std::get(Elem).Reg.Number, 987u); ASSERT_EQ(std::get(Elem).NumDescriptors, 1u); ASSERT_EQ(std::get(Elem).Space, 2u); ASSERT_EQ(std::get(Elem).Offset, DescriptorTableOffsetAppend); ASSERT_EQ(std::get(Elem).Flags, DescriptorRangeFlags::None); Elem = Elements[3].getElement(); ASSERT_TRUE(std::holds_alternative(Elem)); ASSERT_EQ(std::get(Elem).Type, ClauseType::UAV); ASSERT_EQ(std::get(Elem).Reg.ViewType, RegisterType::UReg); ASSERT_EQ(std::get(Elem).Reg.Number, 4294967294u); ASSERT_EQ(std::get(Elem).NumDescriptors, NumDescriptorsUnbounded); ASSERT_EQ(std::get(Elem).Space, 0u); ASSERT_EQ(std::get(Elem).Offset, DescriptorTableOffsetAppend); auto ValidDescriptorRangeFlags = DescriptorRangeFlags::DescriptorsVolatile | DescriptorRangeFlags::DataVolatile | DescriptorRangeFlags::DataStaticWhileSetAtExecute | DescriptorRangeFlags::DataStatic | DescriptorRangeFlags::DescriptorsStaticKeepingBufferBoundsChecks; ASSERT_EQ(std::get(Elem).Flags, ValidDescriptorRangeFlags); Elem = Elements[4].getElement(); ASSERT_TRUE(std::holds_alternative(Elem)); ASSERT_EQ(std::get(Elem).NumClauses, (uint32_t)4); ASSERT_EQ(std::get(Elem).Visibility, llvm::dxbc::ShaderVisibility::Pixel); // Empty Descriptor Table Elem = Elements[5].getElement(); ASSERT_TRUE(std::holds_alternative(Elem)); ASSERT_EQ(std::get(Elem).NumClauses, 0u); ASSERT_EQ(std::get(Elem).Visibility, llvm::dxbc::ShaderVisibility::All); ASSERT_TRUE(Consumer->isSatisfied()); } TEST_F(ParseHLSLRootSignatureTest, ValidParseStaticSamplerTest) { const llvm::StringLiteral Source = R"cc( StaticSampler(s0), StaticSampler(s0, maxAnisotropy = 3, space = 4, visibility = SHADER_VISIBILITY_DOMAIN, minLOD = 4.2f, mipLODBias = 0.23e+3, addressW = TEXTURE_ADDRESS_CLAMP, addressV = TEXTURE_ADDRESS_BORDER, filter = FILTER_MAXIMUM_MIN_POINT_MAG_LINEAR_MIP_POINT, maxLOD = 9000, addressU = TEXTURE_ADDRESS_MIRROR, comparisonFunc = COMPARISON_NOT_EQUAL, borderColor = STATIC_BORDER_COLOR_OPAQUE_BLACK_UINT ) )cc"; auto Ctx = createMinimalASTContext(); StringLiteral *Signature = wrapSource(Ctx, Source); TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test no diagnostics produced Consumer->setNoDiag(); ASSERT_FALSE(Parser.parse()); auto Elements = Parser.getElements(); ASSERT_EQ(Elements.size(), 2u); // Check default values are as expected RootElement Elem = Elements[0].getElement(); ASSERT_TRUE(std::holds_alternative(Elem)); ASSERT_EQ(std::get(Elem).Reg.ViewType, RegisterType::SReg); ASSERT_EQ(std::get(Elem).Reg.Number, 0u); ASSERT_EQ(std::get(Elem).Filter, llvm::dxbc::SamplerFilter::Anisotropic); ASSERT_EQ(std::get(Elem).AddressU, llvm::dxbc::TextureAddressMode::Wrap); ASSERT_EQ(std::get(Elem).AddressV, llvm::dxbc::TextureAddressMode::Wrap); ASSERT_EQ(std::get(Elem).AddressW, llvm::dxbc::TextureAddressMode::Wrap); ASSERT_FLOAT_EQ(std::get(Elem).MipLODBias, 0.f); ASSERT_EQ(std::get(Elem).MaxAnisotropy, 16u); ASSERT_EQ(std::get(Elem).CompFunc, llvm::dxbc::ComparisonFunc::LessEqual); ASSERT_EQ(std::get(Elem).BorderColor, llvm::dxbc::StaticBorderColor::OpaqueWhite); ASSERT_FLOAT_EQ(std::get(Elem).MinLOD, 0.f); ASSERT_FLOAT_EQ(std::get(Elem).MaxLOD, 3.402823466e+38f); ASSERT_EQ(std::get(Elem).Space, 0u); ASSERT_EQ(std::get(Elem).Visibility, llvm::dxbc::ShaderVisibility::All); // Check values can be set as expected Elem = Elements[1].getElement(); ASSERT_TRUE(std::holds_alternative(Elem)); ASSERT_EQ(std::get(Elem).Reg.ViewType, RegisterType::SReg); ASSERT_EQ(std::get(Elem).Reg.Number, 0u); ASSERT_EQ(std::get(Elem).Filter, llvm::dxbc::SamplerFilter::MaximumMinPointMagLinearMipPoint); ASSERT_EQ(std::get(Elem).AddressU, llvm::dxbc::TextureAddressMode::Mirror); ASSERT_EQ(std::get(Elem).AddressV, llvm::dxbc::TextureAddressMode::Border); ASSERT_EQ(std::get(Elem).AddressW, llvm::dxbc::TextureAddressMode::Clamp); ASSERT_FLOAT_EQ(std::get(Elem).MipLODBias, 230.f); ASSERT_EQ(std::get(Elem).MaxAnisotropy, 3u); ASSERT_EQ(std::get(Elem).CompFunc, llvm::dxbc::ComparisonFunc::NotEqual); ASSERT_EQ(std::get(Elem).BorderColor, llvm::dxbc::StaticBorderColor::OpaqueBlackUint); ASSERT_FLOAT_EQ(std::get(Elem).MinLOD, 4.2f); ASSERT_FLOAT_EQ(std::get(Elem).MaxLOD, 9000.f); ASSERT_EQ(std::get(Elem).Space, 4u); ASSERT_EQ(std::get(Elem).Visibility, llvm::dxbc::ShaderVisibility::Domain); ASSERT_TRUE(Consumer->isSatisfied()); } TEST_F(ParseHLSLRootSignatureTest, ValidParseFloatsTest) { const llvm::StringLiteral Source = R"cc( StaticSampler(s0, mipLODBias = 0), StaticSampler(s0, mipLODBias = +1), StaticSampler(s0, mipLODBias = -1), StaticSampler(s0, mipLODBias = 42.), StaticSampler(s0, mipLODBias = +4.2), StaticSampler(s0, mipLODBias = -.42), StaticSampler(s0, mipLODBias = .42e+3), StaticSampler(s0, mipLODBias = 42E-12), StaticSampler(s0, mipLODBias = 42.f), StaticSampler(s0, mipLODBias = 4.2F), StaticSampler(s0, mipLODBias = 42.e+10f), StaticSampler(s0, mipLODBias = -2147483648), StaticSampler(s0, mipLODBias = 2147483648), )cc"; auto Ctx = createMinimalASTContext(); StringLiteral *Signature = wrapSource(Ctx, Source); TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test no diagnostics produced Consumer->setNoDiag(); ASSERT_FALSE(Parser.parse()); auto Elements = Parser.getElements(); RootElement Elem = Elements[0].getElement(); ASSERT_TRUE(std::holds_alternative(Elem)); ASSERT_FLOAT_EQ(std::get(Elem).MipLODBias, 0.f); Elem = Elements[1].getElement(); ASSERT_TRUE(std::holds_alternative(Elem)); ASSERT_FLOAT_EQ(std::get(Elem).MipLODBias, 1.f); Elem = Elements[2].getElement(); ASSERT_TRUE(std::holds_alternative(Elem)); ASSERT_FLOAT_EQ(std::get(Elem).MipLODBias, -1.f); Elem = Elements[3].getElement(); ASSERT_TRUE(std::holds_alternative(Elem)); ASSERT_FLOAT_EQ(std::get(Elem).MipLODBias, 42.f); Elem = Elements[4].getElement(); ASSERT_TRUE(std::holds_alternative(Elem)); ASSERT_FLOAT_EQ(std::get(Elem).MipLODBias, 4.2f); Elem = Elements[5].getElement(); ASSERT_TRUE(std::holds_alternative(Elem)); ASSERT_FLOAT_EQ(std::get(Elem).MipLODBias, -.42f); Elem = Elements[6].getElement(); ASSERT_TRUE(std::holds_alternative(Elem)); ASSERT_FLOAT_EQ(std::get(Elem).MipLODBias, 420.f); Elem = Elements[7].getElement(); ASSERT_TRUE(std::holds_alternative(Elem)); ASSERT_FLOAT_EQ(std::get(Elem).MipLODBias, 0.000000000042f); Elem = Elements[8].getElement(); ASSERT_TRUE(std::holds_alternative(Elem)); ASSERT_FLOAT_EQ(std::get(Elem).MipLODBias, 42.f); Elem = Elements[9].getElement(); ASSERT_TRUE(std::holds_alternative(Elem)); ASSERT_FLOAT_EQ(std::get(Elem).MipLODBias, 4.2f); Elem = Elements[10].getElement(); ASSERT_TRUE(std::holds_alternative(Elem)); ASSERT_FLOAT_EQ(std::get(Elem).MipLODBias, 420000000000.f); Elem = Elements[11].getElement(); ASSERT_TRUE(std::holds_alternative(Elem)); ASSERT_FLOAT_EQ(std::get(Elem).MipLODBias, -2147483648.f); Elem = Elements[12].getElement(); ASSERT_TRUE(std::holds_alternative(Elem)); ASSERT_FLOAT_EQ(std::get(Elem).MipLODBias, 2147483648.f); ASSERT_TRUE(Consumer->isSatisfied()); } TEST_F(ParseHLSLRootSignatureTest, ValidSamplerFlagsTest) { // This test will checks we can set the valid enum for Sampler descriptor // range flags const llvm::StringLiteral Source = R"cc( DescriptorTable(Sampler(s0, flags = DESCRIPTORS_VOLATILE)) )cc"; auto Ctx = createMinimalASTContext(); StringLiteral *Signature = wrapSource(Ctx, Source); TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test no diagnostics produced Consumer->setNoDiag(); ASSERT_FALSE(Parser.parse()); auto Elements = Parser.getElements(); RootElement Elem = Elements[0].getElement(); ASSERT_TRUE(std::holds_alternative(Elem)); ASSERT_EQ(std::get(Elem).Type, ClauseType::Sampler); auto ValidSamplerFlags = llvm::dxbc::DescriptorRangeFlags::DescriptorsVolatile; ASSERT_EQ(std::get(Elem).Flags, ValidSamplerFlags); ASSERT_TRUE(Consumer->isSatisfied()); } TEST_F(ParseHLSLRootSignatureTest, ValidParseRootConsantsTest) { const llvm::StringLiteral Source = R"cc( RootConstants(num32BitConstants = 1, b0), RootConstants(b42, space = 3, num32BitConstants = 4294967295, visibility = SHADER_VISIBILITY_HULL ) )cc"; auto Ctx = createMinimalASTContext(); StringLiteral *Signature = wrapSource(Ctx, Source); TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test no diagnostics produced Consumer->setNoDiag(); ASSERT_FALSE(Parser.parse()); auto Elements = Parser.getElements(); ASSERT_EQ(Elements.size(), 2u); RootElement Elem = Elements[0].getElement(); ASSERT_TRUE(std::holds_alternative(Elem)); ASSERT_EQ(std::get(Elem).Num32BitConstants, 1u); ASSERT_EQ(std::get(Elem).Reg.ViewType, RegisterType::BReg); ASSERT_EQ(std::get(Elem).Reg.Number, 0u); ASSERT_EQ(std::get(Elem).Space, 0u); ASSERT_EQ(std::get(Elem).Visibility, llvm::dxbc::ShaderVisibility::All); Elem = Elements[1].getElement(); ASSERT_TRUE(std::holds_alternative(Elem)); ASSERT_EQ(std::get(Elem).Num32BitConstants, 4294967295u); ASSERT_EQ(std::get(Elem).Reg.ViewType, RegisterType::BReg); ASSERT_EQ(std::get(Elem).Reg.Number, 42u); ASSERT_EQ(std::get(Elem).Space, 3u); ASSERT_EQ(std::get(Elem).Visibility, llvm::dxbc::ShaderVisibility::Hull); ASSERT_TRUE(Consumer->isSatisfied()); } TEST_F(ParseHLSLRootSignatureTest, ValidParseRootFlagsTest) { using llvm::dxbc::RootFlags; const llvm::StringLiteral Source = R"cc( RootFlags(), RootFlags(0), RootFlags( deny_domain_shader_root_access | deny_pixel_shader_root_access | local_root_signature | cbv_srv_uav_heap_directly_indexed | deny_amplification_shader_root_access | deny_geometry_shader_root_access | deny_hull_shader_root_access | deny_mesh_shader_root_access | allow_stream_output | sampler_heap_directly_indexed | allow_input_assembler_input_layout | deny_vertex_shader_root_access ) )cc"; auto Ctx = createMinimalASTContext(); StringLiteral *Signature = wrapSource(Ctx, Source); TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test no diagnostics produced Consumer->setNoDiag(); ASSERT_FALSE(Parser.parse()); auto Elements = Parser.getElements(); ASSERT_EQ(Elements.size(), 3u); RootElement Elem = Elements[0].getElement(); ASSERT_TRUE(std::holds_alternative(Elem)); ASSERT_EQ(std::get(Elem), RootFlags::None); Elem = Elements[1].getElement(); ASSERT_TRUE(std::holds_alternative(Elem)); ASSERT_EQ(std::get(Elem), RootFlags::None); Elem = Elements[2].getElement(); ASSERT_TRUE(std::holds_alternative(Elem)); auto ValidRootFlags = RootFlags::AllowInputAssemblerInputLayout | RootFlags::DenyVertexShaderRootAccess | RootFlags::DenyHullShaderRootAccess | RootFlags::DenyDomainShaderRootAccess | RootFlags::DenyGeometryShaderRootAccess | RootFlags::DenyPixelShaderRootAccess | RootFlags::AllowStreamOutput | RootFlags::LocalRootSignature | RootFlags::DenyAmplificationShaderRootAccess | RootFlags::DenyMeshShaderRootAccess | RootFlags::CBVSRVUAVHeapDirectlyIndexed | RootFlags::SamplerHeapDirectlyIndexed; ASSERT_EQ(std::get(Elem), ValidRootFlags); ASSERT_TRUE(Consumer->isSatisfied()); } TEST_F(ParseHLSLRootSignatureTest, ValidParseRootDescriptorsTest) { using llvm::dxbc::RootDescriptorFlags; const llvm::StringLiteral Source = R"cc( CBV(b0), SRV(space = 4, t42, visibility = SHADER_VISIBILITY_GEOMETRY, flags = DATA_VOLATILE | DATA_STATIC | DATA_STATIC_WHILE_SET_AT_EXECUTE ), UAV(visibility = SHADER_VISIBILITY_HULL, u34893247), CBV(b0, flags = 0), )cc"; auto Ctx = createMinimalASTContext(); StringLiteral *Signature = wrapSource(Ctx, Source); TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test no diagnostics produced Consumer->setNoDiag(); ASSERT_FALSE(Parser.parse()); auto Elements = Parser.getElements(); ASSERT_EQ(Elements.size(), 4u); RootElement Elem = Elements[0].getElement(); ASSERT_TRUE(std::holds_alternative(Elem)); ASSERT_EQ(std::get(Elem).Type, DescriptorType::CBuffer); ASSERT_EQ(std::get(Elem).Reg.ViewType, RegisterType::BReg); ASSERT_EQ(std::get(Elem).Reg.Number, 0u); ASSERT_EQ(std::get(Elem).Space, 0u); ASSERT_EQ(std::get(Elem).Visibility, llvm::dxbc::ShaderVisibility::All); ASSERT_EQ(std::get(Elem).Flags, RootDescriptorFlags::DataStaticWhileSetAtExecute); Elem = Elements[1].getElement(); ASSERT_TRUE(std::holds_alternative(Elem)); ASSERT_EQ(std::get(Elem).Type, DescriptorType::SRV); ASSERT_EQ(std::get(Elem).Reg.ViewType, RegisterType::TReg); ASSERT_EQ(std::get(Elem).Reg.Number, 42u); ASSERT_EQ(std::get(Elem).Space, 4u); ASSERT_EQ(std::get(Elem).Visibility, llvm::dxbc::ShaderVisibility::Geometry); auto ValidRootDescriptorFlags = RootDescriptorFlags::DataVolatile | RootDescriptorFlags::DataStaticWhileSetAtExecute | RootDescriptorFlags::DataStatic; ASSERT_EQ(std::get(Elem).Flags, ValidRootDescriptorFlags); Elem = Elements[2].getElement(); ASSERT_TRUE(std::holds_alternative(Elem)); ASSERT_EQ(std::get(Elem).Type, DescriptorType::UAV); ASSERT_EQ(std::get(Elem).Reg.ViewType, RegisterType::UReg); ASSERT_EQ(std::get(Elem).Reg.Number, 34893247u); ASSERT_EQ(std::get(Elem).Space, 0u); ASSERT_EQ(std::get(Elem).Visibility, llvm::dxbc::ShaderVisibility::Hull); ASSERT_EQ(std::get(Elem).Flags, RootDescriptorFlags::DataVolatile); ASSERT_EQ(std::get(Elem).Flags, RootDescriptorFlags::DataVolatile); Elem = Elements[3].getElement(); ASSERT_EQ(std::get(Elem).Type, DescriptorType::CBuffer); ASSERT_EQ(std::get(Elem).Reg.ViewType, RegisterType::BReg); ASSERT_EQ(std::get(Elem).Reg.Number, 0u); ASSERT_EQ(std::get(Elem).Space, 0u); ASSERT_EQ(std::get(Elem).Visibility, llvm::dxbc::ShaderVisibility::All); ASSERT_EQ(std::get(Elem).Flags, RootDescriptorFlags::None); ASSERT_TRUE(Consumer->isSatisfied()); } TEST_F(ParseHLSLRootSignatureTest, ValidTrailingCommaTest) { // This test will checks we can handling trailing commas ',' const llvm::StringLiteral Source = R"cc( DescriptorTable( CBV(b0, ), SRV(t42), ) )cc"; auto Ctx = createMinimalASTContext(); StringLiteral *Signature = wrapSource(Ctx, Source); TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test no diagnostics produced Consumer->setNoDiag(); ASSERT_FALSE(Parser.parse()); ASSERT_TRUE(Consumer->isSatisfied()); } TEST_F(ParseHLSLRootSignatureTest, ValidVersion10Test) { // This test checks that the default values are set correctly // when parsing with root signature version 1.0 const llvm::StringLiteral Source = R"cc( CBV(b0), SRV(t0), UAV(u0), DescriptorTable( CBV(b1), SRV(t1), UAV(u1), Sampler(s1), ) )cc"; auto Ctx = createMinimalASTContext(); StringLiteral *Signature = wrapSource(Ctx, Source); TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_0, Signature, *PP); // Test no diagnostics produced Consumer->setNoDiag(); ASSERT_FALSE(Parser.parse()); auto Elements = Parser.getElements(); auto DefRootDescriptorFlag = llvm::dxbc::RootDescriptorFlags::DataVolatile; RootElement Elem = Elements[0].getElement(); ASSERT_TRUE(std::holds_alternative(Elem)); ASSERT_EQ(std::get(Elem).Type, DescriptorType::CBuffer); ASSERT_EQ(std::get(Elem).Flags, DefRootDescriptorFlag); Elem = Elements[1].getElement(); ASSERT_TRUE(std::holds_alternative(Elem)); ASSERT_EQ(std::get(Elem).Type, DescriptorType::SRV); ASSERT_EQ(std::get(Elem).Flags, DefRootDescriptorFlag); Elem = Elements[2].getElement(); ASSERT_TRUE(std::holds_alternative(Elem)); ASSERT_EQ(std::get(Elem).Type, DescriptorType::UAV); ASSERT_EQ(std::get(Elem).Flags, DefRootDescriptorFlag); auto ValidNonSamplerFlags = llvm::dxbc::DescriptorRangeFlags::DescriptorsVolatile | llvm::dxbc::DescriptorRangeFlags::DataVolatile; Elem = Elements[3].getElement(); ASSERT_TRUE(std::holds_alternative(Elem)); ASSERT_EQ(std::get(Elem).Type, ClauseType::CBuffer); ASSERT_EQ(std::get(Elem).Flags, ValidNonSamplerFlags); Elem = Elements[4].getElement(); ASSERT_TRUE(std::holds_alternative(Elem)); ASSERT_EQ(std::get(Elem).Type, ClauseType::SRV); ASSERT_EQ(std::get(Elem).Flags, ValidNonSamplerFlags); Elem = Elements[5].getElement(); ASSERT_TRUE(std::holds_alternative(Elem)); ASSERT_EQ(std::get(Elem).Type, ClauseType::UAV); ASSERT_EQ(std::get(Elem).Flags, ValidNonSamplerFlags); Elem = Elements[6].getElement(); ASSERT_TRUE(std::holds_alternative(Elem)); ASSERT_EQ(std::get(Elem).Type, ClauseType::Sampler); ASSERT_EQ(std::get(Elem).Flags, llvm::dxbc::DescriptorRangeFlags::DescriptorsVolatile); ASSERT_TRUE(Consumer->isSatisfied()); } TEST_F(ParseHLSLRootSignatureTest, ValidVersion11Test) { // This test checks that the default values are set correctly // when parsing with root signature version 1.1 const llvm::StringLiteral Source = R"cc( CBV(b0), SRV(t0), UAV(u0), DescriptorTable( CBV(b1), SRV(t1), UAV(u1), Sampler(s1), ) )cc"; auto Ctx = createMinimalASTContext(); StringLiteral *Signature = wrapSource(Ctx, Source); TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test no diagnostics produced Consumer->setNoDiag(); ASSERT_FALSE(Parser.parse()); auto Elements = Parser.getElements(); RootElement Elem = Elements[0].getElement(); ASSERT_TRUE(std::holds_alternative(Elem)); ASSERT_EQ(std::get(Elem).Type, DescriptorType::CBuffer); ASSERT_EQ(std::get(Elem).Flags, llvm::dxbc::RootDescriptorFlags::DataStaticWhileSetAtExecute); Elem = Elements[1].getElement(); ASSERT_TRUE(std::holds_alternative(Elem)); ASSERT_EQ(std::get(Elem).Type, DescriptorType::SRV); ASSERT_EQ(std::get(Elem).Flags, llvm::dxbc::RootDescriptorFlags::DataStaticWhileSetAtExecute); Elem = Elements[2].getElement(); ASSERT_TRUE(std::holds_alternative(Elem)); ASSERT_EQ(std::get(Elem).Type, DescriptorType::UAV); ASSERT_EQ(std::get(Elem).Flags, llvm::dxbc::RootDescriptorFlags::DataVolatile); Elem = Elements[3].getElement(); ASSERT_TRUE(std::holds_alternative(Elem)); ASSERT_EQ(std::get(Elem).Type, ClauseType::CBuffer); ASSERT_EQ(std::get(Elem).Flags, llvm::dxbc::DescriptorRangeFlags::DataStaticWhileSetAtExecute); Elem = Elements[4].getElement(); ASSERT_TRUE(std::holds_alternative(Elem)); ASSERT_EQ(std::get(Elem).Type, ClauseType::SRV); ASSERT_EQ(std::get(Elem).Flags, llvm::dxbc::DescriptorRangeFlags::DataStaticWhileSetAtExecute); Elem = Elements[5].getElement(); ASSERT_TRUE(std::holds_alternative(Elem)); ASSERT_EQ(std::get(Elem).Type, ClauseType::UAV); ASSERT_EQ(std::get(Elem).Flags, llvm::dxbc::DescriptorRangeFlags::DataVolatile); Elem = Elements[6].getElement(); ASSERT_TRUE(std::holds_alternative(Elem)); ASSERT_EQ(std::get(Elem).Type, ClauseType::Sampler); ASSERT_EQ(std::get(Elem).Flags, llvm::dxbc::DescriptorRangeFlags::None); ASSERT_TRUE(Consumer->isSatisfied()); } // Invalid Parser Tests TEST_F(ParseHLSLRootSignatureTest, InvalidParseUnexpectedTokenTest) { const llvm::StringLiteral Source = R"cc( DescriptorTable() space )cc"; auto Ctx = createMinimalASTContext(); StringLiteral *Signature = wrapSource(Ctx, Source); TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_expected_either); ASSERT_TRUE(Parser.parse()); ASSERT_TRUE(Consumer->isSatisfied()); } TEST_F(ParseHLSLRootSignatureTest, InvalidParseInvalidTokenTest) { const llvm::StringLiteral Source = R"cc( notAnIdentifier )cc"; auto Ctx = createMinimalASTContext(); StringLiteral *Signature = wrapSource(Ctx, Source); TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced - invalid token Consumer->setExpected(diag::err_hlsl_invalid_token); ASSERT_TRUE(Parser.parse()); ASSERT_TRUE(Consumer->isSatisfied()); } TEST_F(ParseHLSLRootSignatureTest, InvalidParseUnexpectedEndOfStreamTest) { const llvm::StringLiteral Source = R"cc( DescriptorTable )cc"; auto Ctx = createMinimalASTContext(); StringLiteral *Signature = wrapSource(Ctx, Source); TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced - expected '(' after DescriptorTable Consumer->setExpected(diag::err_expected_after); ASSERT_TRUE(Parser.parse()); ASSERT_TRUE(Consumer->isSatisfied()); } TEST_F(ParseHLSLRootSignatureTest, InvalidMissingDTParameterTest) { // This test will check that the parsing fails due a mandatory // parameter (register) not being specified const llvm::StringLiteral Source = R"cc( DescriptorTable( CBV() ) )cc"; auto Ctx = createMinimalASTContext(); StringLiteral *Signature = wrapSource(Ctx, Source); TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_rootsig_missing_param); ASSERT_TRUE(Parser.parse()); ASSERT_TRUE(Consumer->isSatisfied()); } TEST_F(ParseHLSLRootSignatureTest, InvalidMissingRDParameterTest) { // This test will check that the parsing fails due a mandatory // parameter (register) not being specified const llvm::StringLiteral Source = R"cc( SRV() )cc"; auto Ctx = createMinimalASTContext(); StringLiteral *Signature = wrapSource(Ctx, Source); TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_rootsig_missing_param); ASSERT_TRUE(Parser.parse()); ASSERT_TRUE(Consumer->isSatisfied()); } TEST_F(ParseHLSLRootSignatureTest, InvalidMissingRCParameterTest) { // This test will check that the parsing fails due a mandatory // parameter (num32BitConstants) not being specified const llvm::StringLiteral Source = R"cc( RootConstants(b0) )cc"; auto Ctx = createMinimalASTContext(); StringLiteral *Signature = wrapSource(Ctx, Source); TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_rootsig_missing_param); ASSERT_TRUE(Parser.parse()); ASSERT_TRUE(Consumer->isSatisfied()); } TEST_F(ParseHLSLRootSignatureTest, InvalidRepeatedMandatoryDTParameterTest) { // This test will check that the parsing fails due the same mandatory // parameter being specified multiple times const llvm::StringLiteral Source = R"cc( DescriptorTable( CBV(b32, b84) ) )cc"; auto Ctx = createMinimalASTContext(); StringLiteral *Signature = wrapSource(Ctx, Source); TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_rootsig_repeat_param); ASSERT_TRUE(Parser.parse()); ASSERT_TRUE(Consumer->isSatisfied()); } TEST_F(ParseHLSLRootSignatureTest, InvalidRepeatedMandatoryRCParameterTest) { // This test will check that the parsing fails due the same mandatory // parameter being specified multiple times const llvm::StringLiteral Source = R"cc( RootConstants(num32BitConstants = 32, num32BitConstants = 24) )cc"; auto Ctx = createMinimalASTContext(); StringLiteral *Signature = wrapSource(Ctx, Source); TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_rootsig_repeat_param); ASSERT_TRUE(Parser.parse()); ASSERT_TRUE(Consumer->isSatisfied()); } TEST_F(ParseHLSLRootSignatureTest, InvalidRepeatedOptionalDTParameterTest) { // This test will check that the parsing fails due the same optional // parameter being specified multiple times const llvm::StringLiteral Source = R"cc( DescriptorTable( CBV(space = 2, space = 0) ) )cc"; auto Ctx = createMinimalASTContext(); StringLiteral *Signature = wrapSource(Ctx, Source); TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_rootsig_repeat_param); ASSERT_TRUE(Parser.parse()); ASSERT_TRUE(Consumer->isSatisfied()); } TEST_F(ParseHLSLRootSignatureTest, InvalidRepeatedOptionalRCParameterTest) { // This test will check that the parsing fails due the same optional // parameter being specified multiple times const llvm::StringLiteral Source = R"cc( RootConstants( visibility = Shader_Visibility_All, b0, num32BitConstants = 1, visibility = Shader_Visibility_Pixel ) )cc"; auto Ctx = createMinimalASTContext(); StringLiteral *Signature = wrapSource(Ctx, Source); TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_rootsig_repeat_param); ASSERT_TRUE(Parser.parse()); ASSERT_TRUE(Consumer->isSatisfied()); } TEST_F(ParseHLSLRootSignatureTest, InvalidLexOverflowedNumberTest) { // This test will check that the lexing fails due to an integer overflow const llvm::StringLiteral Source = R"cc( DescriptorTable( CBV(b4294967296) ) )cc"; auto Ctx = createMinimalASTContext(); StringLiteral *Signature = wrapSource(Ctx, Source); TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_number_literal_overflow); ASSERT_TRUE(Parser.parse()); ASSERT_TRUE(Consumer->isSatisfied()); } TEST_F(ParseHLSLRootSignatureTest, InvalidParseOverflowedNegativeNumberTest) { // This test will check that parsing fails due to a unsigned integer having // too large of a magnitude to be interpreted as its negative const llvm::StringLiteral Source = R"cc( StaticSampler(s0, mipLODBias = -4294967295) )cc"; auto Ctx = createMinimalASTContext(); StringLiteral *Signature = wrapSource(Ctx, Source); TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_number_literal_overflow); ASSERT_TRUE(Parser.parse()); ASSERT_TRUE(Consumer->isSatisfied()); } TEST_F(ParseHLSLRootSignatureTest, InvalidLexOverflowedFloatTest) { // This test will check that the lexing fails due to a float overflow const llvm::StringLiteral Source = R"cc( StaticSampler(s0, mipLODBias = 3.402823467e+38F) )cc"; auto Ctx = createMinimalASTContext(); StringLiteral *Signature = wrapSource(Ctx, Source); TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_number_literal_overflow); ASSERT_TRUE(Parser.parse()); ASSERT_TRUE(Consumer->isSatisfied()); } TEST_F(ParseHLSLRootSignatureTest, InvalidLexNegOverflowedFloatTest) { // This test will check that the lexing fails due to negative float overflow const llvm::StringLiteral Source = R"cc( StaticSampler(s0, mipLODBias = -3.402823467e+38F) )cc"; auto Ctx = createMinimalASTContext(); StringLiteral *Signature = wrapSource(Ctx, Source); TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_number_literal_overflow); ASSERT_TRUE(Parser.parse()); ASSERT_TRUE(Consumer->isSatisfied()); } TEST_F(ParseHLSLRootSignatureTest, InvalidLexOverflowedDoubleTest) { // This test will check that the lexing fails due to an overflow of double const llvm::StringLiteral Source = R"cc( StaticSampler(s0, mipLODBias = 1.e+500) )cc"; auto Ctx = createMinimalASTContext(); StringLiteral *Signature = wrapSource(Ctx, Source); TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_number_literal_overflow); ASSERT_TRUE(Parser.parse()); ASSERT_TRUE(Consumer->isSatisfied()); } TEST_F(ParseHLSLRootSignatureTest, InvalidLexUnderflowFloatTest) { // This test will check that the lexing fails due to double underflow const llvm::StringLiteral Source = R"cc( StaticSampler(s0, mipLODBias = 10e-309) )cc"; auto Ctx = createMinimalASTContext(); StringLiteral *Signature = wrapSource(Ctx, Source); TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_number_literal_underflow); ASSERT_TRUE(Parser.parse()); ASSERT_TRUE(Consumer->isSatisfied()); } TEST_F(ParseHLSLRootSignatureTest, InvalidNonZeroFlagsTest) { // This test will check that parsing fails when a non-zero integer literal // is given to flags const llvm::StringLiteral Source = R"cc( DescriptorTable( CBV(b0, flags = 3) ) )cc"; auto Ctx = createMinimalASTContext(); StringLiteral *Signature = wrapSource(Ctx, Source); TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_rootsig_non_zero_flag); ASSERT_TRUE(Parser.parse()); ASSERT_TRUE(Consumer->isSatisfied()); } TEST_F(ParseHLSLRootSignatureTest, InvalidRootElementMissingCommaTest) { // This test will check that an error is produced when there is a missing // comma between parameters const llvm::StringLiteral Source = R"cc( RootFlags() RootConstants(num32BitConstants = 1, b0) )cc"; auto Ctx = createMinimalASTContext(); StringLiteral *Signature = wrapSource(Ctx, Source); TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_expected_either); ASSERT_TRUE(Parser.parse()); ASSERT_TRUE(Consumer->isSatisfied()); } TEST_F(ParseHLSLRootSignatureTest, InvalidDescriptorTableMissingCommaTest) { // This test will check that an error is produced when there is a missing // comma between parameters const llvm::StringLiteral Source = R"cc( DescriptorTable( CBV(b0) visibility = SHADER_VISIBILITY_ALL ) )cc"; auto Ctx = createMinimalASTContext(); StringLiteral *Signature = wrapSource(Ctx, Source); TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_expected_either); ASSERT_TRUE(Parser.parse()); ASSERT_TRUE(Consumer->isSatisfied()); } TEST_F(ParseHLSLRootSignatureTest, InvalidRootConstantParamsCommaTest) { // This test will check that an error is produced when there is a missing // comma between parameters const llvm::StringLiteral Source = R"cc( RootConstants( num32BitConstants = 1 b0 ) )cc"; auto Ctx = createMinimalASTContext(); StringLiteral *Signature = wrapSource(Ctx, Source); TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_expected_either); ASSERT_TRUE(Parser.parse()); ASSERT_TRUE(Consumer->isSatisfied()); } TEST_F(ParseHLSLRootSignatureTest, InvalidRootDescriptorParamsCommaTest) { // This test will check that an error is produced when there is a missing // comma between parameters const llvm::StringLiteral Source = R"cc( CBV( b0 flags = 0 ) )cc"; auto Ctx = createMinimalASTContext(); StringLiteral *Signature = wrapSource(Ctx, Source); TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_expected_either); ASSERT_TRUE(Parser.parse()); ASSERT_TRUE(Consumer->isSatisfied()); } TEST_F(ParseHLSLRootSignatureTest, InvalidDescriptorClauseParamsCommaTest) { // This test will check that an error is produced when there is a missing // comma between parameters const llvm::StringLiteral Source = R"cc( DescriptorTable( UAV( u0 flags = 0 ) ) )cc"; auto Ctx = createMinimalASTContext(); StringLiteral *Signature = wrapSource(Ctx, Source); TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_expected_either); ASSERT_TRUE(Parser.parse()); ASSERT_TRUE(Consumer->isSatisfied()); } TEST_F(ParseHLSLRootSignatureTest, InvalidStaticSamplerCommaTest) { // This test will check that an error is produced when there is a missing // comma between parameters const llvm::StringLiteral Source = R"cc( StaticSampler( s0 maxLOD = 3 ) )cc"; auto Ctx = createMinimalASTContext(); StringLiteral *Signature = wrapSource(Ctx, Source); TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_expected_either); ASSERT_TRUE(Parser.parse()); ASSERT_TRUE(Consumer->isSatisfied()); } TEST_F(ParseHLSLRootSignatureTest, InvalidRootDescriptorParamTest) { // This test will check that an error is produced when there is a invalid // value of a parameter const llvm::StringLiteral Source = R"cc( SRV(t0, invalid) )cc"; auto Ctx = createMinimalASTContext(); StringLiteral *Signature = wrapSource(Ctx, Source); TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_invalid_token); ASSERT_TRUE(Parser.parse()); ASSERT_TRUE(Consumer->isSatisfied()); } TEST_F(ParseHLSLRootSignatureTest, InvalidDescriptorTableParamTest) { // This test will check that an error is produced when there is a invalid // value of a parameter const llvm::StringLiteral Source = R"cc( DescriptorTable( visibility = SHADER_VISIBILITY_ALL, invalid ) )cc"; auto Ctx = createMinimalASTContext(); StringLiteral *Signature = wrapSource(Ctx, Source); TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_invalid_token); ASSERT_TRUE(Parser.parse()); ASSERT_TRUE(Consumer->isSatisfied()); } TEST_F(ParseHLSLRootSignatureTest, InvalidDescriptorTableClauseParamTest) { // This test will check that an error is produced when there is a invalid // value of a parameter const llvm::StringLiteral Source = R"cc( DescriptorTable( CBV(invalid) ) )cc"; auto Ctx = createMinimalASTContext(); StringLiteral *Signature = wrapSource(Ctx, Source); TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_invalid_token); ASSERT_TRUE(Parser.parse()); ASSERT_TRUE(Consumer->isSatisfied()); } TEST_F(ParseHLSLRootSignatureTest, InvalidStaticSamplerParamTest) { // This test will check that an error is produced when there is a invalid // value of a parameter const llvm::StringLiteral Source = R"cc( StaticSampler( s0, filter = FILTER_MAXIMUM_MIN_POINT_MAG_LINEAR_MIP_POINT, invalid, comparisonFunc = COMPARISON_EQUAL, ) )cc"; auto Ctx = createMinimalASTContext(); StringLiteral *Signature = wrapSource(Ctx, Source); TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_invalid_token); ASSERT_TRUE(Parser.parse()); ASSERT_TRUE(Consumer->isSatisfied()); } TEST_F(ParseHLSLRootSignatureTest, InvalidVisibilityValueTest) { // This test will check that an error is produced when there is a invalid // value of a parameter const llvm::StringLiteral Source = R"cc( UAV( u0, visibility = SHADER_VISIBILITY_TYPO ) )cc"; auto Ctx = createMinimalASTContext(); StringLiteral *Signature = wrapSource(Ctx, Source); TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_invalid_token); ASSERT_TRUE(Parser.parse()); ASSERT_TRUE(Consumer->isSatisfied()); } TEST_F(ParseHLSLRootSignatureTest, InvalidRegisterValueTest) { // This test will check that an error is produced when there is a invalid // value of a parameter const llvm::StringLiteral Source = R"cc( StaticSampler( b0 ) )cc"; auto Ctx = createMinimalASTContext(); StringLiteral *Signature = wrapSource(Ctx, Source); TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_invalid_token); ASSERT_TRUE(Parser.parse()); ASSERT_TRUE(Consumer->isSatisfied()); } TEST_F(ParseHLSLRootSignatureTest, InvalidFilterValueTest) { // This test will check that an error is produced when there is a invalid // value of a parameter const llvm::StringLiteral Source = R"cc( StaticSampler( s0, filter = FILTER_TYPO ) )cc"; auto Ctx = createMinimalASTContext(); StringLiteral *Signature = wrapSource(Ctx, Source); TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_invalid_token); ASSERT_TRUE(Parser.parse()); ASSERT_TRUE(Consumer->isSatisfied()); } TEST_F(ParseHLSLRootSignatureTest, InvalidTextureAddressModeValueTest) { // This test will check that an error is produced when there is a invalid // value of a parameter const llvm::StringLiteral Source = R"cc( StaticSampler( s0, addressU = TEXTURE_ADDRESS_MODE_TYPO ) )cc"; auto Ctx = createMinimalASTContext(); StringLiteral *Signature = wrapSource(Ctx, Source); TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_invalid_token); ASSERT_TRUE(Parser.parse()); ASSERT_TRUE(Consumer->isSatisfied()); } TEST_F(ParseHLSLRootSignatureTest, InvalidComparisonFuncValueTest) { // This test will check that an error is produced when there is a invalid // value of a parameter const llvm::StringLiteral Source = R"cc( StaticSampler( s0, comparisonFunc = COMPARISON_FUNC_TYPO ) )cc"; auto Ctx = createMinimalASTContext(); StringLiteral *Signature = wrapSource(Ctx, Source); TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_invalid_token); ASSERT_TRUE(Parser.parse()); ASSERT_TRUE(Consumer->isSatisfied()); } TEST_F(ParseHLSLRootSignatureTest, InvalidStaticBorderColorValueTest) { // This test will check that an error is produced when there is a invalid // value of a parameter const llvm::StringLiteral Source = R"cc( StaticSampler( s0, borderColor = STATIC_BORDER_COLOR_TYPO ) )cc"; auto Ctx = createMinimalASTContext(); StringLiteral *Signature = wrapSource(Ctx, Source); TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_invalid_token); ASSERT_TRUE(Parser.parse()); ASSERT_TRUE(Consumer->isSatisfied()); } TEST_F(ParseHLSLRootSignatureTest, InvalidRootFlagsValueTest) { // This test will check that an error is produced when there is a invalid // value of a parameter const llvm::StringLiteral Source = R"cc( RootFlags( ROOT_FLAG_TYPO ) )cc"; auto Ctx = createMinimalASTContext(); StringLiteral *Signature = wrapSource(Ctx, Source); TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_invalid_token); ASSERT_TRUE(Parser.parse()); ASSERT_TRUE(Consumer->isSatisfied()); } TEST_F(ParseHLSLRootSignatureTest, InvalidRootDescriptorFlagsValueTest) { // This test will check that an error is produced when there is a invalid // value of a parameter const llvm::StringLiteral Source = R"cc( CBV( flags = DATA_STATIC | ROOT_DESRIPTOR_FLAG_TYPO ) )cc"; auto Ctx = createMinimalASTContext(); StringLiteral *Signature = wrapSource(Ctx, Source); TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_invalid_token); ASSERT_TRUE(Parser.parse()); ASSERT_TRUE(Consumer->isSatisfied()); } TEST_F(ParseHLSLRootSignatureTest, InvalidDescriptorRangeFlagsValueTest) { // This test will check that an error is produced when there is a invalid // value of a parameter const llvm::StringLiteral Source = R"cc( DescriptorTable( CBV( flags = DATA_STATIC | DESRIPTOR_RANGE_FLAG_TYPO | DESCRIPTORS_VOLATILE ) ) )cc"; auto Ctx = createMinimalASTContext(); StringLiteral *Signature = wrapSource(Ctx, Source); TrivialModuleLoader ModLoader; auto PP = createPP(Source, ModLoader); hlsl::RootSignatureParser Parser(RootSignatureVersion::V1_1, Signature, *PP); // Test correct diagnostic produced Consumer->setExpected(diag::err_hlsl_invalid_token); ASSERT_TRUE(Parser.parse()); ASSERT_TRUE(Consumer->isSatisfied()); } } // anonymous namespace