emit-c-as-single-file: move to new backend

This commit is contained in:
Ivan Krysak
2026-06-04 11:00:19 +00:00
committed by Pietro Fezzardi
parent 190405a77b
commit 14ea4b6cd7
9 changed files with 134 additions and 191 deletions
@@ -1,50 +0,0 @@
#pragma once
//
// This file is distributed under the MIT License. See LICENSE.md for details.
//
#include <array>
#include <string>
#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<pipeline::ContractGroup, 1> 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
@@ -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<MetaAddress> &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<PipeRunArgument<const PTMLCFunctionBytesContainer,
+2 -7
View File
@@ -3,13 +3,8 @@
#
revng_add_analyses_library_internal(
revngBackend
ALAPVariableDeclaration.cpp
DecompilePipe.cpp
DecompileFunction.cpp
EmitCAsDirectoryPipe.cpp
EmitCAsSingleFile.cpp
EmitCAsSingleFilePipe.cpp)
revngBackend ALAPVariableDeclaration.cpp DecompilePipe.cpp
DecompileFunction.cpp EmitCAsDirectoryPipe.cpp)
target_link_libraries(
revngBackend
+21 -1
View File
@@ -7,7 +7,6 @@
#include "revng/Backend/DecompileFunction.h"
#include "revng/Backend/EmitCAsDirectoryPipe.h"
#include "revng/Backend/EmitCAsSingleFile.h"
#include "revng/EarlyFunctionAnalysis/ControlFlowGraphCache.h"
#include "revng/HeadersGeneration/Options.h"
#include "revng/HeadersGeneration/PTMLHeaderBuilder.h"
@@ -16,6 +15,27 @@
#include "revng/Support/GzipTarFile.h"
#include "revng/Support/ResourceFinder.h"
static void printSingleCFile(ptml::ModelCBuilder &B,
const revng::pipes::DecompileStringMap &Functions,
const std::set<MetaAddress> &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;
-67
View File
@@ -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<MetaAddress> &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
-50
View File
@@ -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<DecompiledFileContainer>
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<revng::pipes::EmitCAsSingleFile> Y;
+1
View File
@@ -7,6 +7,7 @@ revng_add_analyses_library_internal(
CliftContainer.cpp
Clifter.cpp
EmitC.cpp
EmitCAsSingleFile.cpp
Headers.cpp
ImportDataModel.cpp
ImportDescriptiveInfo.cpp
+106
View File
@@ -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<DecompiledFileContainer>
Reg;
} // namespace revng::pipes
class EmitCAsSingleFile {
public:
static constexpr auto Name = "emit-c-as-single-file";
std::array<pipeline::ContractGroup, 1> 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<EmitCAsSingleFile> 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<llvm::raw_pwrite_stream> 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
+1 -1
View File
@@ -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"