// 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 #include #include #include #include #include #include #include #include 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 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 objectsPath, string libraryPath, string linker, llvm::Optional> 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 objectsPath, string libraryPath, string linker, llvm::Optional> extraArgs) { auto cmd = linkerCmd(objectsPath, libraryPath, linker, extraArgs); return callCmd(cmd); } } // namespace concretelang } // namespace mlir