
- defines the Parser class and an initial set of helper methods to support consuming tokens. functionality is demonstrated through a simple empty descriptor table test case - defines an initial in-memory representation of a DescriptorTable - implements a test harness that will be used to validate the correct diagnostics are generated. it will construct a dummy pre-processor with diagnostics consumer to do so Implements the first part of https://github.com/llvm/llvm-project/issues/126569
246 lines
7.3 KiB
C++
246 lines
7.3 KiB
C++
//=== 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/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 llvm::hlsl::rootsig;
|
|
|
|
namespace {
|
|
|
|
// 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<unsigned> 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, new DiagnosticOptions, 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<Preprocessor> createPP(StringRef Source,
|
|
TrivialModuleLoader &ModLoader) {
|
|
std::unique_ptr<llvm::MemoryBuffer> Buf =
|
|
llvm::MemoryBuffer::getMemBuffer(Source);
|
|
SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf)));
|
|
|
|
HeaderSearchOptions SearchOpts;
|
|
HeaderSearch HeaderInfo(SearchOpts, SourceMgr, Diags, LangOpts,
|
|
Target.get());
|
|
std::unique_ptr<Preprocessor> PP = std::make_unique<Preprocessor>(
|
|
std::make_shared<PreprocessorOptions>(), Diags, LangOpts, SourceMgr,
|
|
HeaderInfo, ModLoader,
|
|
/*IILookup =*/nullptr,
|
|
/*OwnsHeaderSearch =*/false);
|
|
PP->Initialize(*Target);
|
|
PP->EnterMainSourceFile();
|
|
return PP;
|
|
}
|
|
|
|
FileSystemOptions FileMgrOpts;
|
|
FileManager FileMgr;
|
|
IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
|
|
ExpectedDiagConsumer *Consumer;
|
|
DiagnosticsEngine Diags;
|
|
SourceManager SourceMgr;
|
|
LangOptions LangOpts;
|
|
std::shared_ptr<TargetOptions> TargetOpts;
|
|
IntrusiveRefCntPtr<TargetInfo> Target;
|
|
};
|
|
|
|
// Valid Parser Tests
|
|
|
|
TEST_F(ParseHLSLRootSignatureTest, ValidParseEmptyTest) {
|
|
const llvm::StringLiteral Source = R"cc()cc";
|
|
|
|
TrivialModuleLoader ModLoader;
|
|
auto PP = createPP(Source, ModLoader);
|
|
auto TokLoc = SourceLocation();
|
|
|
|
hlsl::RootSignatureLexer Lexer(Source, TokLoc);
|
|
SmallVector<RootElement> Elements;
|
|
hlsl::RootSignatureParser Parser(Elements, Lexer, *PP);
|
|
|
|
// Test no diagnostics produced
|
|
Consumer->setNoDiag();
|
|
|
|
ASSERT_FALSE(Parser.parse());
|
|
ASSERT_EQ((int)Elements.size(), 0);
|
|
|
|
ASSERT_TRUE(Consumer->isSatisfied());
|
|
}
|
|
|
|
TEST_F(ParseHLSLRootSignatureTest, ValidParseDTClausesTest) {
|
|
const llvm::StringLiteral Source = R"cc(
|
|
DescriptorTable(
|
|
CBV(),
|
|
SRV(),
|
|
Sampler(),
|
|
UAV()
|
|
),
|
|
DescriptorTable()
|
|
)cc";
|
|
|
|
TrivialModuleLoader ModLoader;
|
|
auto PP = createPP(Source, ModLoader);
|
|
auto TokLoc = SourceLocation();
|
|
|
|
hlsl::RootSignatureLexer Lexer(Source, TokLoc);
|
|
SmallVector<RootElement> Elements;
|
|
hlsl::RootSignatureParser Parser(Elements, Lexer, *PP);
|
|
|
|
// Test no diagnostics produced
|
|
Consumer->setNoDiag();
|
|
|
|
ASSERT_FALSE(Parser.parse());
|
|
|
|
// First Descriptor Table with 4 elements
|
|
RootElement Elem = Elements[0];
|
|
ASSERT_TRUE(std::holds_alternative<DescriptorTableClause>(Elem));
|
|
ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Type, ClauseType::CBuffer);
|
|
|
|
Elem = Elements[1];
|
|
ASSERT_TRUE(std::holds_alternative<DescriptorTableClause>(Elem));
|
|
ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Type, ClauseType::SRV);
|
|
|
|
Elem = Elements[2];
|
|
ASSERT_TRUE(std::holds_alternative<DescriptorTableClause>(Elem));
|
|
ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Type, ClauseType::Sampler);
|
|
|
|
Elem = Elements[3];
|
|
ASSERT_TRUE(std::holds_alternative<DescriptorTableClause>(Elem));
|
|
ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Type, ClauseType::UAV);
|
|
|
|
Elem = Elements[4];
|
|
ASSERT_TRUE(std::holds_alternative<DescriptorTable>(Elem));
|
|
ASSERT_EQ(std::get<DescriptorTable>(Elem).NumClauses, (uint32_t)4);
|
|
|
|
// Empty Descriptor Table
|
|
Elem = Elements[5];
|
|
ASSERT_TRUE(std::holds_alternative<DescriptorTable>(Elem));
|
|
ASSERT_EQ(std::get<DescriptorTable>(Elem).NumClauses, 0u);
|
|
ASSERT_TRUE(Consumer->isSatisfied());
|
|
}
|
|
|
|
// Invalid Parser Tests
|
|
|
|
TEST_F(ParseHLSLRootSignatureTest, InvalidParseUnexpectedTokenTest) {
|
|
const llvm::StringLiteral Source = R"cc(
|
|
DescriptorTable()
|
|
space
|
|
)cc";
|
|
|
|
TrivialModuleLoader ModLoader;
|
|
auto PP = createPP(Source, ModLoader);
|
|
auto TokLoc = SourceLocation();
|
|
|
|
hlsl::RootSignatureLexer Lexer(Source, TokLoc);
|
|
SmallVector<RootElement> Elements;
|
|
hlsl::RootSignatureParser Parser(Elements, Lexer, *PP);
|
|
|
|
// Test correct diagnostic produced
|
|
Consumer->setExpected(diag::err_hlsl_unexpected_end_of_params);
|
|
ASSERT_TRUE(Parser.parse());
|
|
|
|
ASSERT_TRUE(Consumer->isSatisfied());
|
|
}
|
|
|
|
TEST_F(ParseHLSLRootSignatureTest, InvalidParseInvalidTokenTest) {
|
|
const llvm::StringLiteral Source = R"cc(
|
|
notAnIdentifier
|
|
)cc";
|
|
|
|
TrivialModuleLoader ModLoader;
|
|
auto PP = createPP(Source, ModLoader);
|
|
auto TokLoc = SourceLocation();
|
|
|
|
hlsl::RootSignatureLexer Lexer(Source, TokLoc);
|
|
SmallVector<RootElement> Elements;
|
|
hlsl::RootSignatureParser Parser(Elements, Lexer, *PP);
|
|
|
|
// Test correct diagnostic produced - invalid token
|
|
Consumer->setExpected(diag::err_hlsl_unexpected_end_of_params);
|
|
ASSERT_TRUE(Parser.parse());
|
|
|
|
ASSERT_TRUE(Consumer->isSatisfied());
|
|
}
|
|
|
|
TEST_F(ParseHLSLRootSignatureTest, InvalidParseUnexpectedEndOfStreamTest) {
|
|
const llvm::StringLiteral Source = R"cc(
|
|
DescriptorTable
|
|
)cc";
|
|
|
|
TrivialModuleLoader ModLoader;
|
|
auto PP = createPP(Source, ModLoader);
|
|
auto TokLoc = SourceLocation();
|
|
|
|
hlsl::RootSignatureLexer Lexer(Source, TokLoc);
|
|
SmallVector<RootElement> Elements;
|
|
hlsl::RootSignatureParser Parser(Elements, Lexer, *PP);
|
|
|
|
// Test correct diagnostic produced - end of stream
|
|
Consumer->setExpected(diag::err_expected_after);
|
|
ASSERT_TRUE(Parser.parse());
|
|
|
|
ASSERT_TRUE(Consumer->isSatisfied());
|
|
}
|
|
|
|
} // anonymous namespace
|