diff --git a/include/revng/Backend/EmitCAsSingleFilePipe.h b/include/revng/Backend/EmitCAsSingleFilePipe.h deleted file mode 100644 index 550b9243f..000000000 --- a/include/revng/Backend/EmitCAsSingleFilePipe.h +++ /dev/null @@ -1,50 +0,0 @@ -#pragma once - -// -// This file is distributed under the MIT License. See LICENSE.md for details. -// - -#include -#include - -#include "llvm/ADT/ArrayRef.h" -#include "llvm/Support/raw_ostream.h" - -#include "revng/Backend/DecompilePipe.h" -#include "revng/Pipeline/Context.h" -#include "revng/Pipeline/Contract.h" -#include "revng/Pipes/Kinds.h" -#include "revng/Pipes/StringBufferContainer.h" -#include "revng/Pipes/StringMap.h" - -namespace revng::pipes { - -inline constexpr char DecompiledMIMEType[] = "text/x.c+ptml"; -inline constexpr char DecompiledSuffix[] = ".c"; -inline constexpr char DecompiledName[] = "decompiled-c-code"; -using DecompiledFileContainer = StringBufferContainer<&kinds::DecompiledToC, - DecompiledName, - DecompiledMIMEType, - DecompiledSuffix>; - -class EmitCAsSingleFile { -public: - static constexpr auto Name = "emit-c-as-single-file"; - - std::array getContract() const { - using namespace pipeline; - using namespace revng::kinds; - - return { ContractGroup({ Contract(Decompiled, - 0, - DecompiledToC, - 1, - InputPreservation::Preserve) }) }; - } - - void run(pipeline::ExecutionContext &EC, - const DecompileStringMap &DecompiledFunctionsContainer, - DecompiledFileContainer &OutCFile); -}; - -} // end namespace revng::pipes diff --git a/include/revng/Backend/EmitCAsSingleFile.h b/include/revng/CliftPipes/EmitCAsSingleFile.h similarity index 75% rename from include/revng/Backend/EmitCAsSingleFile.h rename to include/revng/CliftPipes/EmitCAsSingleFile.h index f59708d7e..fb38c58e9 100644 --- a/include/revng/Backend/EmitCAsSingleFile.h +++ b/include/revng/CliftPipes/EmitCAsSingleFile.h @@ -4,23 +4,9 @@ // This file is distributed under the MIT License. See LICENSE.md for details. // -#include "revng/Backend/DecompilePipe.h" +#include "revng/CliftPipes/Configuration.h" #include "revng/Pipebox/Containers.h" #include "revng/PipeboxCommon/Model.h" -#include "revng/Pipes/StringMap.h" -#include "revng/Support/MetaAddress.h" - -namespace ptml { -class ModelCBuilder; -} - -namespace detail { -using DecompiledStringMap = revng::pipes::DecompileStringMap; -} - -void printSingleCFile(ptml::ModelCBuilder &B, - const detail::DecompiledStringMap &Functions, - const std::set &Targets); namespace revng::pypeline { @@ -32,6 +18,8 @@ private: const PTMLCFunctionBytesContainer &Input; PTMLCBytesContainer &Output; + CEmissionPipeConfiguration Configuration; + public: static constexpr llvm::StringRef Name = "emit-c-as-single-file"; using Arguments = TypeList &Targets) { + auto Scope = B.getScopeTag(ptml::tags::Div); + // Print headers + B.append(B.getIncludeQuote("types-and-globals.h") + + B.getIncludeQuote("helpers.h") + "\n"); + + if (Targets.empty()) { + // If Targets is empty print all the Functions' bodies + for (const auto &[MetaAddress, CFunction] : Functions) + B.append(CFunction + '\n'); + } else { + // Otherwise only print the bodies of the Targets + auto End = Functions.end(); + for (const auto &MetaAddress : Targets) + if (auto It = Functions.find(MetaAddress); It != End) + B.append(It->second + '\n'); + } +} + namespace revng::pipes { using namespace pipeline; diff --git a/lib/Backend/EmitCAsSingleFile.cpp b/lib/Backend/EmitCAsSingleFile.cpp deleted file mode 100644 index dfb9a6b72..000000000 --- a/lib/Backend/EmitCAsSingleFile.cpp +++ /dev/null @@ -1,67 +0,0 @@ -// -// This file is distributed under the MIT License. See LICENSE.md for details. -// - -#include "llvm/Support/raw_ostream.h" - -#include "revng/Backend/EmitCAsSingleFile.h" -#include "revng/TypeNames/ModelCBuilder.h" - -using namespace revng::pipes; - -void printSingleCFile(ptml::ModelCBuilder &B, - const DecompileStringMap &Functions, - const std::set &Targets) { - auto Scope = B.getScopeTag(ptml::tags::Div); - // Print headers - B.append(B.getIncludeQuote("types-and-globals.h") - + B.getIncludeQuote("helpers.h") + "\n"); - - if (Targets.empty()) { - // If Targets is empty print all the Functions' bodies - for (const auto &[MetaAddress, CFunction] : Functions) - B.append(CFunction + '\n'); - } else { - // Otherwise only print the bodies of the Targets - auto End = Functions.end(); - for (const auto &MetaAddress : Targets) - if (auto It = Functions.find(MetaAddress); It != End) - B.append(It->second + '\n'); - } -} - -namespace revng::pypeline::piperuns { - -EmitCAsSingleFile::EmitCAsSingleFile(const class Model &Model, - llvm::StringRef Config, - llvm::StringRef DynamicConfig, - const PTMLCFunctionBytesContainer &Input, - PTMLCBytesContainer &Output) : - Binary(*Model.get().get()), Input(Input), Output(Output) { -} - -void EmitCAsSingleFile::run() { - auto Out = Output.getOStream(ObjectID()); - ptml::ModelCBuilder B(*Out, - Binary, - /* EnableTaglessMode = */ false, - // Disable stack frame inlining because enabling it - // could break the property that we emit syntactically - // valid C code, due to the stack frame type definition - // being duplicated in the global header and - // in the function's body. In the single file artifact - // recompilability is still important. - { .EnableStackFrameInlining = false }); - - auto Scope = B.getScopeTag(ptml::tags::Div); - // Print headers - B.append(B.getIncludeQuote("types-and-globals.h") - + B.getIncludeQuote("helpers.h") + "\n"); - - for (const auto &Object : Input.objects()) { - auto Buffer = Input.getMemoryBuffer(Object); - B.append(Buffer->getBuffer().str() + "\n"); - } -} - -} // namespace revng::pypeline::piperuns diff --git a/lib/Backend/EmitCAsSingleFilePipe.cpp b/lib/Backend/EmitCAsSingleFilePipe.cpp deleted file mode 100644 index cbe887c14..000000000 --- a/lib/Backend/EmitCAsSingleFilePipe.cpp +++ /dev/null @@ -1,50 +0,0 @@ -// -// This file is distributed under the MIT License. See LICENSE.md for details. -// - -#include "revng/Backend/EmitCAsSingleFile.h" -#include "revng/Backend/EmitCAsSingleFilePipe.h" -#include "revng/HeadersGeneration/Options.h" -#include "revng/Pipeline/AllRegistries.h" -#include "revng/Pipeline/RegisterContainerFactory.h" -#include "revng/Pipes/FileContainer.h" -#include "revng/Pipes/Kinds.h" -#include "revng/TypeNames/ModelCBuilder.h" - -using namespace revng::kinds; - -namespace revng::pipes { - -static pipeline::RegisterDefaultConstructibleContainer - Reg; - -using Container = DecompileStringMap; -void EmitCAsSingleFile::run(pipeline::ExecutionContext &EC, - const Container &DecompiledFunctions, - DecompiledFileContainer &OutCFile) { - - llvm::raw_string_ostream Out = OutCFile.asStream(); - - namespace options = revng::options; - ptml::ModelCBuilder B(Out, - *getModelFromContext(EC), - /* EnableTaglessMode = */ false, - // Disable stack frame inlining because enabling it - // could break the property that we emit syntactically - // valid C code, due to the stack frame type definition - // being duplicated in the global header and - // in the function's body. In the single file artifact - // recompilability is still important. - { .EnableStackFrameInlining = false }); - - // Make a single C file with an empty set of targets, which means all the - // functions in DecompiledFunctions - printSingleCFile(B, DecompiledFunctions, {} /* Targets */); - Out.flush(); - - EC.commitUniqueTarget(OutCFile); -} - -} // end namespace revng::pipes - -static pipeline::RegisterPipe Y; diff --git a/lib/CliftPipes/CMakeLists.txt b/lib/CliftPipes/CMakeLists.txt index 5542ea0ad..ab4bf1d3c 100644 --- a/lib/CliftPipes/CMakeLists.txt +++ b/lib/CliftPipes/CMakeLists.txt @@ -7,6 +7,7 @@ revng_add_analyses_library_internal( CliftContainer.cpp Clifter.cpp EmitC.cpp + EmitCAsSingleFile.cpp Headers.cpp ImportDataModel.cpp ImportDescriptiveInfo.cpp diff --git a/lib/CliftPipes/EmitCAsSingleFile.cpp b/lib/CliftPipes/EmitCAsSingleFile.cpp new file mode 100644 index 000000000..4dab48826 --- /dev/null +++ b/lib/CliftPipes/EmitCAsSingleFile.cpp @@ -0,0 +1,106 @@ +// +// This file is distributed under the MIT License. See LICENSE.md for details. +// + +#include "revng/CliftPipes/EmitCAsSingleFile.h" +#include "revng/PTML/CTokenEmitter.h" +#include "revng/PTML/Constants.h" +#include "revng/PTML/PTMLEmitter.h" +#include "revng/Pipeline/AllRegistries.h" +#include "revng/Pipes/Containers.h" +#include "revng/Pipes/FileContainer.h" +#include "revng/Pipes/Kinds.h" +#include "revng/Pipes/StringBufferContainer.h" + +static void printIncludes(ptml::CTokenEmitter &Tokens) { + + Tokens.emitIncludeDirective("types-and-globals.h", + "", + ptml::CTokenEmitter::IncludeMode::Quote); + Tokens.emitIncludeDirective("helpers.h", + "", + ptml::CTokenEmitter::IncludeMode::Quote); + Tokens.emitNewline(); +} + +namespace revng::pipes { + +inline constexpr char DecompiledMIMEType[] = "text/x.c+ptml"; +inline constexpr char DecompiledSuffix[] = ".c"; +inline constexpr char DecompiledName[] = "decompiled-c-code"; +using DecompiledFileContainer = StringBufferContainer<&kinds::DecompiledToC, + DecompiledName, + DecompiledMIMEType, + DecompiledSuffix>; + +static pipeline::RegisterDefaultConstructibleContainer + Reg; + +} // namespace revng::pipes + +class EmitCAsSingleFile { +public: + static constexpr auto Name = "emit-c-as-single-file"; + + std::array getContract() const { + using namespace pipeline; + using namespace revng::kinds; + + return { ContractGroup({ Contract(Decompiled, + 0, + DecompiledToC, + 1, + InputPreservation::Preserve) }) }; + } + + void run(pipeline::ExecutionContext &EC, + const revng::pipes::DecompileStringMap &DecompiledFunctions, + revng::pipes::DecompiledFileContainer &OutCFile) { + { + llvm::raw_string_ostream Out = OutCFile.asStream(); + static constexpr ptml::Tagging Tags = ptml::Tagging::Enabled; + + ptml::CTokenEmitter Tokens(Out, Tags); + printIncludes(Tokens); + + ptml::StreamEmitter RawEmitter(Out); + for (const auto &[MetaAddress, CFunction] : DecompiledFunctions) + RawEmitter.emit(CFunction + "\n"); + } + + EC.commitUniqueTarget(OutCFile); + } +}; + +static pipeline::RegisterPipe Y; + +namespace revng::pypeline::piperuns { + +EmitCAsSingleFile::EmitCAsSingleFile(const class Model &Model, + llvm::StringRef Configuration, + llvm::StringRef DynamicConfig, + const PTMLCFunctionBytesContainer &Input, + PTMLCBytesContainer &Output) : + Binary(*Model.get().get()), + Input(Input), + Output(Output), + Configuration(parseCEmissionPipeConfiguration(Configuration)) { +} + +void EmitCAsSingleFile::run() { + std::unique_ptr Out = Output.getOStream(ObjectID()); + + ptml::CTokenEmitter Tokens(*Out, + Configuration.DisableMarkup ? + ptml::Tagging::Disabled : + ptml::Tagging::Enabled); + printIncludes(Tokens); + + ptml::StreamEmitter RawEmitter(*Out); + for (const auto &Object : Input.objects()) { + auto Buffer = Input.getMemoryBuffer(Object); + RawEmitter.emit(Buffer->getBuffer().str() + "\n"); + } +} + +} // namespace revng::pypeline::piperuns diff --git a/lib/Pipebox/Pipebox.cpp b/lib/Pipebox/Pipebox.cpp index afd43d3c4..c69d746a1 100644 --- a/lib/Pipebox/Pipebox.cpp +++ b/lib/Pipebox/Pipebox.cpp @@ -4,11 +4,11 @@ #include "revng/ABI/Analyses/ConvertFunctionsToCABI.h" #include "revng/ABI/Analyses/ConvertFunctionsToRaw.h" -#include "revng/Backend/EmitCAsSingleFile.h" #include "revng/Canonicalize/SimplifySwitch.h" #include "revng/Canonicalize/SwitchToStatements.h" #include "revng/CliftPipes/Clifter.h" #include "revng/CliftPipes/EmitC.h" +#include "revng/CliftPipes/EmitCAsSingleFile.h" #include "revng/CliftPipes/Headers.h" #include "revng/CliftPipes/ImportDataModel.h" #include "revng/CliftPipes/ImportDescriptiveInfo.h"