Files
concrete/compiler/lib/Support/LLVMEmitFile.cpp

126 lines
3.6 KiB
C++

// Part of the Concrete Compiler Project, under the BSD3 License with Zama
// Exceptions. See
// https://github.com/zama-ai/concrete-compiler-internal/blob/main/LICENSE.txt
// for license information.
#include <errno.h>
#include <llvm/IR/LegacyPassManager.h>
#include <llvm/MC/TargetRegistry.h>
#include <llvm/Support/Host.h>
#include <llvm/Support/ToolOutputFile.h>
#include <llvm/Target/TargetMachine.h>
#include <llvm/Target/TargetOptions.h>
#include <mlir/Support/FileUtilities.h>
#include <concretelang/Support/Error.h>
namespace mlir {
namespace concretelang {
using std::string;
using std::vector;
llvm::TargetMachine *getDefaultTargetMachine() {
auto TargetTriple = llvm::sys::getDefaultTargetTriple();
string Error;
auto Target = llvm::TargetRegistry::lookupTarget(TargetTriple, Error);
if (!Target) {
return nullptr;
}
auto CPU = "generic";
auto Features = "";
llvm::TargetOptions opt;
return Target->createTargetMachine(TargetTriple, CPU, Features, opt,
llvm::Reloc::PIC_);
}
llvm::Error emitObject(llvm::Module &module, string objectPath) {
auto targetMachine = getDefaultTargetMachine();
if (!targetMachine) {
return StreamStringError("No default target machine for object generation");
}
module.setDataLayout(targetMachine->createDataLayout());
string Error;
std::unique_ptr<llvm::ToolOutputFile> objectFile =
mlir::openOutputFile(objectPath, &Error);
if (!objectFile) {
return StreamStringError("Cannot create/open " + objectPath);
}
// The legacy PassManager is mandatory for final code generation.
// https://llvm.org/docs/NewPassManager.html#status-of-the-new-and-legacy-pass-managers
llvm::legacy::PassManager pm;
auto FileType = llvm::CGFT_ObjectFile;
if (targetMachine->addPassesToEmitFile(pm, objectFile->os(), nullptr,
FileType, false)) {
return StreamStringError("TheTargetMachine can't emit object file");
}
pm.run(module);
objectFile->os().flush();
objectFile->os().close();
objectFile->keep();
delete targetMachine;
return llvm::Error::success();
}
string linkerCmd(vector<string> objectsPath, string libraryPath, string linker,
llvm::Optional<vector<string>> extraArgs) {
string cmd = linker + libraryPath;
for (auto objectPath : objectsPath) {
cmd += " " + objectPath;
}
if (extraArgs.hasValue()) {
for (auto extraArg : extraArgs.getValue()) {
cmd += " " + extraArg;
}
}
cmd += " 2>&1"; // to keep stderr with popen
return cmd;
}
llvm::Error callCmd(string cmd) {
errno = 0;
FILE *fp = popen(cmd.c_str(), "r");
if (fp == NULL) {
return StreamStringError(strerror(errno))
<< "\nCannot call the linker: " << cmd;
}
string outputContent;
const int CHUNK_SIZE = 1024;
char chunk[CHUNK_SIZE];
while (fgets(chunk, CHUNK_SIZE, fp) != NULL) {
outputContent += chunk;
}
int status = pclose(fp);
if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
return llvm::Error::success();
} else if (status == -1) {
return StreamStringError("Cannot pclose: " + cmd);
} else {
return StreamStringError("Command failed:" + cmd + "\nCode:" +
std::to_string(status) + "\n" + outputContent);
}
}
llvm::Error emitLibrary(vector<string> objectsPath, string libraryPath,
string linker,
llvm::Optional<vector<string>> extraArgs) {
auto cmd = linkerCmd(objectsPath, libraryPath, linker, extraArgs);
return callCmd(cmd);
}
} // namespace concretelang
} // namespace mlir