Skip to content

Commit e20926a

Browse files
authored
[spir-v] Add option to print SPIR-V between passes (#4503)
This debug/development option matches the `--print-all` flag in spirv-opt or `--print-after-all`/`--print-before-all` in llvm's opt. The new option can be enabled with `-fspv-print-all`.
1 parent b602097 commit e20926a

8 files changed

Lines changed: 102 additions & 6 deletions

File tree

include/dxc/Support/HLSLOptions.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,8 @@ def Wno_vk_ignored_features : Joined<["-"], "Wno-vk-ignored-features">, Group<sp
367367
HelpText<"Do not emit warnings for ingored features resulting from no Vulkan support">;
368368
def Wno_vk_emulated_features : Joined<["-"], "Wno-vk-emulated-features">, Group<spirv_Group>, Flags<[CoreOption, DriverOption, HelpHidden]>,
369369
HelpText<"Do not emit warnings for emulated features resulting from no direct mapping">;
370+
def fspv_print_all: Flag<["-"], "fspv-print-all">, Group<spirv_Group>, Flags<[CoreOption, DriverOption]>,
371+
HelpText<"Print the SPIR-V module before each pass and after the last one. Useful for debugging SPIR-V legalization and optimization passes.">;
370372
def Oconfig : CommaJoined<["-"], "Oconfig=">, Group<spirv_Group>, Flags<[CoreOption]>,
371373
HelpText<"Specify a comma-separated list of SPIRV-Tools passes to customize optimization configuration (see http://khr.io/hlsl2spirv#optimization)">;
372374
// SPIRV Change Ends

include/dxc/Support/SPIRVOptions.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ struct SpirvCodeGenOptions {
8989

9090
bool signaturePacking; ///< Whether signature packing is enabled or not
9191

92+
bool printAll; // Dump SPIR-V module before each pass and after the last one.
93+
9294
// String representation of all command line options.
9395
std::string clOptions;
9496
};

lib/DxcSupport/HLSLOptions.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -986,6 +986,8 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
986986
opts.SpirvOptions.allowedExtensions.push_back(A->getValue());
987987
}
988988

989+
opts.SpirvOptions.printAll = Args.hasFlag(OPT_fspv_print_all, OPT_INVALID, false);
990+
989991
opts.SpirvOptions.debugInfoFile = opts.SpirvOptions.debugInfoSource = false;
990992
opts.SpirvOptions.debugInfoLine = opts.SpirvOptions.debugInfoTool = false;
991993
opts.SpirvOptions.debugInfoRich = false;
@@ -1081,6 +1083,7 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
10811083
Args.hasFlag(OPT_fspv_reduce_load_size, OPT_INVALID, false) ||
10821084
Args.hasFlag(OPT_fspv_reflect, OPT_INVALID, false) ||
10831085
Args.hasFlag(OPT_fspv_fix_func_call_arguments, OPT_INVALID, false) ||
1086+
Args.hasFlag(OPT_fspv_print_all, OPT_INVALID, false) ||
10841087
Args.hasFlag(OPT_Wno_vk_ignored_features, OPT_INVALID, false) ||
10851088
Args.hasFlag(OPT_Wno_vk_emulated_features, OPT_INVALID, false) ||
10861089
Args.hasFlag(OPT_fvk_auto_shift_bindings, OPT_INVALID, false) ||

tools/clang/include/clang/SPIRV/String.h

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,13 @@
99
#ifndef LLVM_CLANG_SPIRV_STRING_H
1010
#define LLVM_CLANG_SPIRV_STRING_H
1111

12-
#include <string>
13-
#include <vector>
14-
1512
#include "llvm/ADT/ArrayRef.h"
1613
#include "llvm/ADT/StringRef.h"
14+
#include "llvm/Support/raw_ostream.h"
15+
16+
#include <streambuf>
17+
#include <string>
18+
#include <vector>
1719

1820
namespace clang {
1921
namespace spirv {
@@ -28,6 +30,36 @@ std::vector<uint32_t> encodeSPIRVString(llvm::StringRef strChars);
2830
/// It follows the SPIR-V string encoding requirements.
2931
std::string decodeSPIRVString(llvm::ArrayRef<uint32_t> strWords);
3032

33+
/// \brief Stream buffer implementation that writes to `llvm::raw_ostream`.
34+
/// Intended to be used with APIs that write to `std::ostream`.
35+
///
36+
/// Sample:
37+
/// ```
38+
/// RawOstreamBuf buf(llvm::errs());
39+
/// std::ostream os(&buf);
40+
/// some_print(os);
41+
/// ```
42+
class RawOstreamBuf : public std::streambuf {
43+
public:
44+
RawOstreamBuf(llvm::raw_ostream &os) : os(os) {}
45+
using char_type = std::streambuf::char_type;
46+
using int_type = std::streambuf::int_type;
47+
48+
protected:
49+
std::streamsize xsputn(const char_type *s, std::streamsize count) override {
50+
os << llvm::StringRef(s, count);
51+
return count;
52+
}
53+
54+
int_type overflow(int_type c) override {
55+
os << char_type(c);
56+
return 0;
57+
}
58+
59+
private:
60+
llvm::raw_ostream &os;
61+
};
62+
3163
} // end namespace string
3264
} // end namespace spirv
3365
} // end namespace clang

tools/clang/lib/SPIRV/SpirvEmitter.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13032,12 +13032,16 @@ bool SpirvEmitter::spirvToolsValidate(std::vector<uint32_t> *mod,
1303213032
bool SpirvEmitter::spirvToolsOptimize(std::vector<uint32_t> *mod,
1303313033
std::string *messages) {
1303413034
spvtools::Optimizer optimizer(featureManager.getTargetEnv());
13035-
1303613035
optimizer.SetMessageConsumer(
1303713036
[messages](spv_message_level_t /*level*/, const char * /*source*/,
1303813037
const spv_position_t & /*position*/,
1303913038
const char *message) { *messages += message; });
1304013039

13040+
string::RawOstreamBuf printAllBuf(llvm::errs());
13041+
std::ostream printAllOS(&printAllBuf);
13042+
if (spirvOptions.printAll)
13043+
optimizer.SetPrintAll(&printAllOS);
13044+
1304113045
spvtools::OptimizerOptions options;
1304213046
options.set_run_validator(false);
1304313047

@@ -13073,6 +13077,11 @@ bool SpirvEmitter::spirvToolsLegalize(std::vector<uint32_t> *mod,
1307313077
const spv_position_t & /*position*/,
1307413078
const char *message) { *messages += message; });
1307513079

13080+
string::RawOstreamBuf printAllBuf(llvm::errs());
13081+
std::ostream printAllOS(&printAllBuf);
13082+
if (spirvOptions.printAll)
13083+
optimizer.SetPrintAll(&printAllOS);
13084+
1307613085
spvtools::OptimizerOptions options;
1307713086
options.set_run_validator(false);
1307813087
// Add interface variable SROA if the signature packing is enabled.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// RUN: %dxc -T ps_6_0 -E main -spirv -fspv-print-all
2+
3+
// We expect the whole module to be printed multiple times, but we cannot check
4+
// that here as stderr contents do not appear as test diagnostics. Instead,
5+
// just confirm that the file compiles fine with `-fspv-print-all` enabled.
6+
7+
// CHECK: OpEntryPoint Fragment %main
8+
9+
struct Input
10+
{
11+
float4 color : COLOR;
12+
};
13+
14+
float4 main(Input input) : SV_TARGET
15+
{
16+
return input.color;
17+
}

tools/clang/unittests/SPIRV/CodeGenSpirvTest.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3126,4 +3126,6 @@ float4 PSMain(float4 color : COLOR) : SV_TARGET { return color; }
31263126

31273127
TEST_F(FileTest, RenameEntrypoint) { runFileTest("fspv-entrypoint-name.hlsl"); }
31283128

3129+
TEST_F(FileTest, PrintAll) { runFileTest("fspv-print-all.hlsl"); }
3130+
31293131
} // namespace

tools/clang/unittests/SPIRV/StringTest.cpp

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@
77
//
88
//===----------------------------------------------------------------------===//
99

10-
#include "gmock/gmock.h"
1110
#include "clang/SPIRV/String.h"
11+
#include "llvm/Support/raw_ostream.h"
12+
#include "gmock/gmock.h"
1213
#include "gtest/gtest.h"
14+
#include <ostream>
1315

1416
namespace {
1517

@@ -79,7 +81,34 @@ TEST(String, EncodeAndDecodeString) {
7981

8082
EXPECT_EQ(str, result);
8183
}
82-
8384
// TODO: Add more ModuleBuilder tests
8485

86+
TEST(String, RawOstreamBuf) {
87+
// Set up the following output stream structure:
88+
// os -> buf -> rawOS -> underlyingBuffer
89+
//
90+
// Check that the contents written to `os` appear in `underlyingBuffer`.
91+
std::string underlingBuffer;
92+
llvm::raw_string_ostream rawOS(underlingBuffer);
93+
string::RawOstreamBuf buf(rawOS);
94+
std::ostream os(&buf);
95+
96+
// Flushes both buffers.
97+
auto flush = [&rawOS, &os] {
98+
os.flush();
99+
rawOS.flush();
100+
};
101+
102+
EXPECT_EQ(underlingBuffer, "");
103+
os << "test";
104+
flush();
105+
EXPECT_EQ(underlingBuffer, "test");
106+
os << 13 << 37 << "\n";
107+
flush();
108+
EXPECT_EQ(underlingBuffer, "test1337\n");
109+
os << ' ';
110+
flush();
111+
EXPECT_EQ(underlingBuffer, "test1337\n ");
112+
}
113+
85114
} // anonymous namespace

0 commit comments

Comments
 (0)