Skip to content

[passmanager] Change SIL pass pipeline plan to use an LLVM YAML representation. #29111

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 64 additions & 64 deletions lib/SILOptimizer/PassManager/PassPipeline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -755,82 +755,82 @@ SILPassPipelinePlan::getPassPipelineForKinds(const SILOptions &Options,
// Dumping And Loading Pass Pipelines from Yaml
//===----------------------------------------------------------------------===//

namespace {

struct YAMLPassPipeline {
std::string name;
std::vector<PassKind> passes;

YAMLPassPipeline() {}
YAMLPassPipeline(const SILPassPipeline &pipeline,
SILPassPipelinePlan::PipelineKindRange pipelineKinds)
: name(pipeline.Name), passes() {
llvm::copy(pipelineKinds, std::back_inserter(passes));
}
};

} // end anonymous namespace

namespace llvm {
namespace yaml {

template <> struct ScalarEnumerationTraits<PassKind> {
static void enumeration(IO &io, PassKind &value) {
#define PASS(ID, TAG, NAME) io.enumCase(value, #TAG, PassKind::ID);
#include "swift/SILOptimizer/PassManager/Passes.def"
}
};

template <> struct MappingTraits<YAMLPassPipeline> {
static void mapping(IO &io, YAMLPassPipeline &info) {
io.mapRequired("name", info.name);
io.mapRequired("passes", info.passes);
}
};

} // namespace yaml
} // namespace llvm

LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(PassKind)
LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(YAMLPassPipeline)

void SILPassPipelinePlan::dump() {
print(llvm::errs());
llvm::errs() << '\n';
}

void SILPassPipelinePlan::print(llvm::raw_ostream &os) {
// Our pipelines yaml representation is simple, we just output it ourselves
// rather than use the yaml writer interface. We want to use the yaml reader
// interface to be resilient against slightly different forms of yaml.
os << "[\n";
interleave(getPipelines(),
[&](const SILPassPipeline &Pipeline) {
os << " [\n";

os << " \"" << Pipeline.Name << "\"";
for (PassKind Kind : getPipelinePasses(Pipeline)) {
os << ",\n [\"" << PassKindID(Kind) << "\","
<< "\"" << PassKindTag(Kind) << "\"]";
}
},
[&] { os << "\n ],\n"; });
os << "\n ]\n";
os << ']';
llvm::yaml::Output out(os);
std::vector<YAMLPassPipeline> data;
transform(getPipelines(), std::back_inserter(data),
[&](const SILPassPipeline &pipeline) {
return YAMLPassPipeline(pipeline, getPipelinePasses(pipeline));
});
out << data;
}

SILPassPipelinePlan
SILPassPipelinePlan::getPassPipelineFromFile(const SILOptions &Options,
StringRef Filename) {
namespace yaml = llvm::yaml;
LLVM_DEBUG(llvm::dbgs() << "Parsing Pass Pipeline from " << Filename << "\n");

// Load the input file.
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileBufOrErr =
llvm::MemoryBuffer::getFileOrSTDIN(Filename);
if (!FileBufOrErr) {
llvm_unreachable("Failed to read yaml file");
}

StringRef Buffer = FileBufOrErr->get()->getBuffer();
llvm::SourceMgr SM;
yaml::Stream Stream(Buffer, SM);
yaml::document_iterator DI = Stream.begin();
assert(DI != Stream.end() && "Failed to read a document");
yaml::Node *N = DI->getRoot();
assert(N && "Failed to find a root");
SILPassPipelinePlan::getPassPipelineFromFile(const SILOptions &options,
StringRef filename) {
std::vector<YAMLPassPipeline> yamlPipelines;
{
// Load the input file.
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> fileBufOrErr =
llvm::MemoryBuffer::getFileOrSTDIN(filename);
if (!fileBufOrErr) {
llvm_unreachable("Failed to read yaml file");
}

SILPassPipelinePlan P(Options);
llvm::yaml::Input in(fileBufOrErr->get()->getBuffer());
in >> yamlPipelines;
}

auto *RootList = cast<yaml::SequenceNode>(N);
llvm::SmallVector<PassKind, 32> Passes;
for (yaml::Node &PipelineNode :
make_range(RootList->begin(), RootList->end())) {
Passes.clear();
LLVM_DEBUG(llvm::dbgs() << "New Pipeline:\n");

auto *Desc = cast<yaml::SequenceNode>(&PipelineNode);
yaml::SequenceNode::iterator DescIter = Desc->begin();
StringRef Name = cast<yaml::ScalarNode>(&*DescIter)->getRawValue();
LLVM_DEBUG(llvm::dbgs() << " Name: \"" << Name << "\"\n");
++DescIter;

for (auto DescEnd = Desc->end(); DescIter != DescEnd; ++DescIter) {
auto *InnerPassList = cast<yaml::SequenceNode>(&*DescIter);
auto *FirstNode = &*InnerPassList->begin();
StringRef PassName = cast<yaml::ScalarNode>(FirstNode)->getRawValue();
unsigned Size = PassName.size() - 2;
PassName = PassName.substr(1, Size);
LLVM_DEBUG(llvm::dbgs() << " Pass: \"" << PassName << "\"\n");
auto Kind = PassKindFromString(PassName);
assert(Kind != PassKind::invalidPassKind && "Found invalid pass kind?!");
Passes.push_back(Kind);
}
SILPassPipelinePlan silPlan(options);

P.startPipeline(Name);
P.addPasses(Passes);
for (auto &pipeline : yamlPipelines) {
silPlan.startPipeline(pipeline.name);
silPlan.addPasses(pipeline.passes);
}

return P;
return silPlan;
}
3 changes: 2 additions & 1 deletion lib/Serialization/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ add_swift_host_library(swiftSerialization STATIC
BitstreamReader
)
target_link_libraries(swiftSerialization PRIVATE
swiftClangImporter)
swiftClangImporter
swiftSIL)

24 changes: 11 additions & 13 deletions test/sil-passpipeline-dump/basic.test-sh
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
// RUN: %sil-passpipeline-dumper -Onone | %FileCheck %s
// RUN: %sil-passpipeline-dumper -Onone | %{python} -c 'import json; import sys; json.load(sys.stdin)'

// CHECK: [
// CHECK: [
// CHECK: "Serialization",
// CHECK: ["SerializeSILPass","serialize-sil"]
// CHECK: ],
// CHECK: [
// CHECK: "Rest of Onone",
// CHECK: ["UsePrespecialized","use-prespecialized"],
// CHECK: ["AssumeSingleThreaded","sil-assume-single-threaded"],
// CHECK: ["SILDebugInfoGenerator","sil-debuginfo-gen"]
// CHECK: ]
// CHECK: ]
// CHECK: ---
// CHECK: name: Mandatory Combines
// CHECK: passes: [ "for-each-loop-unroll", "mandatory-combine" ]
// CHECK: ---
// CHECK: name: Serialization
// CHECK: passes: [ "serialize-sil", "ownership-model-eliminator" ]
// CHECK: ---
// CHECK: name: Rest of Onone
// CHECK: passes: [ "use-prespecialized", "sil-assume-single-threaded",
// CHECK: "sil-debuginfo-gen" ]
// CHECK: ...
18 changes: 8 additions & 10 deletions tools/sil-passpipeline-dumper/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@ add_swift_host_tool(sil-passpipeline-dumper
SILPassPipelineDumper.cpp
SWIFT_COMPONENT tools
)
target_link_libraries(sil-passpipeline-dumper
PRIVATE
swiftClangImporter
swiftFrontend
swiftSerialization
swiftSILGen
swiftSILOptimizer
# FIXME: Circular dependencies require re-listing these libraries.
swiftAST
swiftSema)
target_link_libraries(sil-passpipeline-dumper PRIVATE
swiftFrontend
swiftIRGen
swiftSILGen
swiftSILOptimizer
# Clang libraries included to appease the linker on linux.
clangBasic
clangCodeGen)