From c86d304f4dd75858e7f726a730df2aef5bdfe2c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20C=C3=A1rdenas?= Date: Tue, 8 Jul 2025 04:41:10 +0200 Subject: [PATCH 01/10] [llvm-advisor] add initial project structure and configuration The AdvisorConfig class provides JSON based configuration loading with file classification patterns and output directory management. --- llvm/tools/llvm-advisor/CMakeLists.txt | 15 +++++ llvm/tools/llvm-advisor/config/config.json | 7 ++ llvm/tools/llvm-advisor/src/CMakeLists.txt | 35 ++++++++++ .../llvm-advisor/src/Config/AdvisorConfig.cpp | 64 +++++++++++++++++++ .../llvm-advisor/src/Config/AdvisorConfig.h | 41 ++++++++++++ 5 files changed, 162 insertions(+) create mode 100644 llvm/tools/llvm-advisor/CMakeLists.txt create mode 100644 llvm/tools/llvm-advisor/config/config.json create mode 100644 llvm/tools/llvm-advisor/src/CMakeLists.txt create mode 100644 llvm/tools/llvm-advisor/src/Config/AdvisorConfig.cpp create mode 100644 llvm/tools/llvm-advisor/src/Config/AdvisorConfig.h diff --git a/llvm/tools/llvm-advisor/CMakeLists.txt b/llvm/tools/llvm-advisor/CMakeLists.txt new file mode 100644 index 0000000000000..d2389bdd1e0fa --- /dev/null +++ b/llvm/tools/llvm-advisor/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 3.18) + +set(LLVM_TOOL_LLVM_ADVISOR_BUILD_DEFAULT ON) +set(LLVM_REQUIRE_EXE_NAMES llvm-advisor) + +add_subdirectory(src) + +# Set the executable name +set_target_properties(llvm-advisor PROPERTIES + OUTPUT_NAME llvm-advisor) + +# Install the binary +install(TARGETS llvm-advisor + RUNTIME DESTINATION bin + COMPONENT llvm-advisor) diff --git a/llvm/tools/llvm-advisor/config/config.json b/llvm/tools/llvm-advisor/config/config.json new file mode 100644 index 0000000000000..9e94a41ff46c4 --- /dev/null +++ b/llvm/tools/llvm-advisor/config/config.json @@ -0,0 +1,7 @@ +{ + "outputDir": ".llvm-advisor", + "verbose": false, + "keepTemps": false, + "runProfiler": true, + "timeout": 60 +} diff --git a/llvm/tools/llvm-advisor/src/CMakeLists.txt b/llvm/tools/llvm-advisor/src/CMakeLists.txt new file mode 100644 index 0000000000000..81088f8231625 --- /dev/null +++ b/llvm/tools/llvm-advisor/src/CMakeLists.txt @@ -0,0 +1,35 @@ +# Gather all .cpp sources in this directory tree +file(GLOB_RECURSE LLVM_ADVISOR_SOURCES CONFIGURE_DEPENDS + ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp +) + +# Define the executable target +add_llvm_tool(llvm-advisor + ${LLVM_ADVISOR_SOURCES} +) + +# Link required LLVM libraries +target_link_libraries(llvm-advisor PRIVATE + LLVMSupport + LLVMCore + LLVMIRReader + LLVMBitWriter + LLVMRemarks + LLVMProfileData +) + +# Set include directories +target_include_directories(llvm-advisor PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} +) + +# Install the Python view module alongside the binary +install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../view/ + DESTINATION ${CMAKE_INSTALL_BINDIR}/view + FILES_MATCHING + PATTERN "*.py" + PATTERN "*.html" + PATTERN "*.css" + PATTERN "*.js" + PATTERN "*.md" +) diff --git a/llvm/tools/llvm-advisor/src/Config/AdvisorConfig.cpp b/llvm/tools/llvm-advisor/src/Config/AdvisorConfig.cpp new file mode 100644 index 0000000000000..69f1e3d52702e --- /dev/null +++ b/llvm/tools/llvm-advisor/src/Config/AdvisorConfig.cpp @@ -0,0 +1,64 @@ +#include "AdvisorConfig.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/JSON.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" + +namespace llvm { +namespace advisor { + +AdvisorConfig::AdvisorConfig() { + // Use relative path as default, will be resolved by CompilationManager + OutputDir_ = ".llvm-advisor"; +} + +Expected AdvisorConfig::loadFromFile(const std::string &path) { + auto BufferOrError = MemoryBuffer::getFile(path); + if (!BufferOrError) { + return createStringError(BufferOrError.getError(), + "Cannot read config file"); + } + + auto Buffer = std::move(*BufferOrError); + Expected JsonOrError = json::parse(Buffer->getBuffer()); + if (!JsonOrError) { + return JsonOrError.takeError(); + } + + auto &Json = *JsonOrError; + auto *Obj = Json.getAsObject(); + if (!Obj) { + return createStringError(std::make_error_code(std::errc::invalid_argument), + "Config file must contain JSON object"); + } + + if (auto outputDirOpt = Obj->getString("outputDir"); outputDirOpt) { + OutputDir_ = outputDirOpt->str(); + } + + if (auto verboseOpt = Obj->getBoolean("verbose"); verboseOpt) { + Verbose_ = *verboseOpt; + } + + if (auto keepTempsOpt = Obj->getBoolean("keepTemps"); keepTempsOpt) { + KeepTemps_ = *keepTempsOpt; + } + + if (auto runProfileOpt = Obj->getBoolean("runProfiler"); runProfileOpt) { + RunProfiler_ = *runProfileOpt; + } + + if (auto timeoutOpt = Obj->getInteger("timeout"); timeoutOpt) { + TimeoutSeconds_ = static_cast(*timeoutOpt); + } + + return true; +} + +std::string AdvisorConfig::getToolPath(const std::string &tool) const { + // For now, just return the tool name and rely on PATH + return tool; +} + +} // namespace advisor +} // namespace llvm diff --git a/llvm/tools/llvm-advisor/src/Config/AdvisorConfig.h b/llvm/tools/llvm-advisor/src/Config/AdvisorConfig.h new file mode 100644 index 0000000000000..b7f553fddbb23 --- /dev/null +++ b/llvm/tools/llvm-advisor/src/Config/AdvisorConfig.h @@ -0,0 +1,41 @@ +#ifndef LLVM_ADVISOR_CONFIG_H +#define LLVM_ADVISOR_CONFIG_H + +#include "llvm/Support/Error.h" +#include + +namespace llvm { +namespace advisor { + +class AdvisorConfig { +public: + AdvisorConfig(); + + Expected loadFromFile(const std::string &path); + + void setOutputDir(const std::string &dir) { OutputDir_ = dir; } + void setVerbose(bool verbose) { Verbose_ = verbose; } + void setKeepTemps(bool keep) { KeepTemps_ = keep; } + void setRunProfiler(bool run) { RunProfiler_ = run; } + void setTimeout(int seconds) { TimeoutSeconds_ = seconds; } + + const std::string &getOutputDir() const { return OutputDir_; } + bool getVerbose() const { return Verbose_; } + bool getKeepTemps() const { return KeepTemps_; } + bool getRunProfiler() const { return RunProfiler_; } + int getTimeout() const { return TimeoutSeconds_; } + + std::string getToolPath(const std::string &tool) const; + +private: + std::string OutputDir_; + bool Verbose_ = false; + bool KeepTemps_ = false; + bool RunProfiler_ = true; + int TimeoutSeconds_ = 60; +}; + +} // namespace advisor +} // namespace llvm + +#endif From 181e4457e2b5eb1d2417c320fc80cdb7480198dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20C=C3=A1rdenas?= Date: Sun, 13 Jul 2025 05:51:00 +0200 Subject: [PATCH 02/10] [llvm-advisor] Add utility for file and process management - Add FileManager for file operations. - Add FileClassifier for compilation artifact categorization. - Add ProcessRunner for subprocess execution. --- .../llvm-advisor/src/Utils/FileClassifier.cpp | 136 ++++++++++++ .../llvm-advisor/src/Utils/FileClassifier.h | 26 +++ .../llvm-advisor/src/Utils/FileManager.cpp | 205 ++++++++++++++++++ .../llvm-advisor/src/Utils/FileManager.h | 46 ++++ .../llvm-advisor/src/Utils/ProcessRunner.cpp | 69 ++++++ .../llvm-advisor/src/Utils/ProcessRunner.h | 32 +++ 6 files changed, 514 insertions(+) create mode 100644 llvm/tools/llvm-advisor/src/Utils/FileClassifier.cpp create mode 100644 llvm/tools/llvm-advisor/src/Utils/FileClassifier.h create mode 100644 llvm/tools/llvm-advisor/src/Utils/FileManager.cpp create mode 100644 llvm/tools/llvm-advisor/src/Utils/FileManager.h create mode 100644 llvm/tools/llvm-advisor/src/Utils/ProcessRunner.cpp create mode 100644 llvm/tools/llvm-advisor/src/Utils/ProcessRunner.h diff --git a/llvm/tools/llvm-advisor/src/Utils/FileClassifier.cpp b/llvm/tools/llvm-advisor/src/Utils/FileClassifier.cpp new file mode 100644 index 0000000000000..e9b39f984c771 --- /dev/null +++ b/llvm/tools/llvm-advisor/src/Utils/FileClassifier.cpp @@ -0,0 +1,136 @@ +#include "FileClassifier.h" +#include "llvm/Support/Path.h" + +namespace llvm { +namespace advisor { + +FileClassification +FileClassifier::classifyFile(const std::string &filePath) const { + StringRef filename = sys::path::filename(filePath); + StringRef extension = sys::path::extension(filePath); + + FileClassification classification; + classification.isGenerated = true; + classification.isTemporary = false; + + // LLVM IR files + if (extension == ".ll") { + classification.category = "ir"; + classification.description = "LLVM IR text"; + return classification; + } + + // Assembly files + if (extension == ".s" || extension == ".S") { + classification.category = "assembly"; + classification.description = "Assembly"; + return classification; + } + + // Optimization remarks + if (filename.ends_with(".opt.yaml") || filename.ends_with(".opt.yml")) { + classification.category = "remarks"; + classification.description = "Optimization remarks"; + return classification; + } + + // Preprocessed files + if (extension == ".i" || extension == ".ii") { + classification.category = "preprocessed"; + classification.description = "Preprocessed source"; + return classification; + } + + // AST dumps + if (extension == ".ast" || filename.contains("ast-dump")) { + classification.category = "ast"; + classification.description = "AST dump"; + return classification; + } + + // Profile data + if (extension == ".profraw" || extension == ".profdata") { + classification.category = "profile"; + classification.description = "Profile data"; + return classification; + } + + // Include trees + if (filename.contains(".include.") || filename.contains("include-tree")) { + classification.category = "include-tree"; + classification.description = "Include tree"; + return classification; + } + + // Debug info + if (filename.contains("debug") || filename.contains("dwarf")) { + classification.category = "debug"; + classification.description = "Debug information"; + return classification; + } + + // Static analyzer output + if (filename.contains("analysis") || filename.contains("analyzer")) { + classification.category = "static-analyzer"; + classification.description = "Static analyzer output"; + return classification; + } + + // Macro expansion + if (filename.contains("macro-expanded")) { + classification.category = "macro-expansion"; + classification.description = "Macro expansion"; + return classification; + } + + // Compilation phases + if (filename.contains("phases")) { + classification.category = "compilation-phases"; + classification.description = "Compilation phases"; + return classification; + } + + // Control flow graph + if (extension == ".dot" || filename.contains("cfg")) { + classification.category = "cfg"; + classification.description = "Control flow graph"; + return classification; + } + + // Template instantiation + if (filename.contains("template") || filename.contains("instantiation")) { + classification.category = "template-instantiation"; + classification.description = "Template instantiation"; + return classification; + } + + // Default for unknown files + classification.category = "unknown"; + classification.description = "Unknown file type"; + classification.isGenerated = false; + return classification; +} + +bool FileClassifier::shouldCollect(const std::string &filePath) const { + auto classification = classifyFile(filePath); + return classification.category != "unknown" && classification.isGenerated && + !classification.isTemporary; +} + +std::string FileClassifier::getLanguage(const std::string &filePath) const { + StringRef extension = sys::path::extension(filePath); + + if (extension == ".c") + return "C"; + if (extension == ".cpp" || extension == ".cc" || extension == ".cxx" || + extension == ".C") + return "C++"; + if (extension == ".h" || extension == ".hpp" || extension == ".hh" || + extension == ".hxx") + return "Header"; + + return "Unknown"; +} + +} // namespace advisor +} // namespace llvm diff --git a/llvm/tools/llvm-advisor/src/Utils/FileClassifier.h b/llvm/tools/llvm-advisor/src/Utils/FileClassifier.h new file mode 100644 index 0000000000000..6bf7c43ba4ffc --- /dev/null +++ b/llvm/tools/llvm-advisor/src/Utils/FileClassifier.h @@ -0,0 +1,26 @@ +#ifndef LLVM_ADVISOR_FILE_CLASSIFIER_H +#define LLVM_ADVISOR_FILE_CLASSIFIER_H + +#include + +namespace llvm { +namespace advisor { + +struct FileClassification { + std::string category; + std::string description; + bool isTemporary = false; + bool isGenerated = true; +}; + +class FileClassifier { +public: + FileClassification classifyFile(const std::string &filePath) const; + bool shouldCollect(const std::string &filePath) const; + std::string getLanguage(const std::string &filePath) const; +}; + +} // namespace advisor +} // namespace llvm + +#endif diff --git a/llvm/tools/llvm-advisor/src/Utils/FileManager.cpp b/llvm/tools/llvm-advisor/src/Utils/FileManager.cpp new file mode 100644 index 0000000000000..7083d7edb7f3d --- /dev/null +++ b/llvm/tools/llvm-advisor/src/Utils/FileManager.cpp @@ -0,0 +1,205 @@ +#include "FileManager.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" + +#include + +namespace llvm { +namespace advisor { + +Expected FileManager::createTempDir(const std::string &prefix) { + SmallString<128> tempDirPath; + if (std::error_code ec = + sys::fs::createUniqueDirectory(prefix, tempDirPath)) { + return createStringError(ec, "Failed to create unique temporary directory"); + } + return std::string(tempDirPath.str()); +} + +Error FileManager::copyDirectory(const std::string &source, + const std::string &dest) { + std::error_code EC; + + SmallString<128> sourcePathNorm(source); + // Remove trailing slash manually if present + if (sourcePathNorm.ends_with("/") && sourcePathNorm.size() > 1) { + sourcePathNorm.pop_back(); + } + + for (sys::fs::recursive_directory_iterator I(source, EC), E; I != E && !EC; + I.increment(EC)) { + StringRef currentPath = I->path(); + SmallString<128> destPath(dest); + + StringRef relativePath = currentPath; + if (!relativePath.consume_front(sourcePathNorm)) { + return createStringError( + std::make_error_code(std::errc::invalid_argument), + "Path '" + currentPath.str() + "' not in source dir '" + source + + "'"); + } + // Remove leading slash manually if present + if (relativePath.starts_with("/")) { + relativePath = relativePath.drop_front(1); + } + + sys::path::append(destPath, relativePath); + + if (sys::fs::is_directory(currentPath)) { + if (sys::fs::create_directories(destPath)) { + return createStringError(std::make_error_code(std::errc::io_error), + "Failed to create directory: " + + destPath.str().str()); + } + } else { + if (sys::fs::create_directories(sys::path::parent_path(destPath))) { + return createStringError(std::make_error_code(std::errc::io_error), + "Failed to create parent directory for: " + + destPath.str().str()); + } + if (sys::fs::copy_file(currentPath, destPath)) { + return createStringError(std::make_error_code(std::errc::io_error), + "Failed to copy file: " + currentPath.str()); + } + } + } + + if (EC) { + return createStringError(EC, "Failed to iterate directory: " + source); + } + + return Error::success(); +} + +Error FileManager::removeDirectory(const std::string &path) { + if (!sys::fs::exists(path)) { + return Error::success(); + } + + std::error_code EC; + std::vector Dirs; + for (sys::fs::recursive_directory_iterator I(path, EC), E; I != E && !EC; + I.increment(EC)) { + if (I->type() == sys::fs::file_type::directory_file) { + Dirs.push_back(I->path()); + } else { + if (auto E = sys::fs::remove(I->path())) { + return createStringError(E, "Failed to remove file: " + I->path()); + } + } + } + + if (EC) { + return createStringError(EC, "Error iterating directory " + path); + } + + for (const auto &Dir : llvm::reverse(Dirs)) { + if (auto E = sys::fs::remove(Dir)) { + return createStringError(E, "Failed to remove directory: " + Dir); + } + } + + if (auto E = sys::fs::remove(path)) { + return createStringError(E, + "Failed to remove top-level directory: " + path); + } + + return Error::success(); +} + +std::vector FileManager::findFiles(const std::string &directory, + const std::string &pattern) { + std::vector files; + std::error_code EC; + for (sys::fs::recursive_directory_iterator I(directory, EC), E; I != E && !EC; + I.increment(EC)) { + if (I->type() != sys::fs::file_type::directory_file) { + StringRef filename = sys::path::filename(I->path()); + if (filename.find(pattern) != StringRef::npos) { + files.push_back(I->path()); + } + } + } + return files; +} + +std::vector +FileManager::findFilesByExtension(const std::string &directory, + const std::vector &extensions) { + std::vector files; + std::error_code EC; + for (sys::fs::recursive_directory_iterator I(directory, EC), E; I != E && !EC; + I.increment(EC)) { + if (I->type() != sys::fs::file_type::directory_file) { + StringRef filepath = I->path(); + for (const auto &ext : extensions) { + if (filepath.ends_with(ext)) { + files.push_back(filepath.str()); + break; + } + } + } + } + return files; +} + +Error FileManager::moveFile(const std::string &source, + const std::string &dest) { + if (source == dest) { + return Error::success(); + } + + if (sys::fs::create_directories(sys::path::parent_path(dest))) { + return createStringError( + std::make_error_code(std::errc::io_error), + "Failed to create parent directory for destination: " + dest); + } + + if (sys::fs::rename(source, dest)) { + // If rename fails, try copy and remove + if (sys::fs::copy_file(source, dest)) { + return createStringError(std::make_error_code(std::errc::io_error), + "Failed to move file (copy failed): " + source); + } + if (sys::fs::remove(source)) { + return createStringError(std::make_error_code(std::errc::io_error), + "Failed to move file (source removal failed): " + + source); + } + } + + return Error::success(); +} + +Error FileManager::copyFile(const std::string &source, + const std::string &dest) { + if (source == dest) { + return Error::success(); + } + + if (sys::fs::create_directories(sys::path::parent_path(dest))) { + return createStringError( + std::make_error_code(std::errc::io_error), + "Failed to create parent directory for destination: " + dest); + } + + if (sys::fs::copy_file(source, dest)) { + return createStringError(std::make_error_code(std::errc::io_error), + "Failed to copy file: " + source); + } + + return Error::success(); +} + +Expected FileManager::getFileSize(const std::string &path) { + sys::fs::file_status status; + if (auto EC = sys::fs::status(path, status)) { + return createStringError(EC, "File not found: " + path); + } + + return status.getSize(); +} + +} // namespace advisor +} // namespace llvm \ No newline at end of file diff --git a/llvm/tools/llvm-advisor/src/Utils/FileManager.h b/llvm/tools/llvm-advisor/src/Utils/FileManager.h new file mode 100644 index 0000000000000..07b49e647f542 --- /dev/null +++ b/llvm/tools/llvm-advisor/src/Utils/FileManager.h @@ -0,0 +1,46 @@ +#ifndef LLVM_ADVISOR_FILE_MANAGER_H +#define LLVM_ADVISOR_FILE_MANAGER_H + +#include "llvm/Support/Error.h" +#include +#include + +namespace llvm { +namespace advisor { + +class FileManager { +public: + /// Create unique temporary directory with pattern llvm-advisor-xxxxx + static Expected + createTempDir(const std::string &prefix = "llvm-advisor"); + + /// Recursively copy directory + static Error copyDirectory(const std::string &source, + const std::string &dest); + + /// Remove directory and contents + static Error removeDirectory(const std::string &path); + + /// Find files matching pattern + static std::vector findFiles(const std::string &directory, + const std::string &pattern); + + /// Find files by extension + static std::vector + findFilesByExtension(const std::string &directory, + const std::vector &extensions); + + /// Move file from source to destination + static Error moveFile(const std::string &source, const std::string &dest); + + /// Copy file from source to destination + static Error copyFile(const std::string &source, const std::string &dest); + + /// Get file size + static Expected getFileSize(const std::string &path); +}; + +} // namespace advisor +} // namespace llvm + +#endif diff --git a/llvm/tools/llvm-advisor/src/Utils/ProcessRunner.cpp b/llvm/tools/llvm-advisor/src/Utils/ProcessRunner.cpp new file mode 100644 index 0000000000000..b08b3cc88a434 --- /dev/null +++ b/llvm/tools/llvm-advisor/src/Utils/ProcessRunner.cpp @@ -0,0 +1,69 @@ +#include "ProcessRunner.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Program.h" + +namespace llvm { +namespace advisor { + +Expected +ProcessRunner::run(const std::string &program, + const std::vector &args, int timeoutSeconds) { + + auto programPath = sys::findProgramByName(program); + if (!programPath) { + return createStringError(programPath.getError(), + "Tool not found: " + program); + } + + std::vector execArgs; + execArgs.push_back(program); + for (const auto &arg : args) { + execArgs.push_back(arg); + } + + SmallString<128> stdoutPath, stderrPath; + sys::fs::createTemporaryFile("stdout", "tmp", stdoutPath); + sys::fs::createTemporaryFile("stderr", "tmp", stderrPath); + + std::optional redirects[] = { + std::nullopt, // stdin + StringRef(stdoutPath), // stdout + StringRef(stderrPath) // stderr + }; + + int exitCode = sys::ExecuteAndWait(*programPath, execArgs, std::nullopt, + redirects, timeoutSeconds); + + ProcessResult result; + result.exitCode = exitCode; + // TODO: Collect information about compilation time + result.executionTime = 0; // not tracking time + + auto stdoutBuffer = MemoryBuffer::getFile(stdoutPath); + if (stdoutBuffer) { + result.stdout = (*stdoutBuffer)->getBuffer().str(); + } + + auto stderrBuffer = MemoryBuffer::getFile(stderrPath); + if (stderrBuffer) { + result.stderr = (*stderrBuffer)->getBuffer().str(); + } + + sys::fs::remove(stdoutPath); + sys::fs::remove(stderrPath); + + return result; +} + +Expected ProcessRunner::runWithEnv( + const std::string &program, const std::vector &args, + const std::vector &env, int timeoutSeconds) { + + // For simplicity, just use the regular run method + // Environment variables can be added later if needed + return run(program, args, timeoutSeconds); +} + +} // namespace advisor +} // namespace llvm diff --git a/llvm/tools/llvm-advisor/src/Utils/ProcessRunner.h b/llvm/tools/llvm-advisor/src/Utils/ProcessRunner.h new file mode 100644 index 0000000000000..ffd0ef353ba16 --- /dev/null +++ b/llvm/tools/llvm-advisor/src/Utils/ProcessRunner.h @@ -0,0 +1,32 @@ +#ifndef LLVM_ADVISOR_PROCESS_RUNNER_H +#define LLVM_ADVISOR_PROCESS_RUNNER_H + +#include "llvm/Support/Error.h" +#include +#include + +namespace llvm { +namespace advisor { + +class ProcessRunner { +public: + struct ProcessResult { + int exitCode; + std::string stdout; + std::string stderr; + double executionTime; + }; + + static Expected run(const std::string &program, + const std::vector &args, + int timeoutSeconds = 60); + + static Expected + runWithEnv(const std::string &program, const std::vector &args, + const std::vector &env, int timeoutSeconds = 60); +}; + +} // namespace advisor +} // namespace llvm + +#endif From 44997cad101961a716a4970471a573095543a724 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20C=C3=A1rdenas?= Date: Sun, 13 Jul 2025 06:09:39 +0200 Subject: [PATCH 03/10] [llvm-advisor] Add basic build/compilation data models Introduce data structures that represent a single build phase and compilation unit. --- .../llvm-advisor/src/Core/BuildContext.h | 52 +++++++++++++++ .../llvm-advisor/src/Core/CompilationUnit.cpp | 66 +++++++++++++++++++ .../llvm-advisor/src/Core/CompilationUnit.h | 58 ++++++++++++++++ 3 files changed, 176 insertions(+) create mode 100644 llvm/tools/llvm-advisor/src/Core/BuildContext.h create mode 100644 llvm/tools/llvm-advisor/src/Core/CompilationUnit.cpp create mode 100644 llvm/tools/llvm-advisor/src/Core/CompilationUnit.h diff --git a/llvm/tools/llvm-advisor/src/Core/BuildContext.h b/llvm/tools/llvm-advisor/src/Core/BuildContext.h new file mode 100644 index 0000000000000..4f40c37ca8706 --- /dev/null +++ b/llvm/tools/llvm-advisor/src/Core/BuildContext.h @@ -0,0 +1,52 @@ +#ifndef LLVM_ADVISOR_BUILD_CONTEXT_H +#define LLVM_ADVISOR_BUILD_CONTEXT_H + +#include +#include +#include + +namespace llvm { +namespace advisor { + +enum class BuildPhase { + Unknown, + Preprocessing, + Compilation, + Assembly, + Linking, + Archiving, + CMakeConfigure, + CMakeBuild, + MakefileBuild +}; + +enum class BuildTool { + Unknown, + Clang, + GCC, + LLVM_Tools, + CMake, + Make, + Ninja, + Linker, + Archiver +}; + +struct BuildContext { + BuildPhase phase; + BuildTool tool; + std::string workingDirectory; + std::string outputDirectory; + std::vector inputFiles; + std::vector outputFiles; + std::vector expectedGeneratedFiles; + std::map metadata; + bool hasOffloading = false; + bool hasDebugInfo = false; + bool hasOptimization = false; +}; + +} // namespace advisor +} // namespace llvm + +#endif diff --git a/llvm/tools/llvm-advisor/src/Core/CompilationUnit.cpp b/llvm/tools/llvm-advisor/src/Core/CompilationUnit.cpp new file mode 100644 index 0000000000000..8b6a478cfaf63 --- /dev/null +++ b/llvm/tools/llvm-advisor/src/Core/CompilationUnit.cpp @@ -0,0 +1,66 @@ +#include "CompilationUnit.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" + +namespace llvm { +namespace advisor { + +CompilationUnit::CompilationUnit(const CompilationUnitInfo &info, + const std::string &workDir) + : info_(info), workDir_(workDir) { + // Create unit-specific data directory + SmallString<128> dataDir; + sys::path::append(dataDir, workDir, "units", info.name); + sys::fs::create_directories(dataDir); +} + +std::string CompilationUnit::getPrimarySource() const { + if (info_.sources.empty()) { + return ""; + } + return info_.sources[0].path; +} + +std::string CompilationUnit::getDataDir() const { + SmallString<128> dataDir; + sys::path::append(dataDir, workDir_, "units", info_.name); + return dataDir.str().str(); +} + +std::string CompilationUnit::getExecutablePath() const { + return info_.outputExecutable; +} + +void CompilationUnit::addGeneratedFile(const std::string &type, + const std::string &path) { + generatedFiles_[type].push_back(path); +} + +bool CompilationUnit::hasGeneratedFiles(const std::string &type) const { + if (type.empty()) { + return !generatedFiles_.empty(); + } + auto it = generatedFiles_.find(type); + return it != generatedFiles_.end() && !it->second.empty(); +} + +std::vector +CompilationUnit::getGeneratedFiles(const std::string &type) const { + if (type.empty()) { + std::vector allFiles; + for (const auto &pair : generatedFiles_) { + allFiles.insert(allFiles.end(), pair.second.begin(), pair.second.end()); + } + return allFiles; + } + auto it = generatedFiles_.find(type); + return it != generatedFiles_.end() ? it->second : std::vector(); +} + +const std::unordered_map> & +CompilationUnit::getAllGeneratedFiles() const { + return generatedFiles_; +} + +} // namespace advisor +} // namespace llvm \ No newline at end of file diff --git a/llvm/tools/llvm-advisor/src/Core/CompilationUnit.h b/llvm/tools/llvm-advisor/src/Core/CompilationUnit.h new file mode 100644 index 0000000000000..18dbc35ab5aec --- /dev/null +++ b/llvm/tools/llvm-advisor/src/Core/CompilationUnit.h @@ -0,0 +1,58 @@ +#ifndef LLVM_ADVISOR_COMPILATION_UNIT_H +#define LLVM_ADVISOR_COMPILATION_UNIT_H + +#include "llvm/Support/Error.h" +#include +#include +#include + +namespace llvm { +namespace advisor { + +struct SourceFile { + std::string path; + std::string language; + bool isHeader = false; + std::vector dependencies; +}; + +struct CompilationUnitInfo { + std::string name; + std::vector sources; + std::vector compileFlags; + std::string targetArch; + bool hasOffloading = false; + std::string outputObject; + std::string outputExecutable; +}; + +class CompilationUnit { +public: + CompilationUnit(const CompilationUnitInfo &info, const std::string &workDir); + + const std::string &getName() const { return info_.name; } + const CompilationUnitInfo &getInfo() const { return info_; } + const std::string &getWorkDir() const { return workDir_; } + std::string getPrimarySource() const; + + std::string getDataDir() const; + std::string getExecutablePath() const; + + void addGeneratedFile(const std::string &type, const std::string &path); + + bool hasGeneratedFiles(const std::string &type) const; + std::vector + getGeneratedFiles(const std::string &type = "") const; + const std::unordered_map> & + getAllGeneratedFiles() const; + +private: + CompilationUnitInfo info_; + std::string workDir_; + std::unordered_map> generatedFiles_; +}; + +} // namespace advisor +} // namespace llvm + +#endif \ No newline at end of file From 047afa06749d61bb042639440ac16ec26cfb8523 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20C=C3=A1rdenas?= Date: Sun, 13 Jul 2025 06:18:52 +0200 Subject: [PATCH 04/10] [llvm-advisor] Add command analyzer helper CommandAnalyzer inspects an incoming compiler or build-system invocation and classifies the tool in use, the build phase, input/output files and notable flags. --- .../llvm-advisor/src/Core/CommandAnalyzer.cpp | 167 ++++++++++++++++++ .../llvm-advisor/src/Core/CommandAnalyzer.h | 32 ++++ 2 files changed, 199 insertions(+) create mode 100644 llvm/tools/llvm-advisor/src/Core/CommandAnalyzer.cpp create mode 100644 llvm/tools/llvm-advisor/src/Core/CommandAnalyzer.h diff --git a/llvm/tools/llvm-advisor/src/Core/CommandAnalyzer.cpp b/llvm/tools/llvm-advisor/src/Core/CommandAnalyzer.cpp new file mode 100644 index 0000000000000..3192c42669e65 --- /dev/null +++ b/llvm/tools/llvm-advisor/src/Core/CommandAnalyzer.cpp @@ -0,0 +1,167 @@ +#include "CommandAnalyzer.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" + +namespace llvm { +namespace advisor { + +CommandAnalyzer::CommandAnalyzer(const std::string &command, + const std::vector &args) + : command_(command), args_(args) {} + +BuildContext CommandAnalyzer::analyze() const { + BuildContext context; + SmallString<256> cwd; + sys::fs::current_path(cwd); + context.workingDirectory = cwd.str().str(); + + context.tool = detectBuildTool(); + context.phase = detectBuildPhase(context.tool); + context.inputFiles = extractInputFiles(); + context.outputFiles = extractOutputFiles(); + detectBuildFeatures(context); + + return context; +} + +BuildTool CommandAnalyzer::detectBuildTool() const { + return StringSwitch(sys::path::filename(command_)) + .StartsWith("clang", BuildTool::Clang) + .StartsWith("gcc", BuildTool::GCC) + .StartsWith("g++", BuildTool::GCC) + .Case("cmake", BuildTool::CMake) + .Case("make", BuildTool::Make) + .Case("ninja", BuildTool::Ninja) + .EndsWith("-ld", BuildTool::Linker) + .Case("ld", BuildTool::Linker) + .Case("ar", BuildTool::Archiver) + .Case("llvm-ar", BuildTool::Archiver) + .StartsWith("llvm-", BuildTool::LLVM_Tools) + .Default(BuildTool::Unknown); +} + +BuildPhase CommandAnalyzer::detectBuildPhase(BuildTool tool) const { + if (tool == BuildTool::CMake) { + for (const auto &arg : args_) { + if (arg == "--build") + return BuildPhase::CMakeBuild; + } + return BuildPhase::CMakeConfigure; + } + + if (tool == BuildTool::Make || tool == BuildTool::Ninja) { + return BuildPhase::MakefileBuild; + } + + if (tool == BuildTool::Linker) { + return BuildPhase::Linking; + } + + if (tool == BuildTool::Archiver) { + return BuildPhase::Archiving; + } + + if (tool == BuildTool::Clang || tool == BuildTool::GCC) { + for (const auto &arg : args_) { + if (arg == "-E") + return BuildPhase::Preprocessing; + if (arg == "-S") + return BuildPhase::Assembly; + if (arg == "-c") + return BuildPhase::Compilation; + } + + bool hasObjectFile = false; + for (const auto &Arg : args_) { + StringRef argRef(Arg); + if (argRef.ends_with(".o") || argRef.ends_with(".O") || + argRef.ends_with(".obj") || argRef.ends_with(".OBJ")) { + hasObjectFile = true; + break; + } + } + if (hasObjectFile) { + return BuildPhase::Linking; + } + + bool hasSourceFile = false; + for (const auto &Arg : args_) { + StringRef argRef(Arg); + if (argRef.ends_with(".c") || argRef.ends_with(".C") || + argRef.ends_with(".cpp") || argRef.ends_with(".CPP") || + argRef.ends_with(".cc") || argRef.ends_with(".CC") || + argRef.ends_with(".cxx") || argRef.ends_with(".CXX")) { + hasSourceFile = true; + break; + } + } + if (hasSourceFile) { + return BuildPhase::Compilation; // Default for source files + } + } + + return BuildPhase::Unknown; +} + +void CommandAnalyzer::detectBuildFeatures(BuildContext &context) const { + for (const auto &arg : args_) { + if (arg == "-g" || StringRef(arg).starts_with("-g")) { + context.hasDebugInfo = true; + } + + if (StringRef(arg).starts_with("-O") && arg.length() > 2) { + context.hasOptimization = true; + } + + if (arg.find("openmp") != std::string::npos || + arg.find("openacc") != std::string::npos || + arg.find("cuda") != std::string::npos || + arg.find("offload") != std::string::npos) { + context.hasOffloading = true; + } + + if (StringRef(arg).starts_with("-march=")) { + context.metadata["target_arch"] = arg.substr(7); + } + if (StringRef(arg).starts_with("-mtune=")) { + context.metadata["tune"] = arg.substr(7); + } + if (StringRef(arg).starts_with("--offload-arch=")) { + context.metadata["offload_arch"] = arg.substr(15); + } + } +} + +std::vector CommandAnalyzer::extractInputFiles() const { + std::vector inputs; + for (size_t i = 0; i < args_.size(); ++i) { + const auto &arg = args_[i]; + if (StringRef(arg).starts_with("-")) { + if (arg == "-o" || arg == "-I" || arg == "-L" || arg == "-D") { + i++; + } + continue; + } + if (sys::fs::exists(arg)) { + inputs.push_back(arg); + } + } + return inputs; +} + +std::vector CommandAnalyzer::extractOutputFiles() const { + std::vector outputs; + for (size_t i = 0; i < args_.size(); ++i) { + const auto &arg = args_[i]; + if (arg == "-o" && i + 1 < args_.size()) { + outputs.push_back(args_[i + 1]); + i++; + } + } + return outputs; +} + +} // namespace advisor +} // namespace llvm diff --git a/llvm/tools/llvm-advisor/src/Core/CommandAnalyzer.h b/llvm/tools/llvm-advisor/src/Core/CommandAnalyzer.h new file mode 100644 index 0000000000000..c3efdff147e5f --- /dev/null +++ b/llvm/tools/llvm-advisor/src/Core/CommandAnalyzer.h @@ -0,0 +1,32 @@ +#ifndef LLVM_ADVISOR_COMMAND_ANALYZER_H +#define LLVM_ADVISOR_COMMAND_ANALYZER_H + +#include "BuildContext.h" +#include +#include + +namespace llvm { +namespace advisor { + +class CommandAnalyzer { +public: + CommandAnalyzer(const std::string &command, + const std::vector &args); + + BuildContext analyze() const; + +private: + BuildTool detectBuildTool() const; + BuildPhase detectBuildPhase(BuildTool tool) const; + void detectBuildFeatures(BuildContext &context) const; + std::vector extractInputFiles() const; + std::vector extractOutputFiles() const; + + std::string command_; + std::vector args_; +}; + +} // namespace advisor +} // namespace llvm + +#endif From 2bcbceea50849d0e1a9550d0af81f8780dcb805a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20C=C3=A1rdenas?= Date: Sun, 13 Jul 2025 06:24:53 +0200 Subject: [PATCH 05/10] [llvm-advisor] Add support for builds with extra compiler data This change adds logic to run compiler processes and automatically add options to collect optimization remarks, profiling data, and debug information when needed. --- .../llvm-advisor/src/Core/BuildExecutor.cpp | 109 ++++++++++++++++++ .../llvm-advisor/src/Core/BuildExecutor.h | 34 ++++++ 2 files changed, 143 insertions(+) create mode 100644 llvm/tools/llvm-advisor/src/Core/BuildExecutor.cpp create mode 100644 llvm/tools/llvm-advisor/src/Core/BuildExecutor.h diff --git a/llvm/tools/llvm-advisor/src/Core/BuildExecutor.cpp b/llvm/tools/llvm-advisor/src/Core/BuildExecutor.cpp new file mode 100644 index 0000000000000..a4af5a660c80e --- /dev/null +++ b/llvm/tools/llvm-advisor/src/Core/BuildExecutor.cpp @@ -0,0 +1,109 @@ +#include "BuildExecutor.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Program.h" +#include "llvm/Support/raw_ostream.h" + +namespace llvm { +namespace advisor { + +BuildExecutor::BuildExecutor(const AdvisorConfig &config) : config_(config) {} + +Expected BuildExecutor::execute(const std::string &compiler, + const std::vector &args, + BuildContext &buildContext, + const std::string &tempDir) { + auto instrumentedArgs = instrumentCompilerArgs(args, buildContext, tempDir); + + auto compilerPath = sys::findProgramByName(compiler); + if (!compilerPath) { + return createStringError( + std::make_error_code(std::errc::no_such_file_or_directory), + "Compiler not found: " + compiler); + } + + std::vector execArgs; + execArgs.push_back(compiler); + for (const auto &arg : instrumentedArgs) { + execArgs.push_back(arg); + } + + if (config_.getVerbose()) { + outs() << "Executing: " << compiler; + for (const auto &arg : instrumentedArgs) { + outs() << " " << arg; + } + outs() << "\n"; + } + + return sys::ExecuteAndWait(*compilerPath, execArgs); +} + +std::vector +BuildExecutor::instrumentCompilerArgs(const std::vector &args, + BuildContext &buildContext, + const std::string &tempDir) { + + std::vector result = args; + std::set existingFlags; + + // Scan existing flags to avoid duplication + for (const auto &arg : args) { + if (arg.find("-g") == 0) + existingFlags.insert("debug"); + if (arg.find("-fsave-optimization-record") != std::string::npos) + existingFlags.insert("remarks"); + if (arg.find("-fprofile-instr-generate") != std::string::npos) + existingFlags.insert("profile"); + } + + // Add debug info if not present + if (existingFlags.find("debug") == existingFlags.end()) { + result.push_back("-g"); + } + + // Add optimization remarks with proper redirection + if (existingFlags.find("remarks") == existingFlags.end()) { + result.push_back("-fsave-optimization-record"); + result.push_back("-foptimization-record-file=" + tempDir + + "/remarks.opt.yaml"); + buildContext.expectedGeneratedFiles.push_back(tempDir + + "/remarks.opt.yaml"); + } else { + // If user already specified remarks, find and redirect the file + bool foundFileFlag = false; + for (auto &arg : result) { + if (arg.find("-foptimization-record-file=") != std::string::npos) { + // Extract filename and redirect to temp + StringRef existingPath = StringRef(arg).substr(26); + StringRef filename = sys::path::filename(existingPath); + arg = "-foptimization-record-file=" + tempDir + "/" + filename.str(); + buildContext.expectedGeneratedFiles.push_back(tempDir + "/" + + filename.str()); + foundFileFlag = true; + break; + } + } + // If no explicit file specified, add our own + if (!foundFileFlag) { + result.push_back("-foptimization-record-file=" + tempDir + + "/remarks.opt.yaml"); + buildContext.expectedGeneratedFiles.push_back(tempDir + + "/remarks.opt.yaml"); + } + } + + // Add profiling if enabled and not present, redirect to temp directory + if (config_.getRunProfiler() && + existingFlags.find("profile") == existingFlags.end()) { + result.push_back("-fprofile-instr-generate=" + tempDir + + "/profile.profraw"); + result.push_back("-fcoverage-mapping"); + buildContext.expectedGeneratedFiles.push_back(tempDir + "/profile.profraw"); + } + + return result; +} + +} // namespace advisor +} // namespace llvm diff --git a/llvm/tools/llvm-advisor/src/Core/BuildExecutor.h b/llvm/tools/llvm-advisor/src/Core/BuildExecutor.h new file mode 100644 index 0000000000000..a77ffd70c9b57 --- /dev/null +++ b/llvm/tools/llvm-advisor/src/Core/BuildExecutor.h @@ -0,0 +1,34 @@ +#ifndef LLVM_ADVISOR_BUILD_EXECUTOR_H +#define LLVM_ADVISOR_BUILD_EXECUTOR_H + +#include "../Config/AdvisorConfig.h" +#include "BuildContext.h" +#include "llvm/Support/Error.h" +#include +#include +#include + +namespace llvm { +namespace advisor { + +class BuildExecutor { +public: + BuildExecutor(const AdvisorConfig &config); + + Expected execute(const std::string &compiler, + const std::vector &args, + BuildContext &buildContext, const std::string &tempDir); + +private: + std::vector + instrumentCompilerArgs(const std::vector &args, + BuildContext &buildContext, + const std::string &tempDir); + + const AdvisorConfig &config_; +}; + +} // namespace advisor +} // namespace llvm + +#endif From 00c1ad337dd0f6566daac9c7c0438a0bd52b1c5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20C=C3=A1rdenas?= Date: Sun, 13 Jul 2025 06:34:37 +0200 Subject: [PATCH 06/10] [llvm-advisor] Add build coordinator support This change adds logic to manage builds end to end. It runs the build process, calls the detector, extracts data, and moves generated files to the output directory. --- .../src/Core/CompilationManager.cpp | 257 ++++++++++++++++++ .../src/Core/CompilationManager.h | 45 +++ 2 files changed, 302 insertions(+) create mode 100644 llvm/tools/llvm-advisor/src/Core/CompilationManager.cpp create mode 100644 llvm/tools/llvm-advisor/src/Core/CompilationManager.h diff --git a/llvm/tools/llvm-advisor/src/Core/CompilationManager.cpp b/llvm/tools/llvm-advisor/src/Core/CompilationManager.cpp new file mode 100644 index 0000000000000..e07db9d365009 --- /dev/null +++ b/llvm/tools/llvm-advisor/src/Core/CompilationManager.cpp @@ -0,0 +1,257 @@ +#include "CompilationManager.h" +#include "../Detection/UnitDetector.h" +#include "../Utils/FileManager.h" +#include "CommandAnalyzer.h" +#include "DataExtractor.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include +#include +#include + +namespace llvm { +namespace advisor { + +CompilationManager::CompilationManager(const AdvisorConfig &config) + : config_(config), buildExecutor_(config) { + + // Get current working directory first + SmallString<256> currentDir; + sys::fs::current_path(currentDir); + initialWorkingDir_ = currentDir.str().str(); + + // Create temp directory with proper error handling + SmallString<128> tempDirPath; + if (auto EC = sys::fs::createUniqueDirectory("llvm-advisor", tempDirPath)) { + // Use timestamp for temp folder naming + auto now = std::chrono::system_clock::now(); + auto timestamp = + std::chrono::duration_cast(now.time_since_epoch()) + .count(); + tempDir_ = "/tmp/llvm-advisor-" + std::to_string(timestamp); + sys::fs::create_directories(tempDir_); + } else { + tempDir_ = tempDirPath.str().str(); + } + + // Ensure the directory actually exists + if (!sys::fs::exists(tempDir_)) { + sys::fs::create_directories(tempDir_); + } + + if (config_.getVerbose()) { + outs() << "Using temporary directory: " << tempDir_ << "\n"; + } +} + +CompilationManager::~CompilationManager() { + if (!config_.getKeepTemps() && sys::fs::exists(tempDir_)) { + sys::fs::remove_directories(tempDir_); + } +} + +Expected CompilationManager::executeWithDataCollection( + const std::string &compiler, const std::vector &args) { + + // Analyze the build command + BuildContext buildContext = CommandAnalyzer(compiler, args).analyze(); + + if (config_.getVerbose()) { + outs() << "Build phase: " << static_cast(buildContext.phase) << "\n"; + } + + // Skip data collection for linking/archiving phases + if (buildContext.phase == BuildPhase::Linking || + buildContext.phase == BuildPhase::Archiving) { + return buildExecutor_.execute(compiler, args, buildContext, tempDir_); + } + + // Detect compilation units + UnitDetector detector(config_); + auto detectedUnits = detector.detectUnits(compiler, args); + if (!detectedUnits) { + return detectedUnits.takeError(); + } + + std::vector> units; + for (auto &unitInfo : *detectedUnits) { + units.push_back(std::make_unique(unitInfo, tempDir_)); + } + + // Scan existing files before compilation + auto existingFiles = scanDirectory(initialWorkingDir_); + + // Execute compilation with instrumentation + auto execResult = + buildExecutor_.execute(compiler, args, buildContext, tempDir_); + if (!execResult) { + return execResult; + } + int exitCode = *execResult; + + // Collect generated files (even if compilation failed for analysis) + collectGeneratedFiles(existingFiles, units); + + // Extract additional data + DataExtractor extractor(config_); + for (auto &unit : units) { + if (auto Err = extractor.extractAllData(*unit, tempDir_)) { + if (config_.getVerbose()) { + errs() << "Data extraction failed: " << toString(std::move(Err)) + << "\n"; + } + } + } + + // Organize output + if (auto Err = organizeOutput(units)) { + if (config_.getVerbose()) { + errs() << "Output organization failed: " << toString(std::move(Err)) + << "\n"; + } + } + + // Clean up leaked files from source directory + cleanupLeakedFiles(); + + return exitCode; +} + +std::set +CompilationManager::scanDirectory(const std::string &dir) const { + std::set files; + std::error_code EC; + for (sys::fs::directory_iterator DI(dir, EC), DE; DI != DE && !EC; + DI.increment(EC)) { + if (DI->type() != sys::fs::file_type::directory_file) { + files.insert(DI->path()); + } + } + return files; +} + +void CompilationManager::collectGeneratedFiles( + const std::set &existingFiles, + std::vector> &units) { + FileClassifier classifier; + + // Collect files from temp directory + std::error_code EC; + for (sys::fs::recursive_directory_iterator DI(tempDir_, EC), DE; + DI != DE && !EC; DI.increment(EC)) { + if (DI->type() != sys::fs::file_type::directory_file) { + std::string filePath = DI->path(); + if (classifier.shouldCollect(filePath)) { + auto classification = classifier.classifyFile(filePath); + + // Add to appropriate unit + if (!units.empty()) { + units[0]->addGeneratedFile(classification.category, filePath); + } + } + } + } + + // Also check for files that leaked into source directory + auto currentFiles = scanDirectory(initialWorkingDir_); + for (const auto &file : currentFiles) { + if (existingFiles.find(file) == existingFiles.end()) { + if (classifier.shouldCollect(file)) { + auto classification = classifier.classifyFile(file); + + // Move leaked file to temp directory + std::string destPath = tempDir_ + "/" + sys::path::filename(file).str(); + if (!FileManager::moveFile(file, destPath)) { + if (!units.empty()) { + units[0]->addGeneratedFile(classification.category, destPath); + } + } + } + } + } +} + +Error CompilationManager::organizeOutput( + const std::vector> &units) { + // Resolve output directory as absolute path from initial working directory + SmallString<256> outputDirPath; + if (sys::path::is_absolute(config_.getOutputDir())) { + outputDirPath = config_.getOutputDir(); + } else { + outputDirPath = initialWorkingDir_; + sys::path::append(outputDirPath, config_.getOutputDir()); + } + + std::string outputDir = outputDirPath.str().str(); + + if (config_.getVerbose()) { + outs() << "Output directory: " << outputDir << "\n"; + } + + // Move collected files to organized structure + for (const auto &unit : units) { + std::string unitDir = outputDir + "/" + unit->getName(); + + // Remove existing unit directory if it exists + if (sys::fs::exists(unitDir)) { + if (auto EC = sys::fs::remove_directories(unitDir)) { + if (config_.getVerbose()) { + errs() << "Warning: Could not remove existing unit directory: " + << unitDir << "\n"; + } + } + } + + // Create fresh unit directory + if (auto EC = sys::fs::create_directories(unitDir)) { + continue; // Skip if we can't create the directory + } + + const auto &generatedFiles = unit->getAllGeneratedFiles(); + for (const auto &category : generatedFiles) { + std::string categoryDir = unitDir + "/" + category.first; + sys::fs::create_directories(categoryDir); + + for (const auto &file : category.second) { + std::string destFile = + categoryDir + "/" + sys::path::filename(file).str(); + if (auto Err = FileManager::copyFile(file, destFile)) { + if (config_.getVerbose()) { + errs() << "Failed to copy " << file << " to " << destFile << "\n"; + } + } + } + } + } + + return Error::success(); +} + +void CompilationManager::cleanupLeakedFiles() { + FileClassifier classifier; + + // Clean up any remaining leaked files in source directory + auto currentFiles = scanDirectory(initialWorkingDir_); + for (const auto &file : currentFiles) { + StringRef filename = sys::path::filename(file); + + // Remove optimization remarks files that leaked + if (filename.ends_with(".opt.yaml") || filename.ends_with(".opt.yml")) { + sys::fs::remove(file); + if (config_.getVerbose()) { + outs() << "Cleaned up leaked file: " << file << "\n"; + } + } + + // Remove profile files that leaked + if (filename.ends_with(".profraw") || filename.ends_with(".profdata")) { + sys::fs::remove(file); + if (config_.getVerbose()) { + outs() << "Cleaned up leaked file: " << file << "\n"; + } + } + } +} + +} // namespace advisor +} // namespace llvm diff --git a/llvm/tools/llvm-advisor/src/Core/CompilationManager.h b/llvm/tools/llvm-advisor/src/Core/CompilationManager.h new file mode 100644 index 0000000000000..5256042a8c464 --- /dev/null +++ b/llvm/tools/llvm-advisor/src/Core/CompilationManager.h @@ -0,0 +1,45 @@ +#ifndef LLVM_ADVISOR_COMPILATION_MANAGER_H +#define LLVM_ADVISOR_COMPILATION_MANAGER_H + +#include "../Config/AdvisorConfig.h" +#include "../Utils/FileClassifier.h" +#include "BuildExecutor.h" +#include "CompilationUnit.h" +#include "llvm/Support/Error.h" +#include +#include +#include + +namespace llvm { +namespace advisor { + +class CompilationManager { +public: + explicit CompilationManager(const AdvisorConfig &config); + ~CompilationManager(); + + Expected executeWithDataCollection(const std::string &compiler, + const std::vector &args); + +private: + std::set scanDirectory(const std::string &dir) const; + + void + collectGeneratedFiles(const std::set &existingFiles, + std::vector> &units); + + Error + organizeOutput(const std::vector> &units); + + void cleanupLeakedFiles(); + + const AdvisorConfig &config_; + BuildExecutor buildExecutor_; + std::string tempDir_; + std::string initialWorkingDir_; +}; + +} // namespace advisor +} // namespace llvm + +#endif From ed61ffd6e95681aa7b1f0e45b1d6acc9a48d73b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20C=C3=A1rdenas?= Date: Sun, 13 Jul 2025 06:38:54 +0200 Subject: [PATCH 07/10] [llvm-advisor] Add support for collecting extra build outputs Adds helpers to run the compilation with extra flags to collect IR, assembly, AST dumps, include trees, debug info, and other data. --- .../llvm-advisor/src/Core/DataExtractor.cpp | 367 ++++++++++++++++++ .../llvm-advisor/src/Core/DataExtractor.h | 44 +++ 2 files changed, 411 insertions(+) create mode 100644 llvm/tools/llvm-advisor/src/Core/DataExtractor.cpp create mode 100644 llvm/tools/llvm-advisor/src/Core/DataExtractor.h diff --git a/llvm/tools/llvm-advisor/src/Core/DataExtractor.cpp b/llvm/tools/llvm-advisor/src/Core/DataExtractor.cpp new file mode 100644 index 0000000000000..4d709e4a6d51c --- /dev/null +++ b/llvm/tools/llvm-advisor/src/Core/DataExtractor.cpp @@ -0,0 +1,367 @@ +#include "DataExtractor.h" +#include "../Utils/ProcessRunner.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" +#include + +namespace llvm { +namespace advisor { + +DataExtractor::DataExtractor(const AdvisorConfig &config) : config_(config) {} + +Error DataExtractor::extractAllData(CompilationUnit &unit, + const std::string &tempDir) { + if (config_.getVerbose()) { + outs() << "Extracting data for unit: " << unit.getName() << "\n"; + } + + // Create extraction subdirectories + sys::fs::create_directories(tempDir + "/ir"); + sys::fs::create_directories(tempDir + "/assembly"); + sys::fs::create_directories(tempDir + "/ast"); + sys::fs::create_directories(tempDir + "/preprocessed"); + sys::fs::create_directories(tempDir + "/include-tree"); + sys::fs::create_directories(tempDir + "/debug"); + sys::fs::create_directories(tempDir + "/static-analyzer"); + + if (auto Err = extractIR(unit, tempDir)) + return Err; + if (auto Err = extractAssembly(unit, tempDir)) + return Err; + if (auto Err = extractAST(unit, tempDir)) + return Err; + if (auto Err = extractPreprocessed(unit, tempDir)) + return Err; + if (auto Err = extractIncludeTree(unit, tempDir)) + return Err; + if (auto Err = extractDebugInfo(unit, tempDir)) + return Err; + if (auto Err = extractStaticAnalysis(unit, tempDir)) + return Err; + if (auto Err = extractMacroExpansion(unit, tempDir)) + return Err; + if (auto Err = extractCompilationPhases(unit, tempDir)) + return Err; + + return Error::success(); +} + +std::vector +DataExtractor::getBaseCompilerArgs(const CompilationUnitInfo &unitInfo) const { + std::vector baseArgs; + + // Copy include paths and defines + for (const auto &arg : unitInfo.compileFlags) { + if (StringRef(arg).starts_with("-I") || StringRef(arg).starts_with("-D") || + StringRef(arg).starts_with("-U") || + StringRef(arg).starts_with("-std=") || + StringRef(arg).starts_with("-m") || StringRef(arg).starts_with("-f") || + StringRef(arg).starts_with("-W") || StringRef(arg).starts_with("-O")) { + // Skip problematic flags for extraction + if (StringRef(arg).starts_with("-fsave-optimization-record") || + StringRef(arg).starts_with("-fprofile-instr-generate") || + StringRef(arg).starts_with("-fcoverage-mapping") || + StringRef(arg).starts_with("-foptimization-record-file")) { + continue; + } + baseArgs.push_back(arg); + } + } + + return baseArgs; +} + +Error DataExtractor::extractIR(CompilationUnit &unit, + const std::string &tempDir) { + for (const auto &source : unit.getInfo().sources) { + if (source.isHeader) + continue; + + std::string outputFile = + tempDir + "/ir/" + sys::path::stem(source.path).str() + ".ll"; + + auto baseArgs = getBaseCompilerArgs(unit.getInfo()); + baseArgs.push_back("-emit-llvm"); + baseArgs.push_back("-S"); + baseArgs.push_back("-o"); + baseArgs.push_back(outputFile); + baseArgs.push_back(source.path); + + if (auto Err = runCompilerWithFlags(baseArgs)) { + if (config_.getVerbose()) { + errs() << "Failed to extract IR for " << source.path << "\n"; + } + continue; + } + + if (sys::fs::exists(outputFile)) { + unit.addGeneratedFile("ir", outputFile); + } + } + return Error::success(); +} + +Error DataExtractor::extractAssembly(CompilationUnit &unit, + const std::string &tempDir) { + for (const auto &source : unit.getInfo().sources) { + if (source.isHeader) + continue; + + std::string outputFile = + tempDir + "/assembly/" + sys::path::stem(source.path).str() + ".s"; + + auto baseArgs = getBaseCompilerArgs(unit.getInfo()); + baseArgs.push_back("-S"); + baseArgs.push_back("-o"); + baseArgs.push_back(outputFile); + baseArgs.push_back(source.path); + + if (auto Err = runCompilerWithFlags(baseArgs)) { + if (config_.getVerbose()) { + errs() << "Failed to extract assembly for " << source.path << "\n"; + } + continue; + } + + if (sys::fs::exists(outputFile)) { + unit.addGeneratedFile("assembly", outputFile); + } + } + return Error::success(); +} + +Error DataExtractor::extractAST(CompilationUnit &unit, + const std::string &tempDir) { + for (const auto &source : unit.getInfo().sources) { + if (source.isHeader) + continue; + + std::string outputFile = + tempDir + "/ast/" + sys::path::stem(source.path).str() + ".ast"; + + auto baseArgs = getBaseCompilerArgs(unit.getInfo()); + baseArgs.push_back("-ast-dump"); + baseArgs.push_back("-fsyntax-only"); + baseArgs.push_back(source.path); + + auto result = ProcessRunner::run(config_.getToolPath("clang"), baseArgs, + config_.getTimeout()); + if (result && result->exitCode == 0) { + std::error_code EC; + raw_fd_ostream OS(outputFile, EC); + if (!EC) { + OS << result->stdout; + unit.addGeneratedFile("ast", outputFile); + } + } + } + return Error::success(); +} + +Error DataExtractor::extractPreprocessed(CompilationUnit &unit, + const std::string &tempDir) { + for (const auto &source : unit.getInfo().sources) { + if (source.isHeader) + continue; + + std::string ext = (source.language == "C++") ? ".ii" : ".i"; + std::string outputFile = + tempDir + "/preprocessed/" + sys::path::stem(source.path).str() + ext; + + auto baseArgs = getBaseCompilerArgs(unit.getInfo()); + baseArgs.push_back("-E"); + baseArgs.push_back("-o"); + baseArgs.push_back(outputFile); + baseArgs.push_back(source.path); + + if (auto Err = runCompilerWithFlags(baseArgs)) { + if (config_.getVerbose()) { + errs() << "Failed to extract preprocessed for " << source.path << "\n"; + } + continue; + } + + if (sys::fs::exists(outputFile)) { + unit.addGeneratedFile("preprocessed", outputFile); + } + } + return Error::success(); +} + +Error DataExtractor::extractIncludeTree(CompilationUnit &unit, + const std::string &tempDir) { + for (const auto &source : unit.getInfo().sources) { + if (source.isHeader) + continue; + + std::string outputFile = tempDir + "/include-tree/" + + sys::path::stem(source.path).str() + + ".include.txt"; + + auto baseArgs = getBaseCompilerArgs(unit.getInfo()); + baseArgs.push_back("-H"); + baseArgs.push_back("-fsyntax-only"); + baseArgs.push_back(source.path); + + auto result = ProcessRunner::run(config_.getToolPath("clang"), baseArgs, + config_.getTimeout()); + if (result && !result->stderr.empty()) { + std::error_code EC; + raw_fd_ostream OS(outputFile, EC); + if (!EC) { + OS << result->stderr; // Include tree goes to stderr + unit.addGeneratedFile("include-tree", outputFile); + } + } + } + return Error::success(); +} + +Error DataExtractor::extractDebugInfo(CompilationUnit &unit, + const std::string &tempDir) { + for (const auto &source : unit.getInfo().sources) { + if (source.isHeader) + continue; + + std::string outputFile = + tempDir + "/debug/" + sys::path::stem(source.path).str() + ".debug.txt"; + std::string objectFile = + tempDir + "/debug/" + sys::path::stem(source.path).str() + ".o"; + + auto baseArgs = getBaseCompilerArgs(unit.getInfo()); + baseArgs.push_back("-g"); + baseArgs.push_back("-c"); + baseArgs.push_back("-o"); + baseArgs.push_back(objectFile); + baseArgs.push_back(source.path); + + if (auto Err = runCompilerWithFlags(baseArgs)) { + if (config_.getVerbose()) { + errs() << "Failed to extract debug info for " << source.path << "\n"; + } + continue; + } + + // Extract DWARF info using llvm-dwarfdump + if (sys::fs::exists(objectFile)) { + std::vector dwarfArgs = {objectFile}; + auto result = + ProcessRunner::run("llvm-dwarfdump", dwarfArgs, config_.getTimeout()); + if (result && result->exitCode == 0) { + std::error_code EC; + raw_fd_ostream OS(outputFile, EC); + if (!EC) { + OS << result->stdout; + unit.addGeneratedFile("debug", outputFile); + } + } + } + } + return Error::success(); +} + +Error DataExtractor::extractStaticAnalysis(CompilationUnit &unit, + const std::string &tempDir) { + for (const auto &source : unit.getInfo().sources) { + if (source.isHeader) + continue; + + std::string outputFile = tempDir + "/static-analyzer/" + + sys::path::stem(source.path).str() + + ".analysis.txt"; + + auto baseArgs = getBaseCompilerArgs(unit.getInfo()); + baseArgs.push_back("--analyze"); + baseArgs.push_back("-Xanalyzer"); + baseArgs.push_back("-analyzer-output=text"); + baseArgs.push_back(source.path); + + auto result = ProcessRunner::run(config_.getToolPath("clang"), baseArgs, + config_.getTimeout()); + if (result) { + std::error_code EC; + raw_fd_ostream OS(outputFile, EC); + if (!EC) { + OS << "STDOUT:\n" << result->stdout << "\nSTDERR:\n" << result->stderr; + unit.addGeneratedFile("static-analyzer", outputFile); + } + } + } + return Error::success(); +} + +Error DataExtractor::extractMacroExpansion(CompilationUnit &unit, + const std::string &tempDir) { + for (const auto &source : unit.getInfo().sources) { + if (source.isHeader) + continue; + + std::string outputFile = + tempDir + "/preprocessed/" + sys::path::stem(source.path).str() + + ".macro-expanded" + ((source.language == "C++") ? ".ii" : ".i"); + + auto baseArgs = getBaseCompilerArgs(unit.getInfo()); + baseArgs.push_back("-E"); + baseArgs.push_back("-dM"); // Show macro definitions + baseArgs.push_back("-o"); + baseArgs.push_back(outputFile); + baseArgs.push_back(source.path); + + if (auto Err = runCompilerWithFlags(baseArgs)) { + if (config_.getVerbose()) { + errs() << "Failed to extract macro expansion for " << source.path + << "\n"; + } + continue; + } + + if (sys::fs::exists(outputFile)) { + unit.addGeneratedFile("macro-expansion", outputFile); + } + } + return Error::success(); +} + +Error DataExtractor::extractCompilationPhases(CompilationUnit &unit, + const std::string &tempDir) { + for (const auto &source : unit.getInfo().sources) { + if (source.isHeader) + continue; + + std::string outputFile = tempDir + "/debug/" + + sys::path::stem(source.path).str() + ".phases.txt"; + + auto baseArgs = getBaseCompilerArgs(unit.getInfo()); + baseArgs.push_back("-v"); // Verbose compilation phases + baseArgs.push_back("-fsyntax-only"); + baseArgs.push_back(source.path); + + auto result = ProcessRunner::run(config_.getToolPath("clang"), baseArgs, + config_.getTimeout()); + if (result) { + std::error_code EC; + raw_fd_ostream OS(outputFile, EC); + if (!EC) { + OS << "COMPILATION PHASES:\n" + << result->stderr; // Verbose output goes to stderr + unit.addGeneratedFile("compilation-phases", outputFile); + } + } + } + return Error::success(); +} + +Error DataExtractor::runCompilerWithFlags( + const std::vector &args) { + auto result = ProcessRunner::run(config_.getToolPath("clang"), args, + config_.getTimeout()); + if (!result || result->exitCode != 0) { + return createStringError(std::make_error_code(std::errc::io_error), + "Compiler failed"); + } + return Error::success(); +} + +} // namespace advisor +} // namespace llvm diff --git a/llvm/tools/llvm-advisor/src/Core/DataExtractor.h b/llvm/tools/llvm-advisor/src/Core/DataExtractor.h new file mode 100644 index 0000000000000..7564660ed05b9 --- /dev/null +++ b/llvm/tools/llvm-advisor/src/Core/DataExtractor.h @@ -0,0 +1,44 @@ +#ifndef LLVM_ADVISOR_DATA_EXTRACTOR_H +#define LLVM_ADVISOR_DATA_EXTRACTOR_H + +#include "../Config/AdvisorConfig.h" +#include "CompilationUnit.h" +#include "llvm/Support/Error.h" +#include +#include + +namespace llvm { +namespace advisor { + +class DataExtractor { +public: + DataExtractor(const AdvisorConfig &config); + + Error extractAllData(CompilationUnit &unit, const std::string &tempDir); + +private: + std::vector + getBaseCompilerArgs(const CompilationUnitInfo &unitInfo) const; + + Error extractIR(CompilationUnit &unit, const std::string &tempDir); + Error extractAssembly(CompilationUnit &unit, const std::string &tempDir); + Error extractAST(CompilationUnit &unit, const std::string &tempDir); + Error extractPreprocessed(CompilationUnit &unit, const std::string &tempDir); + Error extractIncludeTree(CompilationUnit &unit, const std::string &tempDir); + Error extractDebugInfo(CompilationUnit &unit, const std::string &tempDir); + Error extractStaticAnalysis(CompilationUnit &unit, + const std::string &tempDir); + Error extractMacroExpansion(CompilationUnit &unit, + const std::string &tempDir); + Error extractCompilationPhases(CompilationUnit &unit, + const std::string &tempDir); + + Error runCompilerWithFlags(const std::vector &args); + + const AdvisorConfig &config_; +}; + +} // namespace advisor +} // namespace llvm + +#endif From bc8d356b0cfc7e79cef3b70b521da41abb77eb1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20C=C3=A1rdenas?= Date: Sun, 13 Jul 2025 06:44:04 +0200 Subject: [PATCH 08/10] [llvm-advisor] Add support for detecting compilation units Adds logic to scan the origin compiler arguments, find source files, figure out compile flags and output paths, and create a description of each compilation unit. This is the entry point for the analysis pipeline. --- .../src/Detection/UnitDetector.cpp | 114 ++++++++++++++++++ .../llvm-advisor/src/Detection/UnitDetector.h | 35 ++++++ 2 files changed, 149 insertions(+) create mode 100644 llvm/tools/llvm-advisor/src/Detection/UnitDetector.cpp create mode 100644 llvm/tools/llvm-advisor/src/Detection/UnitDetector.h diff --git a/llvm/tools/llvm-advisor/src/Detection/UnitDetector.cpp b/llvm/tools/llvm-advisor/src/Detection/UnitDetector.cpp new file mode 100644 index 0000000000000..16d24f7a61d8f --- /dev/null +++ b/llvm/tools/llvm-advisor/src/Detection/UnitDetector.cpp @@ -0,0 +1,114 @@ +#include "UnitDetector.h" +#include "llvm/ADT/Hashing.h" +#include "llvm/Support/Path.h" + +namespace llvm { +namespace advisor { + +UnitDetector::UnitDetector(const AdvisorConfig &config) : config_(config) {} + +Expected> +UnitDetector::detectUnits(const std::string &compiler, + const std::vector &args) { + + auto sources = findSourceFiles(args); + if (sources.empty()) { + return createStringError(std::make_error_code(std::errc::invalid_argument), + "No source files found"); + } + + CompilationUnitInfo unit; + unit.name = generateUnitName(sources); + unit.sources = sources; + + // Store original args but filter out source files for the compile flags + for (const auto &arg : args) { + // Skip source files when adding to compile flags + StringRef extension = sys::path::extension(arg); + if (!arg.empty() && arg[0] != '-' && + (extension == ".c" || extension == ".cpp" || extension == ".cc" || + extension == ".cxx" || extension == ".C")) { + continue; + } + unit.compileFlags.push_back(arg); + } + + // Extract output files and features + extractBuildInfo(args, unit); + + return std::vector{unit}; +} + +std::vector +UnitDetector::findSourceFiles(const std::vector &args) const { + std::vector sources; + + for (const auto &arg : args) { + if (arg.empty() || arg[0] == '-') + continue; + + StringRef extension = sys::path::extension(arg); + if (extension == ".c" || extension == ".cpp" || extension == ".cc" || + extension == ".cxx" || extension == ".C") { + + SourceFile source; + source.path = arg; + source.language = classifier_.getLanguage(arg); + source.isHeader = false; + sources.push_back(source); + } + } + + return sources; +} + +void UnitDetector::extractBuildInfo(const std::vector &args, + CompilationUnitInfo &unit) { + for (size_t i = 0; i < args.size(); ++i) { + const auto &arg = args[i]; + + if (arg == "-o" && i + 1 < args.size()) { + StringRef output = args[i + 1]; + StringRef ext = sys::path::extension(output); + if (ext == ".o") { + unit.outputObject = args[i + 1]; + } else { + unit.outputExecutable = args[i + 1]; + } + } + + if (arg.find("openmp") != std::string::npos || + arg.find("offload") != std::string::npos || + arg.find("cuda") != std::string::npos) { + unit.hasOffloading = true; + } + + if (StringRef(arg).starts_with("-march=")) { + unit.targetArch = arg.substr(7); + } + } +} + +std::string +UnitDetector::generateUnitName(const std::vector &sources) const { + if (sources.empty()) + return "unknown"; + + // Use first source file name as base + std::string baseName = sys::path::stem(sources[0].path).str(); + + // Add hash for uniqueness when multiple sources + if (sources.size() > 1) { + std::string combined; + for (const auto &source : sources) { + combined += source.path; + } + auto hash = hash_value(combined); + baseName += "_" + std::to_string(static_cast(hash) % 10000); + } + + return baseName; +} + +} // namespace advisor +} // namespace llvm diff --git a/llvm/tools/llvm-advisor/src/Detection/UnitDetector.h b/llvm/tools/llvm-advisor/src/Detection/UnitDetector.h new file mode 100644 index 0000000000000..8ad998d3c4e7a --- /dev/null +++ b/llvm/tools/llvm-advisor/src/Detection/UnitDetector.h @@ -0,0 +1,35 @@ +#ifndef LLVM_ADVISOR_UNIT_DETECTOR_H +#define LLVM_ADVISOR_UNIT_DETECTOR_H + +#include "../Config/AdvisorConfig.h" +#include "../Core/CompilationUnit.h" +#include "../Utils/FileClassifier.h" +#include "llvm/Support/Error.h" +#include + +namespace llvm { +namespace advisor { + +class UnitDetector { +public: + explicit UnitDetector(const AdvisorConfig &config); + + Expected> + detectUnits(const std::string &compiler, + const std::vector &args); + +private: + std::vector + findSourceFiles(const std::vector &args) const; + void extractBuildInfo(const std::vector &args, + CompilationUnitInfo &unit); + std::string generateUnitName(const std::vector &sources) const; + + const AdvisorConfig &config_; + FileClassifier classifier_; +}; + +} // namespace advisor +} // namespace llvm + +#endif From cbf57316d8dc6103c7f6ed6ad4714229f02473d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20C=C3=A1rdenas?= Date: Sun, 13 Jul 2025 06:48:06 +0200 Subject: [PATCH 09/10] [llvm-advisor] Add main command-line driver Adds the command-line front-end that handles advisor options, finds the compiler commands, create configuration, and starts the build data collection. --- llvm/tools/llvm-advisor/src/llvm-advisor.cpp | 111 +++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 llvm/tools/llvm-advisor/src/llvm-advisor.cpp diff --git a/llvm/tools/llvm-advisor/src/llvm-advisor.cpp b/llvm/tools/llvm-advisor/src/llvm-advisor.cpp new file mode 100644 index 0000000000000..01c28ba53b95b --- /dev/null +++ b/llvm/tools/llvm-advisor/src/llvm-advisor.cpp @@ -0,0 +1,111 @@ +#include "Config/AdvisorConfig.h" +#include "Core/CompilationManager.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/InitLLVM.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; +using namespace llvm::advisor; + +static cl::opt ConfigFile("config", cl::desc("Configuration file"), + cl::value_desc("filename")); +static cl::opt OutputDir("output-dir", + cl::desc("Output directory"), + cl::value_desc("directory")); +static cl::opt Verbose("verbose", cl::desc("Verbose output")); +static cl::opt KeepTemps("keep-temps", cl::desc("Keep temporary files")); +static cl::opt NoProfiler("no-profiler", cl::desc("Disable profiler")); + +int main(int argc, char **argv) { + InitLLVM X(argc, argv); + + // Parse llvm-advisor options until we find the compiler + std::vector advisorArgs; + advisorArgs.push_back(argv[0]); + + int compilerArgStart = 1; + bool foundCompiler = false; + + for (int i = 1; i < argc; ++i) { + StringRef arg(argv[i]); + if (arg.starts_with("--") || + (arg.starts_with("-") && arg.size() > 1 && arg != "-")) { + advisorArgs.push_back(argv[i]); + if (arg == "--config" || arg == "--output-dir") { + if (i + 1 < argc && !StringRef(argv[i + 1]).starts_with("-")) { + advisorArgs.push_back(argv[++i]); + } + } + } else { + compilerArgStart = i; + foundCompiler = true; + break; + } + } + + if (!foundCompiler) { + errs() << "Error: No compiler command provided.\n"; + errs() << "Usage: llvm-advisor [options] [compiler-args...]\n"; + return 1; + } + + // Parse llvm-advisor options + int advisorArgc = advisorArgs.size(); + cl::ParseCommandLineOptions(advisorArgc, + const_cast(advisorArgs.data()), + "LLVM Compilation Advisor"); + + // Extract compiler and arguments + std::string compiler = argv[compilerArgStart]; + std::vector compilerArgs; + for (int i = compilerArgStart + 1; i < argc; ++i) { + compilerArgs.push_back(argv[i]); + } + + // Configure advisor + AdvisorConfig config; + if (!ConfigFile.empty()) { + if (auto Err = config.loadFromFile(ConfigFile).takeError()) { + errs() << "Error loading config: " << toString(std::move(Err)) << "\n"; + return 1; + } + } + + if (!OutputDir.empty()) { + config.setOutputDir(OutputDir); + } else { + config.setOutputDir(".llvm-advisor"); // Default hidden directory + } + + config.setVerbose(Verbose); + config.setKeepTemps(KeepTemps); + config.setRunProfiler(!NoProfiler); + + // Create output directory + if (auto EC = sys::fs::create_directories(config.getOutputDir())) { + errs() << "Error creating output directory: " << EC.message() << "\n"; + return 1; + } + + if (config.getVerbose()) { + outs() << "LLVM Compilation Advisor\n"; + outs() << "Compiler: " << compiler << "\n"; + outs() << "Output: " << config.getOutputDir() << "\n"; + } + + // Execute with data collection + CompilationManager manager(config); + auto result = manager.executeWithDataCollection(compiler, compilerArgs); + + if (result) { + if (config.getVerbose()) { + outs() << "Compilation completed (exit code: " << *result << ")\n"; + } + return *result; + } else { + errs() << "Error: " << toString(result.takeError()) << "\n"; + return 1; + } +} From 9658c853e32702b14e3b000377273d9c608539ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20C=C3=A1rdenas?= Date: Thu, 24 Jul 2025 11:41:41 +0200 Subject: [PATCH 10/10] [llvm-advisor] Add llvm copyright and use code styling - use cpp code standard based on llvm guidelines --- .../llvm-advisor/src/Config/AdvisorConfig.cpp | 20 +- .../llvm-advisor/src/Config/AdvisorConfig.h | 19 +- .../llvm-advisor/src/Core/BuildContext.h | 34 +- .../llvm-advisor/src/Core/BuildExecutor.cpp | 103 ++- .../llvm-advisor/src/Core/BuildExecutor.h | 38 +- .../llvm-advisor/src/Core/CommandAnalyzer.cpp | 60 +- .../llvm-advisor/src/Core/CommandAnalyzer.h | 32 +- .../src/Core/CompilationManager.cpp | 121 +-- .../src/Core/CompilationManager.h | 43 +- .../llvm-advisor/src/Core/CompilationUnit.cpp | 52 +- .../llvm-advisor/src/Core/CompilationUnit.h | 42 +- .../llvm-advisor/src/Core/DataExtractor.cpp | 765 +++++++++--------- .../llvm-advisor/src/Core/DataExtractor.h | 100 ++- .../src/Detection/UnitDetector.cpp | 62 +- .../llvm-advisor/src/Detection/UnitDetector.h | 37 +- .../llvm-advisor/src/Utils/FileClassifier.cpp | 20 +- .../llvm-advisor/src/Utils/FileClassifier.h | 20 +- .../llvm-advisor/src/Utils/FileManager.cpp | 48 +- .../llvm-advisor/src/Utils/FileManager.h | 39 +- .../llvm-advisor/src/Utils/ProcessRunner.cpp | 27 +- .../llvm-advisor/src/Utils/ProcessRunner.h | 27 +- llvm/tools/llvm-advisor/src/llvm-advisor.cpp | 81 +- 22 files changed, 1075 insertions(+), 715 deletions(-) diff --git a/llvm/tools/llvm-advisor/src/Config/AdvisorConfig.cpp b/llvm/tools/llvm-advisor/src/Config/AdvisorConfig.cpp index 69f1e3d52702e..42bbb2f206573 100644 --- a/llvm/tools/llvm-advisor/src/Config/AdvisorConfig.cpp +++ b/llvm/tools/llvm-advisor/src/Config/AdvisorConfig.cpp @@ -1,3 +1,17 @@ +//===------------------ AdvisorConfig.cpp - LLVM Advisor ------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This is the AdvisorConfig code generator driver. It provides a convenient +// command-line interface for generating an assembly file or a relocatable file, +// given LLVM bitcode. +// +//===----------------------------------------------------------------------===// + #include "AdvisorConfig.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/JSON.h" @@ -12,7 +26,7 @@ AdvisorConfig::AdvisorConfig() { OutputDir_ = ".llvm-advisor"; } -Expected AdvisorConfig::loadFromFile(const std::string &path) { +Expected AdvisorConfig::loadFromFile(llvm::StringRef path) { auto BufferOrError = MemoryBuffer::getFile(path); if (!BufferOrError) { return createStringError(BufferOrError.getError(), @@ -55,9 +69,9 @@ Expected AdvisorConfig::loadFromFile(const std::string &path) { return true; } -std::string AdvisorConfig::getToolPath(const std::string &tool) const { +std::string AdvisorConfig::getToolPath(llvm::StringRef tool) const { // For now, just return the tool name and rely on PATH - return tool; + return tool.str(); } } // namespace advisor diff --git a/llvm/tools/llvm-advisor/src/Config/AdvisorConfig.h b/llvm/tools/llvm-advisor/src/Config/AdvisorConfig.h index b7f553fddbb23..25808a3e52db2 100644 --- a/llvm/tools/llvm-advisor/src/Config/AdvisorConfig.h +++ b/llvm/tools/llvm-advisor/src/Config/AdvisorConfig.h @@ -1,6 +1,21 @@ +//===------------------- AdvisorConfig.h - LLVM Advisor -------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This is the AdvisorConfig code generator driver. It provides a convenient +// command-line interface for generating an assembly file or a relocatable file, +// given LLVM bitcode. +// +//===----------------------------------------------------------------------===// + #ifndef LLVM_ADVISOR_CONFIG_H #define LLVM_ADVISOR_CONFIG_H +#include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" #include @@ -11,7 +26,7 @@ class AdvisorConfig { public: AdvisorConfig(); - Expected loadFromFile(const std::string &path); + Expected loadFromFile(llvm::StringRef path); void setOutputDir(const std::string &dir) { OutputDir_ = dir; } void setVerbose(bool verbose) { Verbose_ = verbose; } @@ -25,7 +40,7 @@ class AdvisorConfig { bool getRunProfiler() const { return RunProfiler_; } int getTimeout() const { return TimeoutSeconds_; } - std::string getToolPath(const std::string &tool) const; + std::string getToolPath(llvm::StringRef tool) const; private: std::string OutputDir_; diff --git a/llvm/tools/llvm-advisor/src/Core/BuildContext.h b/llvm/tools/llvm-advisor/src/Core/BuildContext.h index 4f40c37ca8706..18156f3634bea 100644 --- a/llvm/tools/llvm-advisor/src/Core/BuildContext.h +++ b/llvm/tools/llvm-advisor/src/Core/BuildContext.h @@ -1,9 +1,25 @@ -#ifndef LLVM_ADVISOR_BUILD_CONTEXT_H -#define LLVM_ADVISOR_BUILD_CONTEXT_H +//===------------------- BuildContext.h - LLVM Advisor --------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This is the BuildContext code generator driver. It provides a convenient +// command-line interface for generating an assembly file or a relocatable file, +// given LLVM bitcode. +// +//===----------------------------------------------------------------------===// -#include +#ifndef LLVM_ADVISOR_CORE_BUILDCONTEXT_H +#define LLVM_ADVISOR_CORE_BUILDCONTEXT_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" #include -#include +#include namespace llvm { namespace advisor { @@ -37,10 +53,10 @@ struct BuildContext { BuildTool tool; std::string workingDirectory; std::string outputDirectory; - std::vector inputFiles; - std::vector outputFiles; - std::vector expectedGeneratedFiles; - std::map metadata; + llvm::SmallVector inputFiles; + llvm::SmallVector outputFiles; + llvm::SmallVector expectedGeneratedFiles; + std::unordered_map metadata; bool hasOffloading = false; bool hasDebugInfo = false; bool hasOptimization = false; @@ -49,4 +65,4 @@ struct BuildContext { } // namespace advisor } // namespace llvm -#endif +#endif // LLVM_ADVISOR_CORE_BUILDCONTEXT_H diff --git a/llvm/tools/llvm-advisor/src/Core/BuildExecutor.cpp b/llvm/tools/llvm-advisor/src/Core/BuildExecutor.cpp index a4af5a660c80e..837c1e94e5864 100644 --- a/llvm/tools/llvm-advisor/src/Core/BuildExecutor.cpp +++ b/llvm/tools/llvm-advisor/src/Core/BuildExecutor.cpp @@ -1,4 +1,21 @@ +//===---------------- BuildExecutor.cpp - LLVM Advisor --------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This is the BuildExecutor code generator driver. It provides a convenient +// command-line interface for generating an assembly file or a relocatable file, +// given LLVM bitcode. +// +//===----------------------------------------------------------------------===// + #include "BuildExecutor.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include "llvm/Support/Program.h" @@ -9,76 +26,76 @@ namespace advisor { BuildExecutor::BuildExecutor(const AdvisorConfig &config) : config_(config) {} -Expected BuildExecutor::execute(const std::string &compiler, - const std::vector &args, - BuildContext &buildContext, - const std::string &tempDir) { +llvm::Expected +BuildExecutor::execute(llvm::StringRef compiler, + const llvm::SmallVectorImpl &args, + BuildContext &buildContext, llvm::StringRef tempDir) { auto instrumentedArgs = instrumentCompilerArgs(args, buildContext, tempDir); - auto compilerPath = sys::findProgramByName(compiler); + auto compilerPath = llvm::sys::findProgramByName(compiler); if (!compilerPath) { - return createStringError( + return llvm::createStringError( std::make_error_code(std::errc::no_such_file_or_directory), - "Compiler not found: " + compiler); + "Compiler not found: " + compiler.str()); } - std::vector execArgs; + llvm::SmallVector execArgs; execArgs.push_back(compiler); for (const auto &arg : instrumentedArgs) { execArgs.push_back(arg); } if (config_.getVerbose()) { - outs() << "Executing: " << compiler; + llvm::outs() << "Executing: " << compiler; for (const auto &arg : instrumentedArgs) { - outs() << " " << arg; + llvm::outs() << " " << arg; } - outs() << "\n"; + llvm::outs() << "\n"; } - return sys::ExecuteAndWait(*compilerPath, execArgs); + return llvm::sys::ExecuteAndWait(*compilerPath, execArgs); } -std::vector -BuildExecutor::instrumentCompilerArgs(const std::vector &args, - BuildContext &buildContext, - const std::string &tempDir) { +llvm::SmallVector BuildExecutor::instrumentCompilerArgs( + const llvm::SmallVectorImpl &args, BuildContext &buildContext, + llvm::StringRef tempDir) { - std::vector result = args; - std::set existingFlags; + llvm::SmallVector result(args.begin(), args.end()); + llvm::DenseSet existingFlags; // Scan existing flags to avoid duplication for (const auto &arg : args) { - if (arg.find("-g") == 0) + if (llvm::StringRef(arg).starts_with("-g")) existingFlags.insert("debug"); - if (arg.find("-fsave-optimization-record") != std::string::npos) + if (llvm::StringRef(arg).contains("-fsave-optimization-record")) existingFlags.insert("remarks"); - if (arg.find("-fprofile-instr-generate") != std::string::npos) + if (llvm::StringRef(arg).contains("-fprofile-instr-generate")) existingFlags.insert("profile"); } // Add debug info if not present - if (existingFlags.find("debug") == existingFlags.end()) { + if (!existingFlags.contains("debug")) { result.push_back("-g"); } // Add optimization remarks with proper redirection - if (existingFlags.find("remarks") == existingFlags.end()) { + if (!existingFlags.contains("remarks")) { result.push_back("-fsave-optimization-record"); - result.push_back("-foptimization-record-file=" + tempDir + + result.push_back("-foptimization-record-file=" + tempDir.str() + "/remarks.opt.yaml"); - buildContext.expectedGeneratedFiles.push_back(tempDir + + buildContext.expectedGeneratedFiles.push_back(tempDir.str() + "/remarks.opt.yaml"); } else { // If user already specified remarks, find and redirect the file bool foundFileFlag = false; for (auto &arg : result) { - if (arg.find("-foptimization-record-file=") != std::string::npos) { + if (llvm::StringRef(arg).contains("-foptimization-record-file=")) { // Extract filename and redirect to temp - StringRef existingPath = StringRef(arg).substr(26); - StringRef filename = sys::path::filename(existingPath); - arg = "-foptimization-record-file=" + tempDir + "/" + filename.str(); - buildContext.expectedGeneratedFiles.push_back(tempDir + "/" + + llvm::StringRef existingPath = llvm::StringRef(arg).substr(26); + llvm::StringRef filename = llvm::sys::path::filename(existingPath); + arg = "-foptimization-record-file=" + tempDir.str() + "/" + + filename.str(); + buildContext.expectedGeneratedFiles.push_back(tempDir.str() + "/" + filename.str()); foundFileFlag = true; break; @@ -86,20 +103,34 @@ BuildExecutor::instrumentCompilerArgs(const std::vector &args, } // If no explicit file specified, add our own if (!foundFileFlag) { - result.push_back("-foptimization-record-file=" + tempDir + + result.push_back("-foptimization-record-file=" + tempDir.str() + "/remarks.opt.yaml"); - buildContext.expectedGeneratedFiles.push_back(tempDir + + buildContext.expectedGeneratedFiles.push_back(tempDir.str() + "/remarks.opt.yaml"); } } // Add profiling if enabled and not present, redirect to temp directory - if (config_.getRunProfiler() && - existingFlags.find("profile") == existingFlags.end()) { - result.push_back("-fprofile-instr-generate=" + tempDir + + if (config_.getRunProfiler() && !existingFlags.contains("profile")) { + result.push_back("-fprofile-instr-generate=" + tempDir.str() + "/profile.profraw"); result.push_back("-fcoverage-mapping"); - buildContext.expectedGeneratedFiles.push_back(tempDir + "/profile.profraw"); + buildContext.expectedGeneratedFiles.push_back(tempDir.str() + + "/profile.profraw"); + } + + // Add remark extraction flags if none present + bool hasRpass = false; + for (const auto &arg : result) { + if (llvm::StringRef(arg).starts_with("-Rpass=")) { + hasRpass = true; + break; + } + } + if (!hasRpass) { + // For now we add offloading and general analysis passes + result.push_back("-Rpass=kernel-info"); + result.push_back("-Rpass=analysis"); } return result; diff --git a/llvm/tools/llvm-advisor/src/Core/BuildExecutor.h b/llvm/tools/llvm-advisor/src/Core/BuildExecutor.h index a77ffd70c9b57..965ad86158944 100644 --- a/llvm/tools/llvm-advisor/src/Core/BuildExecutor.h +++ b/llvm/tools/llvm-advisor/src/Core/BuildExecutor.h @@ -1,12 +1,26 @@ -#ifndef LLVM_ADVISOR_BUILD_EXECUTOR_H -#define LLVM_ADVISOR_BUILD_EXECUTOR_H +//===------------------- BuildExecutor.h - LLVM Advisor -------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This is the BuildExecutor code generator driver. It provides a convenient +// command-line interface for generating an assembly file or a relocatable file, +// given LLVM bitcode. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADVISOR_CORE_BUILDEXECUTOR_H +#define LLVM_ADVISOR_CORE_BUILDEXECUTOR_H #include "../Config/AdvisorConfig.h" #include "BuildContext.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" -#include #include -#include namespace llvm { namespace advisor { @@ -15,15 +29,15 @@ class BuildExecutor { public: BuildExecutor(const AdvisorConfig &config); - Expected execute(const std::string &compiler, - const std::vector &args, - BuildContext &buildContext, const std::string &tempDir); + llvm::Expected execute(llvm::StringRef compiler, + const llvm::SmallVectorImpl &args, + BuildContext &buildContext, + llvm::StringRef tempDir); private: - std::vector - instrumentCompilerArgs(const std::vector &args, - BuildContext &buildContext, - const std::string &tempDir); + llvm::SmallVector + instrumentCompilerArgs(const llvm::SmallVectorImpl &args, + BuildContext &buildContext, llvm::StringRef tempDir); const AdvisorConfig &config_; }; @@ -31,4 +45,4 @@ class BuildExecutor { } // namespace advisor } // namespace llvm -#endif +#endif // LLVM_ADVISOR_CORE_BUILDEXECUTOR_H diff --git a/llvm/tools/llvm-advisor/src/Core/CommandAnalyzer.cpp b/llvm/tools/llvm-advisor/src/Core/CommandAnalyzer.cpp index 3192c42669e65..7e5dc8b00114e 100644 --- a/llvm/tools/llvm-advisor/src/Core/CommandAnalyzer.cpp +++ b/llvm/tools/llvm-advisor/src/Core/CommandAnalyzer.cpp @@ -1,4 +1,19 @@ +//===----------------- CommandAnalyzer.cpp - LLVM Advisor -----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This is the CommandAnalyzer code generator driver. It provides a convenient +// command-line interface for generating an assembly file or a relocatable file, +// given LLVM bitcode. +// +//===----------------------------------------------------------------------===// + #include "CommandAnalyzer.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/FileSystem.h" @@ -7,14 +22,14 @@ namespace llvm { namespace advisor { -CommandAnalyzer::CommandAnalyzer(const std::string &command, - const std::vector &args) - : command_(command), args_(args) {} +CommandAnalyzer::CommandAnalyzer(llvm::StringRef command, + const llvm::SmallVectorImpl &args) + : command_(command.str()), args_(args.data(), args.data() + args.size()) {} BuildContext CommandAnalyzer::analyze() const { BuildContext context; - SmallString<256> cwd; - sys::fs::current_path(cwd); + llvm::SmallString<256> cwd; + llvm::sys::fs::current_path(cwd); context.workingDirectory = cwd.str().str(); context.tool = detectBuildTool(); @@ -27,7 +42,7 @@ BuildContext CommandAnalyzer::analyze() const { } BuildTool CommandAnalyzer::detectBuildTool() const { - return StringSwitch(sys::path::filename(command_)) + return llvm::StringSwitch(llvm::sys::path::filename(command_)) .StartsWith("clang", BuildTool::Clang) .StartsWith("gcc", BuildTool::GCC) .StartsWith("g++", BuildTool::GCC) @@ -75,7 +90,7 @@ BuildPhase CommandAnalyzer::detectBuildPhase(BuildTool tool) const { bool hasObjectFile = false; for (const auto &Arg : args_) { - StringRef argRef(Arg); + llvm::StringRef argRef(Arg); if (argRef.ends_with(".o") || argRef.ends_with(".O") || argRef.ends_with(".obj") || argRef.ends_with(".OBJ")) { hasObjectFile = true; @@ -88,7 +103,7 @@ BuildPhase CommandAnalyzer::detectBuildPhase(BuildTool tool) const { bool hasSourceFile = false; for (const auto &Arg : args_) { - StringRef argRef(Arg); + llvm::StringRef argRef(Arg); if (argRef.ends_with(".c") || argRef.ends_with(".C") || argRef.ends_with(".cpp") || argRef.ends_with(".CPP") || argRef.ends_with(".cc") || argRef.ends_with(".CC") || @@ -107,52 +122,51 @@ BuildPhase CommandAnalyzer::detectBuildPhase(BuildTool tool) const { void CommandAnalyzer::detectBuildFeatures(BuildContext &context) const { for (const auto &arg : args_) { - if (arg == "-g" || StringRef(arg).starts_with("-g")) { + if (arg == "-g" || llvm::StringRef(arg).starts_with("-g")) { context.hasDebugInfo = true; } - if (StringRef(arg).starts_with("-O") && arg.length() > 2) { + if (llvm::StringRef(arg).starts_with("-O") && arg.length() > 2) { context.hasOptimization = true; } - if (arg.find("openmp") != std::string::npos || - arg.find("openacc") != std::string::npos || - arg.find("cuda") != std::string::npos || - arg.find("offload") != std::string::npos) { + llvm::StringRef argRef(arg); + if (argRef.contains("openmp") || argRef.contains("openacc") || + argRef.contains("cuda") || argRef.contains("offload")) { context.hasOffloading = true; } - if (StringRef(arg).starts_with("-march=")) { + if (llvm::StringRef(arg).starts_with("-march=")) { context.metadata["target_arch"] = arg.substr(7); } - if (StringRef(arg).starts_with("-mtune=")) { + if (llvm::StringRef(arg).starts_with("-mtune=")) { context.metadata["tune"] = arg.substr(7); } - if (StringRef(arg).starts_with("--offload-arch=")) { + if (llvm::StringRef(arg).starts_with("--offload-arch=")) { context.metadata["offload_arch"] = arg.substr(15); } } } -std::vector CommandAnalyzer::extractInputFiles() const { - std::vector inputs; +llvm::SmallVector CommandAnalyzer::extractInputFiles() const { + llvm::SmallVector inputs; for (size_t i = 0; i < args_.size(); ++i) { const auto &arg = args_[i]; - if (StringRef(arg).starts_with("-")) { + if (llvm::StringRef(arg).starts_with("-")) { if (arg == "-o" || arg == "-I" || arg == "-L" || arg == "-D") { i++; } continue; } - if (sys::fs::exists(arg)) { + if (llvm::sys::fs::exists(arg)) { inputs.push_back(arg); } } return inputs; } -std::vector CommandAnalyzer::extractOutputFiles() const { - std::vector outputs; +llvm::SmallVector CommandAnalyzer::extractOutputFiles() const { + llvm::SmallVector outputs; for (size_t i = 0; i < args_.size(); ++i) { const auto &arg = args_[i]; if (arg == "-o" && i + 1 < args_.size()) { diff --git a/llvm/tools/llvm-advisor/src/Core/CommandAnalyzer.h b/llvm/tools/llvm-advisor/src/Core/CommandAnalyzer.h index c3efdff147e5f..cb31279121d66 100644 --- a/llvm/tools/llvm-advisor/src/Core/CommandAnalyzer.h +++ b/llvm/tools/llvm-advisor/src/Core/CommandAnalyzer.h @@ -1,17 +1,31 @@ -#ifndef LLVM_ADVISOR_COMMAND_ANALYZER_H -#define LLVM_ADVISOR_COMMAND_ANALYZER_H +//===------------------- CommandAnalyzer.h - LLVM Advisor -----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This is the CommandAnalyzer code generator driver. It provides a convenient +// command-line interface for generating an assembly file or a relocatable file, +// given LLVM bitcode. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_ADVISOR_CORE_COMMANDANALYZER_H +#define LLVM_ADVISOR_CORE_COMMANDANALYZER_H #include "BuildContext.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" #include -#include namespace llvm { namespace advisor { class CommandAnalyzer { public: - CommandAnalyzer(const std::string &command, - const std::vector &args); + CommandAnalyzer(llvm::StringRef command, + const llvm::SmallVectorImpl &args); BuildContext analyze() const; @@ -19,14 +33,14 @@ class CommandAnalyzer { BuildTool detectBuildTool() const; BuildPhase detectBuildPhase(BuildTool tool) const; void detectBuildFeatures(BuildContext &context) const; - std::vector extractInputFiles() const; - std::vector extractOutputFiles() const; + llvm::SmallVector extractInputFiles() const; + llvm::SmallVector extractOutputFiles() const; std::string command_; - std::vector args_; + llvm::SmallVector args_; }; } // namespace advisor } // namespace llvm -#endif +#endif // LLVM_ADVISOR_CORE_COMMANDANALYZER_H diff --git a/llvm/tools/llvm-advisor/src/Core/CompilationManager.cpp b/llvm/tools/llvm-advisor/src/Core/CompilationManager.cpp index e07db9d365009..6a4e1cc0ca2f8 100644 --- a/llvm/tools/llvm-advisor/src/Core/CompilationManager.cpp +++ b/llvm/tools/llvm-advisor/src/Core/CompilationManager.cpp @@ -1,13 +1,29 @@ +//===---------------- CompilationManager.cpp - LLVM Advisor ---------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This is the CompilationManager code generator driver. It provides a +// convenient command-line interface for generating an assembly file or a +// relocatable file, given LLVM bitcode. +// +//===----------------------------------------------------------------------===// + #include "CompilationManager.h" #include "../Detection/UnitDetector.h" #include "../Utils/FileManager.h" #include "CommandAnalyzer.h" #include "DataExtractor.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include #include -#include +#include namespace llvm { namespace advisor { @@ -16,48 +32,51 @@ CompilationManager::CompilationManager(const AdvisorConfig &config) : config_(config), buildExecutor_(config) { // Get current working directory first - SmallString<256> currentDir; - sys::fs::current_path(currentDir); + llvm::SmallString<256> currentDir; + llvm::sys::fs::current_path(currentDir); initialWorkingDir_ = currentDir.str().str(); // Create temp directory with proper error handling - SmallString<128> tempDirPath; - if (auto EC = sys::fs::createUniqueDirectory("llvm-advisor", tempDirPath)) { + llvm::SmallString<128> tempDirPath; + if (auto EC = + llvm::sys::fs::createUniqueDirectory("llvm-advisor", tempDirPath)) { // Use timestamp for temp folder naming auto now = std::chrono::system_clock::now(); auto timestamp = std::chrono::duration_cast(now.time_since_epoch()) .count(); tempDir_ = "/tmp/llvm-advisor-" + std::to_string(timestamp); - sys::fs::create_directories(tempDir_); + llvm::sys::fs::create_directories(tempDir_); } else { tempDir_ = tempDirPath.str().str(); } // Ensure the directory actually exists - if (!sys::fs::exists(tempDir_)) { - sys::fs::create_directories(tempDir_); + if (!llvm::sys::fs::exists(tempDir_)) { + llvm::sys::fs::create_directories(tempDir_); } if (config_.getVerbose()) { - outs() << "Using temporary directory: " << tempDir_ << "\n"; + llvm::outs() << "Using temporary directory: " << tempDir_ << "\n"; } } CompilationManager::~CompilationManager() { - if (!config_.getKeepTemps() && sys::fs::exists(tempDir_)) { - sys::fs::remove_directories(tempDir_); + if (!config_.getKeepTemps() && llvm::sys::fs::exists(tempDir_)) { + llvm::sys::fs::remove_directories(tempDir_); } } -Expected CompilationManager::executeWithDataCollection( - const std::string &compiler, const std::vector &args) { +llvm::Expected CompilationManager::executeWithDataCollection( + const std::string &compiler, + const llvm::SmallVectorImpl &args) { // Analyze the build command BuildContext buildContext = CommandAnalyzer(compiler, args).analyze(); if (config_.getVerbose()) { - outs() << "Build phase: " << static_cast(buildContext.phase) << "\n"; + llvm::outs() << "Build phase: " << static_cast(buildContext.phase) + << "\n"; } // Skip data collection for linking/archiving phases @@ -73,7 +92,7 @@ Expected CompilationManager::executeWithDataCollection( return detectedUnits.takeError(); } - std::vector> units; + llvm::SmallVector, 4> units; for (auto &unitInfo : *detectedUnits) { units.push_back(std::make_unique(unitInfo, tempDir_)); } @@ -97,8 +116,8 @@ Expected CompilationManager::executeWithDataCollection( for (auto &unit : units) { if (auto Err = extractor.extractAllData(*unit, tempDir_)) { if (config_.getVerbose()) { - errs() << "Data extraction failed: " << toString(std::move(Err)) - << "\n"; + llvm::errs() << "Data extraction failed: " + << llvm::toString(std::move(Err)) << "\n"; } } } @@ -106,8 +125,8 @@ Expected CompilationManager::executeWithDataCollection( // Organize output if (auto Err = organizeOutput(units)) { if (config_.getVerbose()) { - errs() << "Output organization failed: " << toString(std::move(Err)) - << "\n"; + llvm::errs() << "Output organization failed: " + << llvm::toString(std::move(Err)) << "\n"; } } @@ -117,13 +136,13 @@ Expected CompilationManager::executeWithDataCollection( return exitCode; } -std::set -CompilationManager::scanDirectory(const std::string &dir) const { - std::set files; +std::unordered_set +CompilationManager::scanDirectory(llvm::StringRef dir) const { + std::unordered_set files; std::error_code EC; - for (sys::fs::directory_iterator DI(dir, EC), DE; DI != DE && !EC; + for (llvm::sys::fs::directory_iterator DI(dir, EC), DE; DI != DE && !EC; DI.increment(EC)) { - if (DI->type() != sys::fs::file_type::directory_file) { + if (DI->type() != llvm::sys::fs::file_type::directory_file) { files.insert(DI->path()); } } @@ -131,15 +150,15 @@ CompilationManager::scanDirectory(const std::string &dir) const { } void CompilationManager::collectGeneratedFiles( - const std::set &existingFiles, - std::vector> &units) { + const std::unordered_set &existingFiles, + llvm::SmallVectorImpl> &units) { FileClassifier classifier; // Collect files from temp directory std::error_code EC; - for (sys::fs::recursive_directory_iterator DI(tempDir_, EC), DE; + for (llvm::sys::fs::recursive_directory_iterator DI(tempDir_, EC), DE; DI != DE && !EC; DI.increment(EC)) { - if (DI->type() != sys::fs::file_type::directory_file) { + if (DI->type() != llvm::sys::fs::file_type::directory_file) { std::string filePath = DI->path(); if (classifier.shouldCollect(filePath)) { auto classification = classifier.classifyFile(filePath); @@ -160,7 +179,8 @@ void CompilationManager::collectGeneratedFiles( auto classification = classifier.classifyFile(file); // Move leaked file to temp directory - std::string destPath = tempDir_ + "/" + sys::path::filename(file).str(); + std::string destPath = + tempDir_ + "/" + llvm::sys::path::filename(file).str(); if (!FileManager::moveFile(file, destPath)) { if (!units.empty()) { units[0]->addGeneratedFile(classification.category, destPath); @@ -171,21 +191,21 @@ void CompilationManager::collectGeneratedFiles( } } -Error CompilationManager::organizeOutput( - const std::vector> &units) { +llvm::Error CompilationManager::organizeOutput( + const llvm::SmallVectorImpl> &units) { // Resolve output directory as absolute path from initial working directory - SmallString<256> outputDirPath; - if (sys::path::is_absolute(config_.getOutputDir())) { + llvm::SmallString<256> outputDirPath; + if (llvm::sys::path::is_absolute(config_.getOutputDir())) { outputDirPath = config_.getOutputDir(); } else { outputDirPath = initialWorkingDir_; - sys::path::append(outputDirPath, config_.getOutputDir()); + llvm::sys::path::append(outputDirPath, config_.getOutputDir()); } std::string outputDir = outputDirPath.str().str(); if (config_.getVerbose()) { - outs() << "Output directory: " << outputDir << "\n"; + llvm::outs() << "Output directory: " << outputDir << "\n"; } // Move collected files to organized structure @@ -193,61 +213,60 @@ Error CompilationManager::organizeOutput( std::string unitDir = outputDir + "/" + unit->getName(); // Remove existing unit directory if it exists - if (sys::fs::exists(unitDir)) { - if (auto EC = sys::fs::remove_directories(unitDir)) { + if (llvm::sys::fs::exists(unitDir)) { + if (auto EC = llvm::sys::fs::remove_directories(unitDir)) { if (config_.getVerbose()) { - errs() << "Warning: Could not remove existing unit directory: " - << unitDir << "\n"; + llvm::errs() << "Warning: Could not remove existing unit directory: " + << unitDir << "\n"; } } } // Create fresh unit directory - if (auto EC = sys::fs::create_directories(unitDir)) { + if (auto EC = llvm::sys::fs::create_directories(unitDir)) { continue; // Skip if we can't create the directory } const auto &generatedFiles = unit->getAllGeneratedFiles(); for (const auto &category : generatedFiles) { std::string categoryDir = unitDir + "/" + category.first; - sys::fs::create_directories(categoryDir); + llvm::sys::fs::create_directories(categoryDir); for (const auto &file : category.second) { std::string destFile = - categoryDir + "/" + sys::path::filename(file).str(); + categoryDir + "/" + llvm::sys::path::filename(file).str(); if (auto Err = FileManager::copyFile(file, destFile)) { if (config_.getVerbose()) { - errs() << "Failed to copy " << file << " to " << destFile << "\n"; + llvm::errs() << "Failed to copy " << file << " to " << destFile + << "\n"; } } } } } - return Error::success(); + return llvm::Error::success(); } void CompilationManager::cleanupLeakedFiles() { - FileClassifier classifier; - // Clean up any remaining leaked files in source directory auto currentFiles = scanDirectory(initialWorkingDir_); for (const auto &file : currentFiles) { - StringRef filename = sys::path::filename(file); + llvm::StringRef filename = llvm::sys::path::filename(file); // Remove optimization remarks files that leaked if (filename.ends_with(".opt.yaml") || filename.ends_with(".opt.yml")) { - sys::fs::remove(file); + llvm::sys::fs::remove(file); if (config_.getVerbose()) { - outs() << "Cleaned up leaked file: " << file << "\n"; + llvm::outs() << "Cleaned up leaked file: " << file << "\n"; } } // Remove profile files that leaked if (filename.ends_with(".profraw") || filename.ends_with(".profdata")) { - sys::fs::remove(file); + llvm::sys::fs::remove(file); if (config_.getVerbose()) { - outs() << "Cleaned up leaked file: " << file << "\n"; + llvm::outs() << "Cleaned up leaked file: " << file << "\n"; } } } diff --git a/llvm/tools/llvm-advisor/src/Core/CompilationManager.h b/llvm/tools/llvm-advisor/src/Core/CompilationManager.h index 5256042a8c464..15af5a6685dcc 100644 --- a/llvm/tools/llvm-advisor/src/Core/CompilationManager.h +++ b/llvm/tools/llvm-advisor/src/Core/CompilationManager.h @@ -1,14 +1,30 @@ -#ifndef LLVM_ADVISOR_COMPILATION_MANAGER_H -#define LLVM_ADVISOR_COMPILATION_MANAGER_H +//===---------------- CompilationManager.h - LLVM Advisor -----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This is the CompilationManager code generator driver. It provides a +// convenient command-line interface for generating an assembly file or a +// relocatable file, given LLVM bitcode. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_ADVISOR_CORE_COMPILATIONMANAGER_H +#define LLVM_ADVISOR_CORE_COMPILATIONMANAGER_H #include "../Config/AdvisorConfig.h" #include "../Utils/FileClassifier.h" #include "BuildExecutor.h" #include "CompilationUnit.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" #include -#include -#include +#include +#include namespace llvm { namespace advisor { @@ -18,18 +34,19 @@ class CompilationManager { explicit CompilationManager(const AdvisorConfig &config); ~CompilationManager(); - Expected executeWithDataCollection(const std::string &compiler, - const std::vector &args); + llvm::Expected + executeWithDataCollection(const std::string &compiler, + const llvm::SmallVectorImpl &args); private: - std::set scanDirectory(const std::string &dir) const; + std::unordered_set scanDirectory(llvm::StringRef dir) const; - void - collectGeneratedFiles(const std::set &existingFiles, - std::vector> &units); + void collectGeneratedFiles( + const std::unordered_set &existingFiles, + llvm::SmallVectorImpl> &units); - Error - organizeOutput(const std::vector> &units); + llvm::Error organizeOutput( + const llvm::SmallVectorImpl> &units); void cleanupLeakedFiles(); @@ -42,4 +59,4 @@ class CompilationManager { } // namespace advisor } // namespace llvm -#endif +#endif // LLVM_ADVISOR_CORE_COMPILATIONMANAGER_H diff --git a/llvm/tools/llvm-advisor/src/Core/CompilationUnit.cpp b/llvm/tools/llvm-advisor/src/Core/CompilationUnit.cpp index 8b6a478cfaf63..acde8ea935d5e 100644 --- a/llvm/tools/llvm-advisor/src/Core/CompilationUnit.cpp +++ b/llvm/tools/llvm-advisor/src/Core/CompilationUnit.cpp @@ -1,6 +1,23 @@ +//===---------------- CompilationUnit.cpp - LLVM Advisor ------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This is the CompilationUnit code generator driver. It provides a convenient +// command-line interface for generating an assembly file or a relocatable file, +// given LLVM bitcode. +// +//===----------------------------------------------------------------------===// + #include "CompilationUnit.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" +#include namespace llvm { namespace advisor { @@ -9,9 +26,9 @@ CompilationUnit::CompilationUnit(const CompilationUnitInfo &info, const std::string &workDir) : info_(info), workDir_(workDir) { // Create unit-specific data directory - SmallString<128> dataDir; - sys::path::append(dataDir, workDir, "units", info.name); - sys::fs::create_directories(dataDir); + llvm::SmallString<128> dataDir; + llvm::sys::path::append(dataDir, workDir, "units", info.name); + llvm::sys::fs::create_directories(dataDir); } std::string CompilationUnit::getPrimarySource() const { @@ -22,8 +39,8 @@ std::string CompilationUnit::getPrimarySource() const { } std::string CompilationUnit::getDataDir() const { - SmallString<128> dataDir; - sys::path::append(dataDir, workDir_, "units", info_.name); + llvm::SmallString<128> dataDir; + llvm::sys::path::append(dataDir, workDir_, "units", info_.name); return dataDir.str().str(); } @@ -31,33 +48,34 @@ std::string CompilationUnit::getExecutablePath() const { return info_.outputExecutable; } -void CompilationUnit::addGeneratedFile(const std::string &type, - const std::string &path) { - generatedFiles_[type].push_back(path); +void CompilationUnit::addGeneratedFile(llvm::StringRef type, + llvm::StringRef path) { + generatedFiles_[type.str()].push_back(path.str()); } -bool CompilationUnit::hasGeneratedFiles(const std::string &type) const { +bool CompilationUnit::hasGeneratedFiles(llvm::StringRef type) const { if (type.empty()) { return !generatedFiles_.empty(); } - auto it = generatedFiles_.find(type); + auto it = generatedFiles_.find(type.str()); return it != generatedFiles_.end() && !it->second.empty(); } -std::vector -CompilationUnit::getGeneratedFiles(const std::string &type) const { +llvm::SmallVector +CompilationUnit::getGeneratedFiles(llvm::StringRef type) const { if (type.empty()) { - std::vector allFiles; + llvm::SmallVector allFiles; for (const auto &pair : generatedFiles_) { - allFiles.insert(allFiles.end(), pair.second.begin(), pair.second.end()); + allFiles.append(pair.second.begin(), pair.second.end()); } return allFiles; } - auto it = generatedFiles_.find(type); - return it != generatedFiles_.end() ? it->second : std::vector(); + auto it = generatedFiles_.find(type.str()); + return it != generatedFiles_.end() ? it->second + : llvm::SmallVector(); } -const std::unordered_map> & +const std::unordered_map> & CompilationUnit::getAllGeneratedFiles() const { return generatedFiles_; } diff --git a/llvm/tools/llvm-advisor/src/Core/CompilationUnit.h b/llvm/tools/llvm-advisor/src/Core/CompilationUnit.h index 18dbc35ab5aec..08461e68e3307 100644 --- a/llvm/tools/llvm-advisor/src/Core/CompilationUnit.h +++ b/llvm/tools/llvm-advisor/src/Core/CompilationUnit.h @@ -1,10 +1,25 @@ -#ifndef LLVM_ADVISOR_COMPILATION_UNIT_H -#define LLVM_ADVISOR_COMPILATION_UNIT_H +//===------------------- CompilationUnit.h - LLVM Advisor -----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This is the CompilationUnit code generator driver. It provides a convenient +// command-line interface for generating an assembly file or a relocatable file, +// given LLVM bitcode. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_ADVISOR_CORE_COMPILATIONUNIT_H +#define LLVM_ADVISOR_CORE_COMPILATIONUNIT_H +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" #include #include -#include namespace llvm { namespace advisor { @@ -13,13 +28,13 @@ struct SourceFile { std::string path; std::string language; bool isHeader = false; - std::vector dependencies; + llvm::SmallVector dependencies; }; struct CompilationUnitInfo { std::string name; - std::vector sources; - std::vector compileFlags; + llvm::SmallVector sources; + llvm::SmallVector compileFlags; std::string targetArch; bool hasOffloading = false; std::string outputObject; @@ -38,21 +53,22 @@ class CompilationUnit { std::string getDataDir() const; std::string getExecutablePath() const; - void addGeneratedFile(const std::string &type, const std::string &path); + void addGeneratedFile(llvm::StringRef type, llvm::StringRef path); - bool hasGeneratedFiles(const std::string &type) const; - std::vector - getGeneratedFiles(const std::string &type = "") const; - const std::unordered_map> & + bool hasGeneratedFiles(llvm::StringRef type) const; + llvm::SmallVector + getGeneratedFiles(llvm::StringRef type = "") const; + const std::unordered_map> & getAllGeneratedFiles() const; private: CompilationUnitInfo info_; std::string workDir_; - std::unordered_map> generatedFiles_; + std::unordered_map> + generatedFiles_; }; } // namespace advisor } // namespace llvm -#endif \ No newline at end of file +#endif // LLVM_ADVISOR_CORE_COMPILATIONUNIT_H \ No newline at end of file diff --git a/llvm/tools/llvm-advisor/src/Core/DataExtractor.cpp b/llvm/tools/llvm-advisor/src/Core/DataExtractor.cpp index 4d709e4a6d51c..db76f436520f0 100644 --- a/llvm/tools/llvm-advisor/src/Core/DataExtractor.cpp +++ b/llvm/tools/llvm-advisor/src/Core/DataExtractor.cpp @@ -1,367 +1,398 @@ -#include "DataExtractor.h" -#include "../Utils/ProcessRunner.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/raw_ostream.h" -#include - -namespace llvm { -namespace advisor { - -DataExtractor::DataExtractor(const AdvisorConfig &config) : config_(config) {} - -Error DataExtractor::extractAllData(CompilationUnit &unit, - const std::string &tempDir) { - if (config_.getVerbose()) { - outs() << "Extracting data for unit: " << unit.getName() << "\n"; - } - - // Create extraction subdirectories - sys::fs::create_directories(tempDir + "/ir"); - sys::fs::create_directories(tempDir + "/assembly"); - sys::fs::create_directories(tempDir + "/ast"); - sys::fs::create_directories(tempDir + "/preprocessed"); - sys::fs::create_directories(tempDir + "/include-tree"); - sys::fs::create_directories(tempDir + "/debug"); - sys::fs::create_directories(tempDir + "/static-analyzer"); - - if (auto Err = extractIR(unit, tempDir)) - return Err; - if (auto Err = extractAssembly(unit, tempDir)) - return Err; - if (auto Err = extractAST(unit, tempDir)) - return Err; - if (auto Err = extractPreprocessed(unit, tempDir)) - return Err; - if (auto Err = extractIncludeTree(unit, tempDir)) - return Err; - if (auto Err = extractDebugInfo(unit, tempDir)) - return Err; - if (auto Err = extractStaticAnalysis(unit, tempDir)) - return Err; - if (auto Err = extractMacroExpansion(unit, tempDir)) - return Err; - if (auto Err = extractCompilationPhases(unit, tempDir)) - return Err; - - return Error::success(); -} - -std::vector -DataExtractor::getBaseCompilerArgs(const CompilationUnitInfo &unitInfo) const { - std::vector baseArgs; - - // Copy include paths and defines - for (const auto &arg : unitInfo.compileFlags) { - if (StringRef(arg).starts_with("-I") || StringRef(arg).starts_with("-D") || - StringRef(arg).starts_with("-U") || - StringRef(arg).starts_with("-std=") || - StringRef(arg).starts_with("-m") || StringRef(arg).starts_with("-f") || - StringRef(arg).starts_with("-W") || StringRef(arg).starts_with("-O")) { - // Skip problematic flags for extraction - if (StringRef(arg).starts_with("-fsave-optimization-record") || - StringRef(arg).starts_with("-fprofile-instr-generate") || - StringRef(arg).starts_with("-fcoverage-mapping") || - StringRef(arg).starts_with("-foptimization-record-file")) { - continue; - } - baseArgs.push_back(arg); - } - } - - return baseArgs; -} - -Error DataExtractor::extractIR(CompilationUnit &unit, - const std::string &tempDir) { - for (const auto &source : unit.getInfo().sources) { - if (source.isHeader) - continue; - - std::string outputFile = - tempDir + "/ir/" + sys::path::stem(source.path).str() + ".ll"; - - auto baseArgs = getBaseCompilerArgs(unit.getInfo()); - baseArgs.push_back("-emit-llvm"); - baseArgs.push_back("-S"); - baseArgs.push_back("-o"); - baseArgs.push_back(outputFile); - baseArgs.push_back(source.path); - - if (auto Err = runCompilerWithFlags(baseArgs)) { - if (config_.getVerbose()) { - errs() << "Failed to extract IR for " << source.path << "\n"; - } - continue; - } - - if (sys::fs::exists(outputFile)) { - unit.addGeneratedFile("ir", outputFile); - } - } - return Error::success(); -} - -Error DataExtractor::extractAssembly(CompilationUnit &unit, - const std::string &tempDir) { - for (const auto &source : unit.getInfo().sources) { - if (source.isHeader) - continue; - - std::string outputFile = - tempDir + "/assembly/" + sys::path::stem(source.path).str() + ".s"; - - auto baseArgs = getBaseCompilerArgs(unit.getInfo()); - baseArgs.push_back("-S"); - baseArgs.push_back("-o"); - baseArgs.push_back(outputFile); - baseArgs.push_back(source.path); - - if (auto Err = runCompilerWithFlags(baseArgs)) { - if (config_.getVerbose()) { - errs() << "Failed to extract assembly for " << source.path << "\n"; - } - continue; - } - - if (sys::fs::exists(outputFile)) { - unit.addGeneratedFile("assembly", outputFile); - } - } - return Error::success(); -} - -Error DataExtractor::extractAST(CompilationUnit &unit, - const std::string &tempDir) { - for (const auto &source : unit.getInfo().sources) { - if (source.isHeader) - continue; - - std::string outputFile = - tempDir + "/ast/" + sys::path::stem(source.path).str() + ".ast"; - - auto baseArgs = getBaseCompilerArgs(unit.getInfo()); - baseArgs.push_back("-ast-dump"); - baseArgs.push_back("-fsyntax-only"); - baseArgs.push_back(source.path); - - auto result = ProcessRunner::run(config_.getToolPath("clang"), baseArgs, - config_.getTimeout()); - if (result && result->exitCode == 0) { - std::error_code EC; - raw_fd_ostream OS(outputFile, EC); - if (!EC) { - OS << result->stdout; - unit.addGeneratedFile("ast", outputFile); - } - } - } - return Error::success(); -} - -Error DataExtractor::extractPreprocessed(CompilationUnit &unit, - const std::string &tempDir) { - for (const auto &source : unit.getInfo().sources) { - if (source.isHeader) - continue; - - std::string ext = (source.language == "C++") ? ".ii" : ".i"; - std::string outputFile = - tempDir + "/preprocessed/" + sys::path::stem(source.path).str() + ext; - - auto baseArgs = getBaseCompilerArgs(unit.getInfo()); - baseArgs.push_back("-E"); - baseArgs.push_back("-o"); - baseArgs.push_back(outputFile); - baseArgs.push_back(source.path); - - if (auto Err = runCompilerWithFlags(baseArgs)) { - if (config_.getVerbose()) { - errs() << "Failed to extract preprocessed for " << source.path << "\n"; - } - continue; - } - - if (sys::fs::exists(outputFile)) { - unit.addGeneratedFile("preprocessed", outputFile); - } - } - return Error::success(); -} - -Error DataExtractor::extractIncludeTree(CompilationUnit &unit, - const std::string &tempDir) { - for (const auto &source : unit.getInfo().sources) { - if (source.isHeader) - continue; - - std::string outputFile = tempDir + "/include-tree/" + - sys::path::stem(source.path).str() + - ".include.txt"; - - auto baseArgs = getBaseCompilerArgs(unit.getInfo()); - baseArgs.push_back("-H"); - baseArgs.push_back("-fsyntax-only"); - baseArgs.push_back(source.path); - - auto result = ProcessRunner::run(config_.getToolPath("clang"), baseArgs, - config_.getTimeout()); - if (result && !result->stderr.empty()) { - std::error_code EC; - raw_fd_ostream OS(outputFile, EC); - if (!EC) { - OS << result->stderr; // Include tree goes to stderr - unit.addGeneratedFile("include-tree", outputFile); - } - } - } - return Error::success(); -} - -Error DataExtractor::extractDebugInfo(CompilationUnit &unit, - const std::string &tempDir) { - for (const auto &source : unit.getInfo().sources) { - if (source.isHeader) - continue; - - std::string outputFile = - tempDir + "/debug/" + sys::path::stem(source.path).str() + ".debug.txt"; - std::string objectFile = - tempDir + "/debug/" + sys::path::stem(source.path).str() + ".o"; - - auto baseArgs = getBaseCompilerArgs(unit.getInfo()); - baseArgs.push_back("-g"); - baseArgs.push_back("-c"); - baseArgs.push_back("-o"); - baseArgs.push_back(objectFile); - baseArgs.push_back(source.path); - - if (auto Err = runCompilerWithFlags(baseArgs)) { - if (config_.getVerbose()) { - errs() << "Failed to extract debug info for " << source.path << "\n"; - } - continue; - } - - // Extract DWARF info using llvm-dwarfdump - if (sys::fs::exists(objectFile)) { - std::vector dwarfArgs = {objectFile}; - auto result = - ProcessRunner::run("llvm-dwarfdump", dwarfArgs, config_.getTimeout()); - if (result && result->exitCode == 0) { - std::error_code EC; - raw_fd_ostream OS(outputFile, EC); - if (!EC) { - OS << result->stdout; - unit.addGeneratedFile("debug", outputFile); - } - } - } - } - return Error::success(); -} - -Error DataExtractor::extractStaticAnalysis(CompilationUnit &unit, - const std::string &tempDir) { - for (const auto &source : unit.getInfo().sources) { - if (source.isHeader) - continue; - - std::string outputFile = tempDir + "/static-analyzer/" + - sys::path::stem(source.path).str() + - ".analysis.txt"; - - auto baseArgs = getBaseCompilerArgs(unit.getInfo()); - baseArgs.push_back("--analyze"); - baseArgs.push_back("-Xanalyzer"); - baseArgs.push_back("-analyzer-output=text"); - baseArgs.push_back(source.path); - - auto result = ProcessRunner::run(config_.getToolPath("clang"), baseArgs, - config_.getTimeout()); - if (result) { - std::error_code EC; - raw_fd_ostream OS(outputFile, EC); - if (!EC) { - OS << "STDOUT:\n" << result->stdout << "\nSTDERR:\n" << result->stderr; - unit.addGeneratedFile("static-analyzer", outputFile); - } - } - } - return Error::success(); -} - -Error DataExtractor::extractMacroExpansion(CompilationUnit &unit, - const std::string &tempDir) { - for (const auto &source : unit.getInfo().sources) { - if (source.isHeader) - continue; - - std::string outputFile = - tempDir + "/preprocessed/" + sys::path::stem(source.path).str() + - ".macro-expanded" + ((source.language == "C++") ? ".ii" : ".i"); - - auto baseArgs = getBaseCompilerArgs(unit.getInfo()); - baseArgs.push_back("-E"); - baseArgs.push_back("-dM"); // Show macro definitions - baseArgs.push_back("-o"); - baseArgs.push_back(outputFile); - baseArgs.push_back(source.path); - - if (auto Err = runCompilerWithFlags(baseArgs)) { - if (config_.getVerbose()) { - errs() << "Failed to extract macro expansion for " << source.path - << "\n"; - } - continue; - } - - if (sys::fs::exists(outputFile)) { - unit.addGeneratedFile("macro-expansion", outputFile); - } - } - return Error::success(); -} - -Error DataExtractor::extractCompilationPhases(CompilationUnit &unit, - const std::string &tempDir) { - for (const auto &source : unit.getInfo().sources) { - if (source.isHeader) - continue; - - std::string outputFile = tempDir + "/debug/" + - sys::path::stem(source.path).str() + ".phases.txt"; - - auto baseArgs = getBaseCompilerArgs(unit.getInfo()); - baseArgs.push_back("-v"); // Verbose compilation phases - baseArgs.push_back("-fsyntax-only"); - baseArgs.push_back(source.path); - - auto result = ProcessRunner::run(config_.getToolPath("clang"), baseArgs, - config_.getTimeout()); - if (result) { - std::error_code EC; - raw_fd_ostream OS(outputFile, EC); - if (!EC) { - OS << "COMPILATION PHASES:\n" - << result->stderr; // Verbose output goes to stderr - unit.addGeneratedFile("compilation-phases", outputFile); - } - } - } - return Error::success(); -} - -Error DataExtractor::runCompilerWithFlags( - const std::vector &args) { - auto result = ProcessRunner::run(config_.getToolPath("clang"), args, - config_.getTimeout()); - if (!result || result->exitCode != 0) { - return createStringError(std::make_error_code(std::errc::io_error), - "Compiler failed"); - } - return Error::success(); -} - -} // namespace advisor -} // namespace llvm +//===------------------ DataExtractor.cpp - LLVM Advisor ------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This is the DataExtractor code generator driver. It provides a convenient +// command-line interface for generating an assembly file or a relocatable file, +// given LLVM bitcode. +// +//===----------------------------------------------------------------------===// + +#include "DataExtractor.h" +#include "../Utils/ProcessRunner.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" +#include + +namespace llvm { +namespace advisor { + +DataExtractor::DataExtractor(const AdvisorConfig &config) : config_(config) {} + +Error DataExtractor::extractAllData(CompilationUnit &unit, + llvm::StringRef tempDir) { + if (config_.getVerbose()) { + outs() << "Extracting data for unit: " << unit.getName() << "\n"; + } + + // Create extraction subdirectories + sys::fs::create_directories(tempDir + "/ir"); + sys::fs::create_directories(tempDir + "/assembly"); + sys::fs::create_directories(tempDir + "/ast"); + sys::fs::create_directories(tempDir + "/preprocessed"); + sys::fs::create_directories(tempDir + "/include-tree"); + sys::fs::create_directories(tempDir + "/debug"); + sys::fs::create_directories(tempDir + "/static-analyzer"); + + if (auto Err = extractIR(unit, tempDir)) + return Err; + if (auto Err = extractAssembly(unit, tempDir)) + return Err; + if (auto Err = extractAST(unit, tempDir)) + return Err; + if (auto Err = extractPreprocessed(unit, tempDir)) + return Err; + if (auto Err = extractIncludeTree(unit, tempDir)) + return Err; + if (auto Err = extractDebugInfo(unit, tempDir)) + return Err; + if (auto Err = extractStaticAnalysis(unit, tempDir)) + return Err; + if (auto Err = extractMacroExpansion(unit, tempDir)) + return Err; + if (auto Err = extractCompilationPhases(unit, tempDir)) + return Err; + + return Error::success(); +} + +llvm::SmallVector +DataExtractor::getBaseCompilerArgs(const CompilationUnitInfo &unitInfo) const { + llvm::SmallVector baseArgs; + + // Copy include paths and defines + for (const auto &arg : unitInfo.compileFlags) { + if (StringRef(arg).starts_with("-I") || StringRef(arg).starts_with("-D") || + StringRef(arg).starts_with("-U") || + StringRef(arg).starts_with("-std=") || + StringRef(arg).starts_with("-m") || StringRef(arg).starts_with("-f") || + StringRef(arg).starts_with("-W") || StringRef(arg).starts_with("-O")) { + // Skip problematic flags for extraction + if (StringRef(arg).starts_with("-fsave-optimization-record") || + StringRef(arg).starts_with("-fprofile-instr-generate") || + StringRef(arg).starts_with("-fcoverage-mapping") || + StringRef(arg).starts_with("-foptimization-record-file")) { + continue; + } + baseArgs.push_back(arg); + } + } + + return baseArgs; +} + +Error DataExtractor::extractIR(CompilationUnit &unit, llvm::StringRef tempDir) { + for (const auto &source : unit.getInfo().sources) { + if (source.isHeader) + continue; + + std::string outputFile = + (tempDir + "/ir/" + sys::path::stem(source.path).str() + ".ll").str(); + + llvm::SmallVector baseArgs = + getBaseCompilerArgs(unit.getInfo()); + baseArgs.push_back("-emit-llvm"); + baseArgs.push_back("-S"); + baseArgs.push_back("-o"); + baseArgs.push_back(outputFile); + baseArgs.push_back(source.path); + + if (auto Err = runCompilerWithFlags(baseArgs)) { + if (config_.getVerbose()) { + errs() << "Failed to extract IR for " << source.path << "\n"; + } + continue; + } + + if (sys::fs::exists(outputFile)) { + unit.addGeneratedFile("ir", outputFile); + } + } + return Error::success(); +} + +Error DataExtractor::extractAssembly(CompilationUnit &unit, + llvm::StringRef tempDir) { + for (const auto &source : unit.getInfo().sources) { + if (source.isHeader) + continue; + + std::string outputFile = + (tempDir + "/assembly/" + sys::path::stem(source.path).str() + ".s") + .str(); + + llvm::SmallVector baseArgs = + getBaseCompilerArgs(unit.getInfo()); + baseArgs.push_back("-S"); + baseArgs.push_back("-o"); + baseArgs.push_back(outputFile); + baseArgs.push_back(source.path); + + if (auto Err = runCompilerWithFlags(baseArgs)) { + if (config_.getVerbose()) { + errs() << "Failed to extract assembly for " << source.path << "\n"; + } + continue; + } + + if (sys::fs::exists(outputFile)) { + unit.addGeneratedFile("assembly", outputFile); + } + } + return Error::success(); +} + +Error DataExtractor::extractAST(CompilationUnit &unit, + llvm::StringRef tempDir) { + for (const auto &source : unit.getInfo().sources) { + if (source.isHeader) + continue; + + std::string outputFile = + (tempDir + "/ast/" + sys::path::stem(source.path).str() + ".ast").str(); + + llvm::SmallVector baseArgs = + getBaseCompilerArgs(unit.getInfo()); + baseArgs.push_back("-ast-dump"); + baseArgs.push_back("-fsyntax-only"); + baseArgs.push_back(source.path); + + auto result = ProcessRunner::run(config_.getToolPath("clang"), baseArgs, + config_.getTimeout()); + if (result && result->exitCode == 0) { + std::error_code EC; + raw_fd_ostream OS(outputFile, EC); + if (!EC) { + OS << result->stdout; + unit.addGeneratedFile("ast", outputFile); + } + } + } + return Error::success(); +} + +Error DataExtractor::extractPreprocessed(CompilationUnit &unit, + llvm::StringRef tempDir) { + for (const auto &source : unit.getInfo().sources) { + if (source.isHeader) + continue; + + std::string ext = (source.language == "C++") ? ".ii" : ".i"; + std::string outputFile = + (tempDir + "/preprocessed/" + sys::path::stem(source.path).str() + ext) + .str(); + + llvm::SmallVector baseArgs = + getBaseCompilerArgs(unit.getInfo()); + baseArgs.push_back("-E"); + baseArgs.push_back("-o"); + baseArgs.push_back(outputFile); + baseArgs.push_back(source.path); + + if (auto Err = runCompilerWithFlags(baseArgs)) { + if (config_.getVerbose()) { + errs() << "Failed to extract preprocessed for " << source.path << "\n"; + } + continue; + } + + if (sys::fs::exists(outputFile)) { + unit.addGeneratedFile("preprocessed", outputFile); + } + } + return Error::success(); +} + +Error DataExtractor::extractIncludeTree(CompilationUnit &unit, + llvm::StringRef tempDir) { + for (const auto &source : unit.getInfo().sources) { + if (source.isHeader) + continue; + + std::string outputFile = + (tempDir + "/include-tree/" + sys::path::stem(source.path).str() + + ".include.txt") + .str(); + + llvm::SmallVector baseArgs = + getBaseCompilerArgs(unit.getInfo()); + baseArgs.push_back("-H"); + baseArgs.push_back("-fsyntax-only"); + baseArgs.push_back(source.path); + + auto result = ProcessRunner::run(config_.getToolPath("clang"), baseArgs, + config_.getTimeout()); + if (result && !result->stderr.empty()) { + std::error_code EC; + raw_fd_ostream OS(outputFile, EC); + if (!EC) { + OS << result->stderr; // Include tree goes to stderr + unit.addGeneratedFile("include-tree", outputFile); + } + } + } + return Error::success(); +} + +Error DataExtractor::extractDebugInfo(CompilationUnit &unit, + llvm::StringRef tempDir) { + for (const auto &source : unit.getInfo().sources) { + if (source.isHeader) + continue; + + std::string outputFile = (tempDir + "/debug/" + + sys::path::stem(source.path).str() + ".debug.txt") + .str(); + std::string objectFile = + (tempDir + "/debug/" + sys::path::stem(source.path).str() + ".o").str(); + + llvm::SmallVector baseArgs = + getBaseCompilerArgs(unit.getInfo()); + baseArgs.push_back("-g"); + baseArgs.push_back("-c"); + baseArgs.push_back("-o"); + baseArgs.push_back(objectFile); + baseArgs.push_back(source.path); + + if (auto Err = runCompilerWithFlags(baseArgs)) { + if (config_.getVerbose()) { + errs() << "Failed to extract debug info for " << source.path << "\n"; + } + continue; + } + + // Extract DWARF info using llvm-dwarfdump + if (sys::fs::exists(objectFile)) { + llvm::SmallVector dwarfArgs = {objectFile}; + auto result = + ProcessRunner::run("llvm-dwarfdump", dwarfArgs, config_.getTimeout()); + if (result && result->exitCode == 0) { + std::error_code EC; + raw_fd_ostream OS(outputFile, EC); + if (!EC) { + OS << result->stdout; + unit.addGeneratedFile("debug", outputFile); + } + } + } + } + return Error::success(); +} + +Error DataExtractor::extractStaticAnalysis(CompilationUnit &unit, + llvm::StringRef tempDir) { + for (const auto &source : unit.getInfo().sources) { + if (source.isHeader) + continue; + + std::string outputFile = + (tempDir + "/static-analyzer/" + sys::path::stem(source.path).str() + + ".analysis.txt") + .str(); + + llvm::SmallVector baseArgs = + getBaseCompilerArgs(unit.getInfo()); + baseArgs.push_back("--analyze"); + baseArgs.push_back("-Xanalyzer"); + baseArgs.push_back("-analyzer-output=text"); + baseArgs.push_back(source.path); + + auto result = ProcessRunner::run(config_.getToolPath("clang"), baseArgs, + config_.getTimeout()); + if (result) { + std::error_code EC; + raw_fd_ostream OS(outputFile, EC); + if (!EC) { + OS << "STDOUT:\n" << result->stdout << "\nSTDERR:\n" << result->stderr; + unit.addGeneratedFile("static-analyzer", outputFile); + } + } + } + return Error::success(); +} + +Error DataExtractor::extractMacroExpansion(CompilationUnit &unit, + llvm::StringRef tempDir) { + for (const auto &source : unit.getInfo().sources) { + if (source.isHeader) + continue; + + std::string outputFile = + (tempDir + "/preprocessed/" + sys::path::stem(source.path).str() + + ".macro-expanded" + ((source.language == "C++") ? ".ii" : ".i")) + .str(); + + llvm::SmallVector baseArgs = + getBaseCompilerArgs(unit.getInfo()); + baseArgs.push_back("-E"); + baseArgs.push_back("-dM"); // Show macro definitions + baseArgs.push_back("-o"); + baseArgs.push_back(outputFile); + baseArgs.push_back(source.path); + + if (auto Err = runCompilerWithFlags(baseArgs)) { + if (config_.getVerbose()) { + errs() << "Failed to extract macro expansion for " << source.path + << "\n"; + } + continue; + } + + if (sys::fs::exists(outputFile)) { + unit.addGeneratedFile("macro-expansion", outputFile); + } + } + return Error::success(); +} + +Error DataExtractor::extractCompilationPhases(CompilationUnit &unit, + llvm::StringRef tempDir) { + for (const auto &source : unit.getInfo().sources) { + if (source.isHeader) + continue; + + std::string outputFile = + (tempDir + "/debug/" + sys::path::stem(source.path).str() + + ".phases.txt") + .str(); + + llvm::SmallVector baseArgs = + getBaseCompilerArgs(unit.getInfo()); + baseArgs.push_back("-v"); // Verbose compilation phases + baseArgs.push_back("-fsyntax-only"); + baseArgs.push_back(source.path); + + auto result = ProcessRunner::run(config_.getToolPath("clang"), baseArgs, + config_.getTimeout()); + if (result) { + std::error_code EC; + raw_fd_ostream OS(outputFile, EC); + if (!EC) { + OS << "COMPILATION PHASES:\n" + << result->stderr; // Verbose output goes to stderr + unit.addGeneratedFile("compilation-phases", outputFile); + } + } + } + return Error::success(); +} + +Error DataExtractor::runCompilerWithFlags( + const llvm::SmallVector &args) { + auto result = ProcessRunner::run(config_.getToolPath("clang"), args, + config_.getTimeout()); + if (!result || result->exitCode != 0) { + return createStringError(std::make_error_code(std::errc::io_error), + "Compiler failed"); + } + return Error::success(); +} + +} // namespace advisor +} // namespace llvm \ No newline at end of file diff --git a/llvm/tools/llvm-advisor/src/Core/DataExtractor.h b/llvm/tools/llvm-advisor/src/Core/DataExtractor.h index 7564660ed05b9..633778c35b306 100644 --- a/llvm/tools/llvm-advisor/src/Core/DataExtractor.h +++ b/llvm/tools/llvm-advisor/src/Core/DataExtractor.h @@ -1,44 +1,56 @@ -#ifndef LLVM_ADVISOR_DATA_EXTRACTOR_H -#define LLVM_ADVISOR_DATA_EXTRACTOR_H - -#include "../Config/AdvisorConfig.h" -#include "CompilationUnit.h" -#include "llvm/Support/Error.h" -#include -#include - -namespace llvm { -namespace advisor { - -class DataExtractor { -public: - DataExtractor(const AdvisorConfig &config); - - Error extractAllData(CompilationUnit &unit, const std::string &tempDir); - -private: - std::vector - getBaseCompilerArgs(const CompilationUnitInfo &unitInfo) const; - - Error extractIR(CompilationUnit &unit, const std::string &tempDir); - Error extractAssembly(CompilationUnit &unit, const std::string &tempDir); - Error extractAST(CompilationUnit &unit, const std::string &tempDir); - Error extractPreprocessed(CompilationUnit &unit, const std::string &tempDir); - Error extractIncludeTree(CompilationUnit &unit, const std::string &tempDir); - Error extractDebugInfo(CompilationUnit &unit, const std::string &tempDir); - Error extractStaticAnalysis(CompilationUnit &unit, - const std::string &tempDir); - Error extractMacroExpansion(CompilationUnit &unit, - const std::string &tempDir); - Error extractCompilationPhases(CompilationUnit &unit, - const std::string &tempDir); - - Error runCompilerWithFlags(const std::vector &args); - - const AdvisorConfig &config_; -}; - -} // namespace advisor -} // namespace llvm - -#endif +//===------------------ DataExtractor.h - LLVM Advisor --------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This is the DataExtractor code generator driver. It provides a convenient +// command-line interface for generating an assembly file or a relocatable file, +// given LLVM bitcode. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_ADVISOR_DATA_EXTRACTOR_H +#define LLVM_ADVISOR_DATA_EXTRACTOR_H + +#include "../Config/AdvisorConfig.h" +#include "CompilationUnit.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Error.h" +#include + +namespace llvm { +namespace advisor { + +class DataExtractor { +public: + DataExtractor(const AdvisorConfig &config); + + Error extractAllData(CompilationUnit &unit, llvm::StringRef tempDir); + +private: + llvm::SmallVector + getBaseCompilerArgs(const CompilationUnitInfo &unitInfo) const; + + Error extractIR(CompilationUnit &unit, llvm::StringRef tempDir); + Error extractAssembly(CompilationUnit &unit, llvm::StringRef tempDir); + Error extractAST(CompilationUnit &unit, llvm::StringRef tempDir); + Error extractPreprocessed(CompilationUnit &unit, llvm::StringRef tempDir); + Error extractIncludeTree(CompilationUnit &unit, llvm::StringRef tempDir); + Error extractDebugInfo(CompilationUnit &unit, llvm::StringRef tempDir); + Error extractStaticAnalysis(CompilationUnit &unit, llvm::StringRef tempDir); + Error extractMacroExpansion(CompilationUnit &unit, llvm::StringRef tempDir); + Error extractCompilationPhases(CompilationUnit &unit, + llvm::StringRef tempDir); + + Error runCompilerWithFlags(const llvm::SmallVector &args); + + const AdvisorConfig &config_; +}; + +} // namespace advisor +} // namespace llvm + +#endif \ No newline at end of file diff --git a/llvm/tools/llvm-advisor/src/Detection/UnitDetector.cpp b/llvm/tools/llvm-advisor/src/Detection/UnitDetector.cpp index 16d24f7a61d8f..35492a4a1108b 100644 --- a/llvm/tools/llvm-advisor/src/Detection/UnitDetector.cpp +++ b/llvm/tools/llvm-advisor/src/Detection/UnitDetector.cpp @@ -1,5 +1,20 @@ +//===--------------------- UnitDetector.cpp - LLVM Advisor ----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This is the UnitDetector code generator driver. It provides a convenient +// command-line interface for generating an assembly file or a relocatable file, +// given LLVM bitcode. +// +//===----------------------------------------------------------------------===// + #include "UnitDetector.h" #include "llvm/ADT/Hashing.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/Support/Path.h" namespace llvm { @@ -7,14 +22,15 @@ namespace advisor { UnitDetector::UnitDetector(const AdvisorConfig &config) : config_(config) {} -Expected> -UnitDetector::detectUnits(const std::string &compiler, - const std::vector &args) { +llvm::Expected> +UnitDetector::detectUnits(llvm::StringRef compiler, + const llvm::SmallVectorImpl &args) { auto sources = findSourceFiles(args); if (sources.empty()) { - return createStringError(std::make_error_code(std::errc::invalid_argument), - "No source files found"); + return llvm::createStringError( + std::make_error_code(std::errc::invalid_argument), + "No source files found"); } CompilationUnitInfo unit; @@ -24,7 +40,7 @@ UnitDetector::detectUnits(const std::string &compiler, // Store original args but filter out source files for the compile flags for (const auto &arg : args) { // Skip source files when adding to compile flags - StringRef extension = sys::path::extension(arg); + llvm::StringRef extension = llvm::sys::path::extension(arg); if (!arg.empty() && arg[0] != '-' && (extension == ".c" || extension == ".cpp" || extension == ".cc" || extension == ".cxx" || extension == ".C")) { @@ -36,18 +52,18 @@ UnitDetector::detectUnits(const std::string &compiler, // Extract output files and features extractBuildInfo(args, unit); - return std::vector{unit}; + return llvm::SmallVector{unit}; } -std::vector -UnitDetector::findSourceFiles(const std::vector &args) const { - std::vector sources; +llvm::SmallVector UnitDetector::findSourceFiles( + const llvm::SmallVectorImpl &args) const { + llvm::SmallVector sources; for (const auto &arg : args) { if (arg.empty() || arg[0] == '-') continue; - StringRef extension = sys::path::extension(arg); + llvm::StringRef extension = llvm::sys::path::extension(arg); if (extension == ".c" || extension == ".cpp" || extension == ".cc" || extension == ".cxx" || extension == ".C") { @@ -62,14 +78,14 @@ UnitDetector::findSourceFiles(const std::vector &args) const { return sources; } -void UnitDetector::extractBuildInfo(const std::vector &args, - CompilationUnitInfo &unit) { +void UnitDetector::extractBuildInfo( + const llvm::SmallVectorImpl &args, CompilationUnitInfo &unit) { for (size_t i = 0; i < args.size(); ++i) { const auto &arg = args[i]; if (arg == "-o" && i + 1 < args.size()) { - StringRef output = args[i + 1]; - StringRef ext = sys::path::extension(output); + llvm::StringRef output = args[i + 1]; + llvm::StringRef ext = llvm::sys::path::extension(output); if (ext == ".o") { unit.outputObject = args[i + 1]; } else { @@ -77,25 +93,25 @@ void UnitDetector::extractBuildInfo(const std::vector &args, } } - if (arg.find("openmp") != std::string::npos || - arg.find("offload") != std::string::npos || - arg.find("cuda") != std::string::npos) { + llvm::StringRef argRef(arg); + if (argRef.contains("openmp") || argRef.contains("offload") || + argRef.contains("cuda")) { unit.hasOffloading = true; } - if (StringRef(arg).starts_with("-march=")) { + if (llvm::StringRef(arg).starts_with("-march=")) { unit.targetArch = arg.substr(7); } } } -std::string -UnitDetector::generateUnitName(const std::vector &sources) const { +std::string UnitDetector::generateUnitName( + const llvm::SmallVectorImpl &sources) const { if (sources.empty()) return "unknown"; // Use first source file name as base - std::string baseName = sys::path::stem(sources[0].path).str(); + std::string baseName = llvm::sys::path::stem(sources[0].path).str(); // Add hash for uniqueness when multiple sources if (sources.size() > 1) { @@ -103,7 +119,7 @@ UnitDetector::generateUnitName(const std::vector &sources) const { for (const auto &source : sources) { combined += source.path; } - auto hash = hash_value(combined); + auto hash = llvm::hash_value(combined); baseName += "_" + std::to_string(static_cast(hash) % 10000); } diff --git a/llvm/tools/llvm-advisor/src/Detection/UnitDetector.h b/llvm/tools/llvm-advisor/src/Detection/UnitDetector.h index 8ad998d3c4e7a..2c721726e14c5 100644 --- a/llvm/tools/llvm-advisor/src/Detection/UnitDetector.h +++ b/llvm/tools/llvm-advisor/src/Detection/UnitDetector.h @@ -1,11 +1,25 @@ -#ifndef LLVM_ADVISOR_UNIT_DETECTOR_H -#define LLVM_ADVISOR_UNIT_DETECTOR_H +//===------------------- UnitDetector.h - LLVM Advisor --------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This is the UnitDetector code generator driver. It provides a convenient +// command-line interface for generating an assembly file or a relocatable file, +// given LLVM bitcode. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_ADVISOR_DETECTION_UNITDETECTOR_H +#define LLVM_ADVISOR_DETECTION_UNITDETECTOR_H #include "../Config/AdvisorConfig.h" #include "../Core/CompilationUnit.h" #include "../Utils/FileClassifier.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/Support/Error.h" -#include +#include namespace llvm { namespace advisor { @@ -14,16 +28,17 @@ class UnitDetector { public: explicit UnitDetector(const AdvisorConfig &config); - Expected> - detectUnits(const std::string &compiler, - const std::vector &args); + llvm::Expected> + detectUnits(llvm::StringRef compiler, + const llvm::SmallVectorImpl &args); private: - std::vector - findSourceFiles(const std::vector &args) const; - void extractBuildInfo(const std::vector &args, + llvm::SmallVector + findSourceFiles(const llvm::SmallVectorImpl &args) const; + void extractBuildInfo(const llvm::SmallVectorImpl &args, CompilationUnitInfo &unit); - std::string generateUnitName(const std::vector &sources) const; + std::string + generateUnitName(const llvm::SmallVectorImpl &sources) const; const AdvisorConfig &config_; FileClassifier classifier_; @@ -32,4 +47,4 @@ class UnitDetector { } // namespace advisor } // namespace llvm -#endif +#endif // LLVM_ADVISOR_DETECTION_UNITDETECTOR_H diff --git a/llvm/tools/llvm-advisor/src/Utils/FileClassifier.cpp b/llvm/tools/llvm-advisor/src/Utils/FileClassifier.cpp index e9b39f984c771..8216221d7c271 100644 --- a/llvm/tools/llvm-advisor/src/Utils/FileClassifier.cpp +++ b/llvm/tools/llvm-advisor/src/Utils/FileClassifier.cpp @@ -1,3 +1,17 @@ +//===------------------- FileClassifier.cpp - LLVM Advisor ----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This is the FileClassifier code generator driver. It provides a convenient +// command-line interface for generating an assembly file or a relocatable file, +// given LLVM bitcode. +// +//===----------------------------------------------------------------------===// + #include "FileClassifier.h" #include "llvm/Support/Path.h" @@ -5,7 +19,7 @@ namespace llvm { namespace advisor { FileClassification -FileClassifier::classifyFile(const std::string &filePath) const { +FileClassifier::classifyFile(llvm::StringRef filePath) const { StringRef filename = sys::path::filename(filePath); StringRef extension = sys::path::extension(filePath); @@ -111,13 +125,13 @@ FileClassifier::classifyFile(const std::string &filePath) const { return classification; } -bool FileClassifier::shouldCollect(const std::string &filePath) const { +bool FileClassifier::shouldCollect(llvm::StringRef filePath) const { auto classification = classifyFile(filePath); return classification.category != "unknown" && classification.isGenerated && !classification.isTemporary; } -std::string FileClassifier::getLanguage(const std::string &filePath) const { +std::string FileClassifier::getLanguage(llvm::StringRef filePath) const { StringRef extension = sys::path::extension(filePath); if (extension == ".c") diff --git a/llvm/tools/llvm-advisor/src/Utils/FileClassifier.h b/llvm/tools/llvm-advisor/src/Utils/FileClassifier.h index 6bf7c43ba4ffc..d669a8c42324c 100644 --- a/llvm/tools/llvm-advisor/src/Utils/FileClassifier.h +++ b/llvm/tools/llvm-advisor/src/Utils/FileClassifier.h @@ -1,6 +1,20 @@ +//===----------------- FileClassifier.h - LLVM Advisor --------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This is the FileClassifier code generator driver. It provides a convenient +// command-line interface for generating an assembly file or a relocatable file, +// given LLVM bitcode. +// +//===----------------------------------------------------------------------===// #ifndef LLVM_ADVISOR_FILE_CLASSIFIER_H #define LLVM_ADVISOR_FILE_CLASSIFIER_H +#include "llvm/ADT/StringRef.h" #include namespace llvm { @@ -15,9 +29,9 @@ struct FileClassification { class FileClassifier { public: - FileClassification classifyFile(const std::string &filePath) const; - bool shouldCollect(const std::string &filePath) const; - std::string getLanguage(const std::string &filePath) const; + FileClassification classifyFile(llvm::StringRef filePath) const; + bool shouldCollect(llvm::StringRef filePath) const; + std::string getLanguage(llvm::StringRef filePath) const; }; } // namespace advisor diff --git a/llvm/tools/llvm-advisor/src/Utils/FileManager.cpp b/llvm/tools/llvm-advisor/src/Utils/FileManager.cpp index 7083d7edb7f3d..c0913032b5973 100644 --- a/llvm/tools/llvm-advisor/src/Utils/FileManager.cpp +++ b/llvm/tools/llvm-advisor/src/Utils/FileManager.cpp @@ -1,24 +1,37 @@ +//===------------------- FileManager.cpp - LLVM Advisor -------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This is the FileManager code generator driver. It provides a convenient +// command-line interface for generating an assembly file or a relocatable file, +// given LLVM bitcode. +// +//===----------------------------------------------------------------------===// + #include "FileManager.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" -#include +#include "llvm/ADT/SmallVector.h" namespace llvm { namespace advisor { -Expected FileManager::createTempDir(const std::string &prefix) { +Expected FileManager::createTempDir(llvm::StringRef prefix) { SmallString<128> tempDirPath; if (std::error_code ec = sys::fs::createUniqueDirectory(prefix, tempDirPath)) { return createStringError(ec, "Failed to create unique temporary directory"); } - return std::string(tempDirPath.str()); + return tempDirPath.str().str(); } -Error FileManager::copyDirectory(const std::string &source, - const std::string &dest) { +Error FileManager::copyDirectory(llvm::StringRef source, llvm::StringRef dest) { std::error_code EC; SmallString<128> sourcePathNorm(source); @@ -72,13 +85,13 @@ Error FileManager::copyDirectory(const std::string &source, return Error::success(); } -Error FileManager::removeDirectory(const std::string &path) { +Error FileManager::removeDirectory(llvm::StringRef path) { if (!sys::fs::exists(path)) { return Error::success(); } std::error_code EC; - std::vector Dirs; + SmallVector Dirs; for (sys::fs::recursive_directory_iterator I(path, EC), E; I != E && !EC; I.increment(EC)) { if (I->type() == sys::fs::file_type::directory_file) { @@ -108,9 +121,9 @@ Error FileManager::removeDirectory(const std::string &path) { return Error::success(); } -std::vector FileManager::findFiles(const std::string &directory, - const std::string &pattern) { - std::vector files; +SmallVector FileManager::findFiles(llvm::StringRef directory, + llvm::StringRef pattern) { + SmallVector files; std::error_code EC; for (sys::fs::recursive_directory_iterator I(directory, EC), E; I != E && !EC; I.increment(EC)) { @@ -124,10 +137,9 @@ std::vector FileManager::findFiles(const std::string &directory, return files; } -std::vector -FileManager::findFilesByExtension(const std::string &directory, - const std::vector &extensions) { - std::vector files; +SmallVector FileManager::findFilesByExtension( + llvm::StringRef directory, const SmallVector &extensions) { + SmallVector files; std::error_code EC; for (sys::fs::recursive_directory_iterator I(directory, EC), E; I != E && !EC; I.increment(EC)) { @@ -144,8 +156,7 @@ FileManager::findFilesByExtension(const std::string &directory, return files; } -Error FileManager::moveFile(const std::string &source, - const std::string &dest) { +Error FileManager::moveFile(llvm::StringRef source, llvm::StringRef dest) { if (source == dest) { return Error::success(); } @@ -172,8 +183,7 @@ Error FileManager::moveFile(const std::string &source, return Error::success(); } -Error FileManager::copyFile(const std::string &source, - const std::string &dest) { +Error FileManager::copyFile(llvm::StringRef source, llvm::StringRef dest) { if (source == dest) { return Error::success(); } @@ -192,7 +202,7 @@ Error FileManager::copyFile(const std::string &source, return Error::success(); } -Expected FileManager::getFileSize(const std::string &path) { +Expected FileManager::getFileSize(llvm::StringRef path) { sys::fs::file_status status; if (auto EC = sys::fs::status(path, status)) { return createStringError(EC, "File not found: " + path); diff --git a/llvm/tools/llvm-advisor/src/Utils/FileManager.h b/llvm/tools/llvm-advisor/src/Utils/FileManager.h index 07b49e647f542..9d52dc8485b1b 100644 --- a/llvm/tools/llvm-advisor/src/Utils/FileManager.h +++ b/llvm/tools/llvm-advisor/src/Utils/FileManager.h @@ -1,9 +1,23 @@ +//===-------------------- FileManager.h - LLVM Advisor --------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This is the FileManager code generator driver. It provides a convenient +// command-line interface for generating an assembly file or a relocatable file, +// given LLVM bitcode. +// +//===----------------------------------------------------------------------===// #ifndef LLVM_ADVISOR_FILE_MANAGER_H #define LLVM_ADVISOR_FILE_MANAGER_H +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" #include -#include namespace llvm { namespace advisor { @@ -12,32 +26,31 @@ class FileManager { public: /// Create unique temporary directory with pattern llvm-advisor-xxxxx static Expected - createTempDir(const std::string &prefix = "llvm-advisor"); + createTempDir(llvm::StringRef prefix = "llvm-advisor"); /// Recursively copy directory - static Error copyDirectory(const std::string &source, - const std::string &dest); + static Error copyDirectory(llvm::StringRef source, llvm::StringRef dest); /// Remove directory and contents - static Error removeDirectory(const std::string &path); + static Error removeDirectory(llvm::StringRef path); /// Find files matching pattern - static std::vector findFiles(const std::string &directory, - const std::string &pattern); + static llvm::SmallVector findFiles(llvm::StringRef directory, + llvm::StringRef pattern); /// Find files by extension - static std::vector - findFilesByExtension(const std::string &directory, - const std::vector &extensions); + static llvm::SmallVector + findFilesByExtension(llvm::StringRef directory, + const llvm::SmallVector &extensions); /// Move file from source to destination - static Error moveFile(const std::string &source, const std::string &dest); + static Error moveFile(llvm::StringRef source, llvm::StringRef dest); /// Copy file from source to destination - static Error copyFile(const std::string &source, const std::string &dest); + static Error copyFile(llvm::StringRef source, llvm::StringRef dest); /// Get file size - static Expected getFileSize(const std::string &path); + static Expected getFileSize(llvm::StringRef path); }; } // namespace advisor diff --git a/llvm/tools/llvm-advisor/src/Utils/ProcessRunner.cpp b/llvm/tools/llvm-advisor/src/Utils/ProcessRunner.cpp index b08b3cc88a434..6e09b0bcf552a 100644 --- a/llvm/tools/llvm-advisor/src/Utils/ProcessRunner.cpp +++ b/llvm/tools/llvm-advisor/src/Utils/ProcessRunner.cpp @@ -1,14 +1,31 @@ +//===-------------------- ProcessRunner.cpp - LLVM Advisor ----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This is the ProcessRunner code generator driver. It provides a convenient +// command-line interface for generating an assembly file or a relocatable file, +// given LLVM bitcode. +// +//===----------------------------------------------------------------------===// + #include "ProcessRunner.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/Program.h" +#include namespace llvm { namespace advisor { Expected -ProcessRunner::run(const std::string &program, - const std::vector &args, int timeoutSeconds) { +ProcessRunner::run(llvm::StringRef program, + const llvm::SmallVector &args, + int timeoutSeconds) { auto programPath = sys::findProgramByName(program); if (!programPath) { @@ -16,7 +33,7 @@ ProcessRunner::run(const std::string &program, "Tool not found: " + program); } - std::vector execArgs; + llvm::SmallVector execArgs; execArgs.push_back(program); for (const auto &arg : args) { execArgs.push_back(arg); @@ -57,8 +74,8 @@ ProcessRunner::run(const std::string &program, } Expected ProcessRunner::runWithEnv( - const std::string &program, const std::vector &args, - const std::vector &env, int timeoutSeconds) { + llvm::StringRef program, const llvm::SmallVector &args, + const llvm::SmallVector &env, int timeoutSeconds) { // For simplicity, just use the regular run method // Environment variables can be added later if needed diff --git a/llvm/tools/llvm-advisor/src/Utils/ProcessRunner.h b/llvm/tools/llvm-advisor/src/Utils/ProcessRunner.h index ffd0ef353ba16..0182257c25534 100644 --- a/llvm/tools/llvm-advisor/src/Utils/ProcessRunner.h +++ b/llvm/tools/llvm-advisor/src/Utils/ProcessRunner.h @@ -1,9 +1,22 @@ +//===------------------- ProcessRunner.h - LLVM Advisor -------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This is the ProcessRunner code generator driver. It provides a convenient +// command-line interface for generating an assembly file or a relocatable file, +// given LLVM bitcode. +// +//===----------------------------------------------------------------------===// #ifndef LLVM_ADVISOR_PROCESS_RUNNER_H #define LLVM_ADVISOR_PROCESS_RUNNER_H +#include "llvm/ADT/SmallVector.h" #include "llvm/Support/Error.h" #include -#include namespace llvm { namespace advisor { @@ -17,13 +30,13 @@ class ProcessRunner { double executionTime; }; - static Expected run(const std::string &program, - const std::vector &args, - int timeoutSeconds = 60); - static Expected - runWithEnv(const std::string &program, const std::vector &args, - const std::vector &env, int timeoutSeconds = 60); + run(llvm::StringRef program, const llvm::SmallVector &args, + int timeoutSeconds = 60); + + static Expected runWithEnv( + llvm::StringRef program, const llvm::SmallVector &args, + const llvm::SmallVector &env, int timeoutSeconds = 60); }; } // namespace advisor diff --git a/llvm/tools/llvm-advisor/src/llvm-advisor.cpp b/llvm/tools/llvm-advisor/src/llvm-advisor.cpp index 01c28ba53b95b..bcb4acf092ec0 100644 --- a/llvm/tools/llvm-advisor/src/llvm-advisor.cpp +++ b/llvm/tools/llvm-advisor/src/llvm-advisor.cpp @@ -1,40 +1,55 @@ +//===-------------- llvm-advisor.cpp - LLVM Advisor -----------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This is the llvm-advisor code generator driver. It provides a convenient +// command-line interface for generating an assembly file or a relocatable file, +// given LLVM bitcode. +// +//===----------------------------------------------------------------------===// + #include "Config/AdvisorConfig.h" #include "Core/CompilationManager.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/InitLLVM.h" #include "llvm/Support/raw_ostream.h" -using namespace llvm; -using namespace llvm::advisor; - -static cl::opt ConfigFile("config", cl::desc("Configuration file"), - cl::value_desc("filename")); -static cl::opt OutputDir("output-dir", - cl::desc("Output directory"), - cl::value_desc("directory")); -static cl::opt Verbose("verbose", cl::desc("Verbose output")); -static cl::opt KeepTemps("keep-temps", cl::desc("Keep temporary files")); -static cl::opt NoProfiler("no-profiler", cl::desc("Disable profiler")); +static llvm::cl::opt + ConfigFile("config", llvm::cl::desc("Configuration file"), + llvm::cl::value_desc("filename")); +static llvm::cl::opt OutputDir("output-dir", + llvm::cl::desc("Output directory"), + llvm::cl::value_desc("directory")); +static llvm::cl::opt Verbose("verbose", llvm::cl::desc("Verbose output")); +static llvm::cl::opt KeepTemps("keep-temps", + llvm::cl::desc("Keep temporary files")); +static llvm::cl::opt NoProfiler("no-profiler", + llvm::cl::desc("Disable profiler")); int main(int argc, char **argv) { - InitLLVM X(argc, argv); + llvm::InitLLVM X(argc, argv); // Parse llvm-advisor options until we find the compiler - std::vector advisorArgs; + llvm::SmallVector advisorArgs; advisorArgs.push_back(argv[0]); int compilerArgStart = 1; bool foundCompiler = false; for (int i = 1; i < argc; ++i) { - StringRef arg(argv[i]); + llvm::StringRef arg(argv[i]); if (arg.starts_with("--") || (arg.starts_with("-") && arg.size() > 1 && arg != "-")) { advisorArgs.push_back(argv[i]); if (arg == "--config" || arg == "--output-dir") { - if (i + 1 < argc && !StringRef(argv[i + 1]).starts_with("-")) { + if (i + 1 < argc && !llvm::StringRef(argv[i + 1]).starts_with("-")) { advisorArgs.push_back(argv[++i]); } } @@ -46,29 +61,31 @@ int main(int argc, char **argv) { } if (!foundCompiler) { - errs() << "Error: No compiler command provided.\n"; - errs() << "Usage: llvm-advisor [options] [compiler-args...]\n"; + llvm::errs() << "Error: No compiler command provided.\n"; + llvm::errs() + << "Usage: llvm-advisor [options] [compiler-args...]\n"; return 1; } // Parse llvm-advisor options - int advisorArgc = advisorArgs.size(); - cl::ParseCommandLineOptions(advisorArgc, - const_cast(advisorArgs.data()), - "LLVM Compilation Advisor"); + int advisorArgc = static_cast(advisorArgs.size()); + llvm::cl::ParseCommandLineOptions(advisorArgc, + const_cast(advisorArgs.data()), + "LLVM Compilation Advisor"); // Extract compiler and arguments std::string compiler = argv[compilerArgStart]; - std::vector compilerArgs; + llvm::SmallVector compilerArgs; for (int i = compilerArgStart + 1; i < argc; ++i) { compilerArgs.push_back(argv[i]); } // Configure advisor - AdvisorConfig config; + llvm::advisor::AdvisorConfig config; if (!ConfigFile.empty()) { if (auto Err = config.loadFromFile(ConfigFile).takeError()) { - errs() << "Error loading config: " << toString(std::move(Err)) << "\n"; + llvm::errs() << "Error loading config: " << llvm::toString(std::move(Err)) + << "\n"; return 1; } } @@ -84,28 +101,28 @@ int main(int argc, char **argv) { config.setRunProfiler(!NoProfiler); // Create output directory - if (auto EC = sys::fs::create_directories(config.getOutputDir())) { - errs() << "Error creating output directory: " << EC.message() << "\n"; + if (auto EC = llvm::sys::fs::create_directories(config.getOutputDir())) { + llvm::errs() << "Error creating output directory: " << EC.message() << "\n"; return 1; } if (config.getVerbose()) { - outs() << "LLVM Compilation Advisor\n"; - outs() << "Compiler: " << compiler << "\n"; - outs() << "Output: " << config.getOutputDir() << "\n"; + llvm::outs() << "LLVM Compilation Advisor\n"; + llvm::outs() << "Compiler: " << compiler << "\n"; + llvm::outs() << "Output: " << config.getOutputDir() << "\n"; } // Execute with data collection - CompilationManager manager(config); + llvm::advisor::CompilationManager manager(config); auto result = manager.executeWithDataCollection(compiler, compilerArgs); if (result) { if (config.getVerbose()) { - outs() << "Compilation completed (exit code: " << *result << ")\n"; + llvm::outs() << "Compilation completed (exit code: " << *result << ")\n"; } return *result; } else { - errs() << "Error: " << toString(result.takeError()) << "\n"; + llvm::errs() << "Error: " << llvm::toString(result.takeError()) << "\n"; return 1; } }