yum-mirror/slang

Making it easier to work with shaders

git clone https://git.yummers.dev/yum-mirror/slang

Ellie HermaszewskaCorrect include dir for libslang (#5539)7b570feed

master
5.6 KiB189 linesraw
1// This file contains a definition of LLVMFileCheck, an implementaion for
2// IFileCheck.
3
4#include "slang-com-helper.h"
5#include "slang-com-ptr.h"
6#include "slang.h"
7
8#include <core/slang-com-object.h>
9#include <llvm/ADT/SmallString.h>
10#include <llvm/FileCheck/FileCheck.h>
11#include <llvm/Support/raw_ostream.h>
12#include <slang-test/filecheck.h>
13
14namespace slang_llvm
15{
16
17using namespace llvm;
18using namespace Slang;
19
20class LLVMFileCheck : IFileCheck, ComBaseObject
21{
22public:
23    // ICastable
24    virtual SLANG_NO_THROW void* SLANG_MCALL castAs(const Guid& guid) override;
25
26    // IUnknown
27    SLANG_COM_BASE_IUNKNOWN_ALL
28    void* getInterface(const Guid& guid);
29    void* getObject(const Guid& guid);
30
31    // IFileCheck
32    virtual TestResult SLANG_MCALL performTest(
33        const char* programName,
34        const char* rulesFilePath,
35        const char* fileCheckPrefix,
36        const char* stringToCheck,
37        const char* stringToCheckName,
38        ReportDiagnostic testReporter,
39        void* reporterData,
40        bool colorDiagnosticOutput) noexcept override;
41
42private:
43    // Everything we need to pass through LLVM back to our diagnostic handler
44    struct ReporterData
45    {
46        ReportDiagnostic reportFun;
47        // User data from the caller of performTest
48        void* data;
49        bool colorDiagnosticOutput;
50        const char* programName;
51        TestMessageType testMessageType;
52    };
53
54    static void fileCheckDiagHandler(const SMDiagnostic& diag, void* reporterData);
55};
56
57class DisplayedStringOStream : public raw_string_ostream
58{
59public:
60    DisplayedStringOStream(std::string& s)
61        : raw_string_ostream(s)
62    {
63    }
64    virtual bool is_displayed() const override { return true; };
65};
66
67void LLVMFileCheck::fileCheckDiagHandler(const SMDiagnostic& diag, void* dataPtr)
68{
69    const ReporterData& reporterData = *reinterpret_cast<ReporterData*>(dataPtr);
70    std::string s;
71    DisplayedStringOStream o(s);
72    o.enable_colors(reporterData.colorDiagnosticOutput);
73    diag.print(reporterData.programName, o);
74    reporterData.reportFun(reporterData.data, TestMessageType::TestFailure, s.c_str());
75}
76
77TestResult LLVMFileCheck::performTest(
78    const char* const programName,
79    const char* const rulesFilePath,
80    const char* const fileCheckPrefix,
81    const char* const stringToCheck,
82    const char* const stringToCheckName,
83    const ReportDiagnostic testReporter,
84    void* const userReporterData,
85    const bool colorDiagnosticOutput) noexcept
86{
87    //
88    // Set up our FileCheck session
89    //
90    FileCheckRequest fcReq;
91    fcReq.CheckPrefixes = {fileCheckPrefix};
92    FileCheck fc(fcReq);
93
94    //
95    // Set up the LLVM source manager for diagnostic output from our input buffers
96    //
97    SourceMgr sourceManager;
98    auto rulesTextOrError = MemoryBuffer::getFile(rulesFilePath, true);
99    if (std::error_code err = rulesTextOrError.getError())
100    {
101        const std::string message = "Unable to load FileCheck rules file: " + err.message();
102        testReporter(userReporterData, TestMessageType::RunError, message.c_str());
103        return TestResult::Fail;
104    }
105    SmallString<4096> rulesBuffer;
106    StringRef rulesStringRef = fc.CanonicalizeFile(*rulesTextOrError.get(), rulesBuffer);
107    sourceManager.AddNewSourceBuffer(
108        MemoryBuffer::getMemBuffer(rulesStringRef, rulesFilePath),
109        SMLoc());
110
111    SmallString<4096> inputBuffer;
112    const auto inputStringMB =
113        MemoryBuffer::getMemBuffer(StringRef(stringToCheck), stringToCheckName, false);
114    const StringRef inputStringRef = fc.CanonicalizeFile(*inputStringMB.get(), inputBuffer);
115    sourceManager.AddNewSourceBuffer(
116        MemoryBuffer::getMemBuffer(inputStringRef, stringToCheckName),
117        SMLoc());
118
119    // Initialize this with a 'RunError' failure type. We'll "downgrade" this to
120    // 'TestFailure' once we've done the FileCheck setup.
121    ReporterData reporterData{
122        testReporter,
123        userReporterData,
124        colorDiagnosticOutput,
125        programName,
126        TestMessageType::RunError};
127    sourceManager.setDiagHandler(fileCheckDiagHandler, static_cast<void*>(&reporterData));
128
129    auto checkPrefix = fc.buildCheckPrefixRegex();
130    if (fc.readCheckFile(sourceManager, rulesStringRef, checkPrefix))
131    {
132        // FileCheck failed to find or understand any FileCheck rules in
133        // the input file, automatic fail, and reported to the diag handler .
134        return TestResult::Fail;
135    }
136
137    // We've done the FileCheck setup, so make sure that any diagnostics
138    // reported on from here are just a regular test failure.
139    reporterData.testMessageType = TestMessageType::TestFailure;
140    if (!fc.checkInput(sourceManager, inputStringRef))
141    {
142        // An ordinary failure, the FileCheck rules didn't match
143        return TestResult::Fail;
144    }
145
146    return TestResult::Pass;
147}
148
149void* LLVMFileCheck::castAs(const Guid& guid)
150{
151    if (auto ptr = getInterface(guid))
152    {
153        return ptr;
154    }
155    return getObject(guid);
156}
157
158void* LLVMFileCheck::getInterface(const Guid& guid)
159{
160    if (guid == ISlangUnknown::getTypeGuid() || guid == ICastable::getTypeGuid() ||
161        guid == IFileCheck::getTypeGuid())
162    {
163        return static_cast<IFileCheck*>(this);
164    }
165    return nullptr;
166}
167
168void* LLVMFileCheck::getObject(const Guid& guid)
169{
170    SLANG_UNUSED(guid);
171    return nullptr;
172}
173
174} // namespace slang_llvm
175
176extern "C" SLANG_DLL_EXPORT SlangResult
177createLLVMFileCheck_V1(const SlangUUID& intfGuid, void** out)
178{
179    Slang::ComPtr<slang_llvm::LLVMFileCheck> fileCheck(new slang_llvm::LLVMFileCheck);
180
181    if (auto ptr = fileCheck->castAs(intfGuid))
182    {
183        fileCheck.detach();
184        *out = ptr;
185        return SLANG_OK;
186    }
187
188    return SLANG_E_NO_INTERFACE;
189}