aboutsummaryrefslogtreecommitdiffstats
path: root/yql/essentials/minikql/codegen/codegen.cpp
diff options
context:
space:
mode:
authorvvvv <vvvv@yandex-team.com>2024-11-07 04:19:26 +0300
committervvvv <vvvv@yandex-team.com>2024-11-07 04:29:50 +0300
commit2661be00f3bc47590fda9218bf0386d6355c8c88 (patch)
tree3d316c07519191283d31c5f537efc6aabb42a2f0 /yql/essentials/minikql/codegen/codegen.cpp
parentcf2a23963ac10add28c50cc114fbf48953eca5aa (diff)
downloadydb-2661be00f3bc47590fda9218bf0386d6355c8c88.tar.gz
Moved yql/minikql YQL-19206
init [nodiff:caesar] commit_hash:d1182ef7d430ccf7e4d37ed933c7126d7bd5d6e4
Diffstat (limited to 'yql/essentials/minikql/codegen/codegen.cpp')
-rw-r--r--yql/essentials/minikql/codegen/codegen.cpp753
1 files changed, 753 insertions, 0 deletions
diff --git a/yql/essentials/minikql/codegen/codegen.cpp b/yql/essentials/minikql/codegen/codegen.cpp
new file mode 100644
index 0000000000..a245702f05
--- /dev/null
+++ b/yql/essentials/minikql/codegen/codegen.cpp
@@ -0,0 +1,753 @@
+#include "codegen.h"
+Y_PRAGMA_DIAGNOSTIC_PUSH
+Y_PRAGMA("GCC diagnostic ignored \"-Wbitwise-instead-of-logical\"")
+#include "codegen_llvm_deps.h" // Y_IGNORE
+Y_PRAGMA_DIAGNOSTIC_POP
+#include <contrib/libs/re2/re2/re2.h>
+
+#include <util/generic/maybe.h>
+#include <util/generic/singleton.h>
+#include <util/generic/hash_set.h>
+#include <util/generic/hash.h>
+#include <util/generic/yexception.h>
+#include <util/generic/strbuf.h>
+#include <util/generic/string.h>
+#include <util/stream/format.h>
+#include <util/system/defaults.h>
+#include <util/system/platform.h>
+#include <util/datetime/base.h>
+
+typedef struct __emutls_control {
+ size_t size; /* size of the object in bytes */
+ size_t align; /* alignment of the object in bytes */
+ union {
+ uintptr_t index; /* data[index-1] is the object address */
+ void* address; /* object address, when in single thread env */
+ } object;
+ void* value; /* null or non-zero initial value for the object */
+} __emutls_control;
+
+#if defined(_msan_enabled_)
+extern "C" void* __emutls_get_address(__emutls_control* control);
+#endif
+
+class TTlsManager {
+public:
+ void* Add(const TString& name, size_t size, size_t align) {
+ //Cerr << "name: " << name << ", size: " << size << ", align: " << align << "\n";
+ auto pair = Tls_.insert(std::make_pair(name, __emutls_control()));
+ if (pair.second) {
+ Zero(pair.first->second);
+ pair.first->second.size = size;
+ pair.first->second.align = align;
+ }
+
+ return &pair.first->second;
+ }
+
+private:
+ THashMap<TString, __emutls_control> Tls_;
+};
+
+#if !defined(_win_) || defined(__clang__)
+extern "C" void __divti3();
+extern "C" void __fixdfti();
+extern "C" void __fixsfti();
+extern "C" void __fixunsdfti();
+extern "C" void __floattidf();
+extern "C" void __floattisf();
+extern "C" void __floatuntidf();
+extern "C" void __floatuntisf();
+extern "C" void __modti3();
+extern "C" void __muloti4();
+extern "C" void __udivti3();
+extern "C" void __umodti3();
+#else
+#include <yql/essentials/public/decimal/yql_decimal.h>
+#define CRT_HAS_128BIT
+#define INT_LIB_H
+#define COMPILER_RT_ABI
+typedef NYql::NDecimal::TInt128 ti_int;
+typedef NYql::NDecimal::TUint128 tu_int;
+
+typedef int si_int;
+typedef unsigned su_int;
+
+typedef long long di_int;
+typedef unsigned long long du_int;
+
+typedef union
+{
+ tu_int all;
+ struct
+ {
+ du_int low;
+ du_int high;
+ }s;
+} utwords;
+
+typedef union
+{
+ ti_int all;
+ struct
+ {
+ du_int low;
+ di_int high;
+ }s;
+} twords;
+
+typedef union
+{
+ du_int all;
+ struct
+ {
+ su_int low;
+ su_int high;
+ }s;
+} udwords;
+
+typedef union
+{
+ su_int u;
+ float f;
+} float_bits;
+
+typedef union
+{
+ udwords u;
+ double f;
+} double_bits;
+
+int __builtin_ctzll(ui64 value) {
+ DWORD trailing_zero = 0;
+ if (_BitScanForward64(&trailing_zero, value)) {
+ return trailing_zero;
+ } else {
+ return 64;
+ }
+}
+
+int __builtin_clzll(ui64 value) {
+ DWORD leading_zero = 0;
+ if (_BitScanReverse64(&leading_zero, value)) {
+ return 63 - leading_zero;
+ } else {
+ return 64;
+ }
+}
+
+#define __divti3 __divti3impl
+#define __udivmodti4 __udivmodti4impl
+#define __modti3 __modti3impl
+#define __clzti2 __clzti2impl
+#define __floattisf __floattisfimpl
+#define __floattidf __floattidfimpl
+
+#include <contrib/libs/cxxsupp/builtins/udivmodti4.c>
+#include <contrib/libs/cxxsupp/builtins/divti3.c>
+#include <contrib/libs/cxxsupp/builtins/modti3.c>
+#include <contrib/libs/cxxsupp/builtins/clzti2.c>
+#include <contrib/libs/cxxsupp/builtins/floattisf.c>
+#include <contrib/libs/cxxsupp/builtins/floattidf.c>
+#include <intrin.h>
+#include <xmmintrin.h>
+
+// Return value in XMM0
+__m128 __vectorcall __divti3abi(ti_int* x, ti_int* y) {
+ __m128 ret;
+ auto z = __divti3(*x, *y);
+ memcpy(&ret, &z, sizeof(ti_int));
+ return ret;
+}
+
+// Return value in XMM0
+__m128 __vectorcall __modti3abi(ti_int* x, ti_int* y) {
+ __m128 ret;
+ auto z = __modti3(*x, *y);
+ memcpy(&ret, &z, sizeof(ti_int));
+ return ret;
+}
+
+float __floattisfabi(du_int x, du_int y) {
+ utwords t;
+ t.s.low = x;
+ t.s.high = y;
+ return __floattisf(t.all);
+}
+
+double __floattidfabi(du_int x, du_int y) {
+ utwords t;
+ t.s.low = x;
+ t.s.high = y;
+ return __floattidf(t.all);
+}
+
+#endif
+
+namespace NYql {
+namespace NCodegen {
+
+namespace {
+
+ void FatalErrorHandler(void* user_data,
+#if LLVM_VERSION_MAJOR == 12
+ const std::string& reason
+#else
+ const char* reason
+#endif
+ , bool gen_crash_diag) {
+ Y_UNUSED(user_data);
+ Y_UNUSED(gen_crash_diag);
+ ythrow yexception() << "LLVM fatal error: " << reason;
+ }
+
+ void AddAddressSanitizerPasses(const llvm::PassManagerBuilder& builder, llvm::legacy::PassManagerBase& pm) {
+ Y_UNUSED(builder);
+ pm.add(llvm::createAddressSanitizerFunctionPass());
+ pm.add(llvm::createModuleAddressSanitizerLegacyPassPass());
+ }
+
+ void AddMemorySanitizerPass(const llvm::PassManagerBuilder& builder, llvm::legacy::PassManagerBase& pm) {
+ Y_UNUSED(builder);
+ pm.add(llvm::createMemorySanitizerLegacyPassPass());
+ }
+
+ void AddThreadSanitizerPass(const llvm::PassManagerBuilder& builder, llvm::legacy::PassManagerBase& pm) {
+ Y_UNUSED(builder);
+ pm.add(llvm::createThreadSanitizerLegacyPassPass());
+ }
+
+ struct TCodegenInit {
+ TCodegenInit() {
+ llvm::InitializeNativeTarget();
+ llvm::InitializeNativeTargetAsmPrinter();
+ llvm::InitializeNativeTargetAsmParser();
+ llvm::InitializeNativeTargetDisassembler();
+ llvm::install_fatal_error_handler(&FatalErrorHandler, nullptr);
+ }
+ };
+
+ bool CompareFuncOffsets(const std::pair<ui64, llvm::Function*>& lhs,
+ const std::pair<ui64, llvm::Function*>& rhs) {
+ return lhs.first < rhs.first;
+ }
+}
+
+bool ICodegen::IsCodegenAvailable() {
+ return true;
+}
+
+class TCodegen : public ICodegen, private llvm::JITEventListener {
+public:
+ TCodegen(ETarget target, ESanitize sanitize)
+ : Target_(target), Sanitize_(sanitize)
+ , EffectiveTarget_(Target_), EffectiveSanitize_(Sanitize_)
+ {
+ Singleton<TCodegenInit>();
+ Context_.setDiagnosticHandlerCallBack(&DiagnosticHandler, this);
+
+ std::unique_ptr<llvm::Module> module(new llvm::Module("yql", Context_));
+ Module_ = module.get();
+ std::string triple;
+ if (EffectiveTarget_ == ETarget::Native && EffectiveSanitize_ == ESanitize::Auto) {
+#if defined(_asan_enabled_)
+ EffectiveSanitize_ = ESanitize::Asan;
+#elif defined(_tsan_enabled_)
+ EffectiveSanitize_ = ESanitize::Tsan;
+#elif defined(_msan_enabled_)
+ EffectiveSanitize_ = ESanitize::Msan;
+#endif
+ }
+
+ if (EffectiveTarget_ == ETarget::CurrentOS || EffectiveTarget_ == ETarget::Native) {
+#if defined(_linux_)
+ EffectiveTarget_ = ETarget::Linux;
+#elif defined(_darwin_)
+ EffectiveTarget_ = ETarget::Darwin;
+#elif defined(_win_)
+ EffectiveTarget_ = ETarget::Windows;
+#else
+#error Unsupported OS
+#endif
+ }
+
+
+ switch (EffectiveTarget_) {
+ case ETarget::Linux:
+ triple = "x86_64-unknown-linux-gnu";
+ break;
+ case ETarget::Darwin:
+ triple = "x86_64-apple-darwin";
+ break;
+ case ETarget::Windows:
+ triple = "x86_64-unknown-windows-msvc";
+ break;
+ default:
+ ythrow yexception() << "Failed to select target";
+ }
+
+ Triple_ = llvm::Triple::normalize(triple);
+ Module_->setTargetTriple(Triple_);
+ Module_->addModuleFlag(llvm::Module::Warning, "Dwarf Version", llvm::dwarf::DWARF_VERSION);
+ Module_->addModuleFlag(llvm::Module::Warning, "Debug Info Version", llvm::DEBUG_METADATA_VERSION);
+
+ llvm::TargetOptions targetOptions;
+ targetOptions.EnableFastISel = true;
+ // init manually, this field was lost in llvm::TargetOptions ctor :/
+ // make coverity happy
+#if LLVM_VERSION_MAJOR == 12
+ targetOptions.StackProtectorGuardOffset = 0;
+#endif
+
+ std::string what;
+ auto&& engineBuilder = llvm::EngineBuilder(std::move(module));
+ engineBuilder
+ .setEngineKind(llvm::EngineKind::JIT)
+ .setOptLevel(llvm::CodeGenOpt::Default)
+ .setErrorStr(&what)
+ .setTargetOptions(targetOptions);
+
+ if (Target_ == ETarget::Native) {
+ auto hostCpu = llvm::sys::getHostCPUName();
+ engineBuilder.setMCPU(hostCpu);
+ }
+
+ Engine_.reset(engineBuilder.create());
+ if (!Engine_)
+ ythrow yexception() << "Failed to construct ExecutionEngine: " << what;
+
+ Module_->setDataLayout(Engine_->getDataLayout().getStringRepresentation());
+ Engine_->RegisterJITEventListener(this);
+ }
+
+ void TogglePerfJITEventListener() override {
+#ifdef __linux__
+ PerfListener_ = llvm::JITEventListener::createPerfJITEventListener();
+ Engine_->RegisterJITEventListener(PerfListener_);
+#endif
+ }
+
+ ~TCodegen() {
+#ifdef __linux__
+ if (PerfListener_) {
+ Engine_->UnregisterJITEventListener(PerfListener_);
+ }
+#endif
+ Engine_->UnregisterJITEventListener(this);
+ }
+
+ ETarget GetEffectiveTarget() const override {
+ return EffectiveTarget_;
+ }
+
+ llvm::LLVMContext& GetContext() override {
+ return Context_;
+ }
+
+
+ llvm::Module& GetModule() override {
+ return *Module_;
+ }
+
+ llvm::ExecutionEngine& GetEngine() override {
+ return *Engine_;
+ }
+
+ void Verify() override {
+ std::string what;
+ llvm::raw_string_ostream os(what);
+ if (llvm::verifyModule(*Module_, &os)) {
+ ythrow yexception() << "Verification error: " << what;
+ }
+ }
+
+ void GetStats(TCodegenStats& stats) override {
+ TCodegenStats ret;
+ for (auto& func : Module_->functions()) {
+ if (func.isDeclaration()) {
+ continue;
+ }
+
+ ui64 instructions = func.getInstructionCount();
+ ret.TotalInstructions += instructions;
+ ret.MaxFunctionInstructions = Max(ret.MaxFunctionInstructions, instructions);
+ ++ret.TotalFunctions;
+ }
+
+ stats = ret;
+ }
+
+ void ExportSymbol(llvm::Function* function) override {
+ if (!ExportedSymbols) {
+ ExportedSymbols.ConstructInPlace();
+ }
+
+ auto name = function->getName();
+ ExportedSymbols->emplace(TString(name.data(), name.size()));
+ }
+
+ void Compile(const TStringBuf compileOpts, TCompileStats* compileStats) override {
+
+ bool dumpTimers = compileOpts.Contains("time-passes");
+ bool disableOpt = compileOpts.Contains("disable-opt");
+#ifndef NDEBUG
+ disableOpt = true;
+#endif
+
+#if defined(_msan_enabled_)
+ ReverseGlobalMapping_[(const void*)&__emutls_get_address] = "__emutls_get_address";
+#endif
+#if defined(_win_) && !defined(__clang__)
+ AddGlobalMapping("__security_check_cookie", (const void*)&__security_check_cookie);
+ AddGlobalMapping("__security_cookie", (const void*)&__security_cookie);
+ AddGlobalMapping("__divti3", (const void*)&__divti3abi);
+ AddGlobalMapping("__modti3", (const void*)&__modti3abi);
+ AddGlobalMapping("__floattisf", (const void*)&__floattisfabi);
+ AddGlobalMapping("__floattidf", (const void*)&__floattidfabi);
+#else
+ AddGlobalMapping("__divti3", (const void*)&__divti3);
+ AddGlobalMapping("__fixdfti", (const void*)&__fixdfti);
+ AddGlobalMapping("__fixsfti", (const void*)&__fixsfti);
+ AddGlobalMapping("__fixunsdfti", (const void*)&__fixunsdfti);
+ AddGlobalMapping("__floattidf", (const void*)&__floattidf);
+ AddGlobalMapping("__floattisf", (const void*)&__floattisf);
+ AddGlobalMapping("__floatuntidf", (const void*)&__floatuntidf);
+ AddGlobalMapping("__floatuntisf", (const void*)&__floatuntisf);
+ AddGlobalMapping("__modti3", (const void*)&__modti3);
+ AddGlobalMapping("__muloti4", (const void*)&__muloti4);
+ AddGlobalMapping("__udivti3", (const void*)&__udivti3);
+ AddGlobalMapping("__umodti3", (const void*)&__umodti3);
+#endif
+
+ for (auto& function : Module_->getFunctionList()) {
+ function.addFnAttr("target-cpu", "x86-64");
+ function.addFnAttr("target-features", "+sse,+sse2");
+ }
+
+ if (dumpTimers) {
+ llvm::TimePassesIsEnabled = true;
+ }
+
+ std::unique_ptr<llvm::legacy::PassManager> modulePassManager;
+ std::unique_ptr<llvm::legacy::FunctionPassManager> functionPassManager;
+
+ if (ExportedSymbols) {
+ modulePassManager = std::make_unique<llvm::legacy::PassManager>();
+ modulePassManager->add(llvm::createInternalizePass([&](const llvm::GlobalValue& gv) -> bool {
+ auto name = TString(gv.getName().str());
+ return ExportedSymbols->contains(name);
+ }));
+
+ modulePassManager->add(llvm::createGlobalDCEPass());
+ modulePassManager->run(*Module_);
+ }
+
+ llvm::PassManagerBuilder passManagerBuilder;
+ passManagerBuilder.OptLevel = disableOpt ? 0 : 2;
+ passManagerBuilder.SizeLevel = 0;
+ passManagerBuilder.Inliner = llvm::createFunctionInliningPass();
+
+ if (EffectiveSanitize_ == ESanitize::Asan) {
+ passManagerBuilder.addExtension(llvm::PassManagerBuilder::EP_OptimizerLast,
+ AddAddressSanitizerPasses);
+ passManagerBuilder.addExtension(llvm::PassManagerBuilder::EP_EnabledOnOptLevel0,
+ AddAddressSanitizerPasses);
+ }
+
+ if (EffectiveSanitize_ == ESanitize::Msan) {
+ passManagerBuilder.addExtension(llvm::PassManagerBuilder::EP_OptimizerLast,
+ AddMemorySanitizerPass);
+ passManagerBuilder.addExtension(llvm::PassManagerBuilder::EP_EnabledOnOptLevel0,
+ AddMemorySanitizerPass);
+ }
+
+ if (EffectiveSanitize_ == ESanitize::Tsan) {
+ passManagerBuilder.addExtension(llvm::PassManagerBuilder::EP_OptimizerLast,
+ AddThreadSanitizerPass);
+ passManagerBuilder.addExtension(llvm::PassManagerBuilder::EP_EnabledOnOptLevel0,
+ AddThreadSanitizerPass);
+ }
+
+ functionPassManager = std::make_unique<llvm::legacy::FunctionPassManager>(Module_);
+ modulePassManager = std::make_unique<llvm::legacy::PassManager>();
+
+ passManagerBuilder.populateModulePassManager(*modulePassManager);
+ passManagerBuilder.populateFunctionPassManager(*functionPassManager);
+
+ auto functionPassStart = Now();
+ functionPassManager->doInitialization();
+ for (auto it = Module_->begin(), jt = Module_->end(); it != jt; ++it) {
+ if (!it->isDeclaration()) {
+ functionPassManager->run(*it);
+ }
+ }
+ functionPassManager->doFinalization();
+
+ if (compileStats) {
+ compileStats->FunctionPassTime = (Now() - functionPassStart).MilliSeconds();
+ }
+
+ auto modulePassStart = Now();
+ modulePassManager->run(*Module_);
+ if (compileStats) {
+ compileStats->ModulePassTime = (Now() - modulePassStart).MilliSeconds();
+ }
+
+ AllocateTls();
+
+ auto finalizeStart = Now();
+ Engine_->finalizeObject();
+ if (compileStats) {
+ compileStats->FinalizeTime = (Now() - finalizeStart).MilliSeconds();
+ }
+
+ for (const auto& secEntry : CodeSections_) {
+ for (auto& func : Module_->functions()) {
+ if (func.isDeclaration()) {
+ continue;
+ }
+
+ auto addr = (ui64)Engine_->getPointerToFunction(&func);
+ if (addr < secEntry.second || addr >= secEntry.second + secEntry.first.getSize()) {
+ continue;
+ }
+
+ SortedFuncs_.emplace_back(addr, &func);
+ }
+
+ SortedFuncs_.emplace_back(secEntry.second + secEntry.first.getSize(), nullptr);
+ }
+
+ std::sort(SortedFuncs_.begin(), SortedFuncs_.end(), CompareFuncOffsets);
+ if (dumpTimers) {
+ llvm::TimerGroup::printAll(llvm::errs());
+ llvm::TimePassesIsEnabled = false;
+ }
+
+ if (compileStats) {
+ compileStats->TotalObjectSize = TotalObjectSize;
+ }
+ }
+
+ void* GetPointerToFunction(llvm::Function* function) override {
+ return Engine_->getPointerToFunction(function);
+ }
+
+ ui64 GetFunctionCodeSize(llvm::Function* function) override {
+ auto addr = (ui64)Engine_->getPointerToFunction(function);
+ auto it = std::upper_bound(SortedFuncs_.begin(), SortedFuncs_.end(), std::make_pair(addr, nullptr), CompareFuncOffsets);
+ return it->first - addr;
+ }
+
+ void ShowGeneratedFunctions(IOutputStream* out) override {
+ *out << "--- functions begin ---\n";
+ for (const auto& secEntry : CodeSections_) {
+ auto expName = secEntry.first.getName();
+ auto name = expName.get();
+ auto sectionName = TStringBuf(name.data(), name.size());
+ *out << "section: " << sectionName << ", addr: " << (void*)secEntry.second << ", size: " << secEntry.first.getSize() << "\n";
+ }
+
+ for (const auto& funcEntry : SortedFuncs_) {
+ if (!funcEntry.second) {
+ continue;
+ }
+
+ const auto& name = funcEntry.second->getName();
+ auto funcName = TStringBuf(name.data(), name.size());
+ auto codeSize = GetFunctionCodeSize(funcEntry.second);
+ *out << "function: " << funcName << ", addr: " << (void*)funcEntry.first << ", size: " <<
+ codeSize << "\n";
+
+ Disassemble(out, (const unsigned char*)funcEntry.first, codeSize);
+ }
+
+ *out << "--- functions end ---\n";
+ }
+
+ void Disassemble(IOutputStream* out, const unsigned char* buf, size_t size) {
+ InitRegexps();
+ auto dis = LLVMCreateDisasm(Triple_.c_str(), nullptr, 0, nullptr, nullptr);
+ if (!dis) {
+ ythrow yexception() << "Cannot create disassembler";
+ }
+
+ std::unique_ptr<void, void(*)(void*)> delDis(dis, LLVMDisasmDispose);
+ LLVMSetDisasmOptions(dis, LLVMDisassembler_Option_AsmPrinterVariant);
+ char outline[1024];
+ size_t pos = 0;
+ while (pos < size) {
+ size_t l = LLVMDisasmInstruction(dis, (uint8_t*)buf + pos, size - pos, 0, outline, sizeof(outline));
+ if (!l) {
+ *out << " " << LeftPad(pos, 4, '0') << "\t???";
+ ++pos;
+ } else {
+ *out << " " << LeftPad(pos, 4, '0') << outline;
+ TStringBuf s(outline);
+ const re2::StringPiece piece(s.data(), s.size());
+ std::array<re2::StringPiece, 2> captures;
+ if (Patterns_->Imm_.Match(piece, 0, s.size(), re2::RE2::UNANCHORED, captures.data(), captures.size())) {
+ auto numBuf = TStringBuf(captures[1].data(), captures[1].size());
+ ui64 addr = FromString<ui64>(numBuf);
+ auto it = ReverseGlobalMapping_.find((void*)addr);
+ if (it != ReverseGlobalMapping_.end()) {
+ *out << " ; &" << it->second;
+ }
+ } else if (Patterns_->Jump_.Match(piece, 0, s.size(), re2::RE2::UNANCHORED, captures.data(), captures.size())) {
+ auto numBuf = TStringBuf(captures[1].data(), captures[1].size());
+ i64 offset = FromString<i64>(numBuf);
+ *out << " ; -> " << pos + l + offset;
+ }
+
+ pos += l;
+ }
+
+ *out << '\n';
+ }
+ }
+
+ void LoadBitCode(TStringBuf bitcode, TStringBuf uniqId) override {
+ if (uniqId && LoadedModules_.contains(uniqId)) {
+ return;
+ }
+ llvm::SMDiagnostic error;
+ auto buffer = llvm::MemoryBuffer::getMemBuffer(
+ llvm::StringRef(bitcode.data(), bitcode.size()));
+ std::unique_ptr<llvm::Module> module = llvm::parseIR(buffer->getMemBufferRef(), error, Context_);
+
+ if (!module) {
+ std::string what;
+ llvm::raw_string_ostream os(what);
+ error.print("error after ParseIR()", os);
+ ythrow yexception() << what;
+ }
+
+ module->setTargetTriple(Triple_);
+ module->setDataLayout(Engine_->getDataLayout().getStringRepresentation());
+ if (uniqId) {
+ module->setModuleIdentifier(llvm::StringRef(uniqId.data(), uniqId.size()));
+ }
+
+ if (llvm::Linker::linkModules(*Module_, std::move(module))) {
+ TString err;
+ err.append("LLVM: error linking module");
+ if (uniqId) {
+ err.append(' ').append(uniqId);
+ }
+ if (Diagnostic_.size()) {
+ err.append(": ").append(Diagnostic_.c_str(), Diagnostic_.size());
+ }
+ ythrow yexception() << err;
+ }
+
+ if (uniqId) {
+ LoadedModules_.emplace(uniqId);
+ }
+ }
+
+ void AddGlobalMapping(TStringBuf name, const void* address) override {
+ ReverseGlobalMapping_[address] = TString(name);
+ Engine_->updateGlobalMapping(llvm::StringRef(name.data(), name.size()), (uint64_t)address);
+ }
+
+ void notifyObjectLoaded(ObjectKey key, const llvm::object::ObjectFile &obj,
+ const llvm::RuntimeDyld::LoadedObjectInfo &loi) override
+ {
+ Y_UNUSED(key);
+ TotalObjectSize += obj.getData().size();
+
+ for (const auto& section : obj.sections()) {
+ //auto nameExp = section.getName();
+ //auto name = nameExp.get();
+ //auto nameStr = TStringBuf(name.data(), name.size());
+ //Cerr << nameStr << "\n";
+ if (section.isText()) {
+ CodeSections_.emplace_back(section, loi.getSectionLoadAddress(section));
+ }
+ }
+ }
+
+private:
+ void OnDiagnosticInfo(const llvm::DiagnosticInfo &info) {
+ llvm::raw_string_ostream ostream(Diagnostic_);
+ llvm::DiagnosticPrinterRawOStream printer(ostream);
+ info.print(printer);
+ }
+
+ static void DiagnosticHandler(const llvm::DiagnosticInfo &info, void* context) {
+ return static_cast<TCodegen*>(context)->OnDiagnosticInfo(info);
+ }
+
+ void AllocateTls() {
+ for (const auto& glob : Module_->globals()) {
+ auto nameRef = glob.getName();
+ if (glob.isThreadLocal()) {
+ llvm::Type* type = glob.getValueType();
+ const llvm::DataLayout& dataLayout = Module_->getDataLayout();
+ auto size = dataLayout.getTypeStoreSize(type);
+ auto align = glob.getAlignment();
+ if (!align) {
+ // When LLVM IL declares a variable without alignment, use
+ // the ABI default alignment for the type.
+ align = dataLayout.getABITypeAlignment(type);
+ }
+
+ TStringBuf name(nameRef.data(), nameRef.size());
+ TString fullName = TString("__emutls_v.") + name;
+ auto ctl = TlsManager_.Add(fullName, size, align);
+ Engine_->updateGlobalMapping(llvm::StringRef(fullName.data(), fullName.size()), (uint64_t)ctl);
+ ReverseGlobalMapping_[&ctl] = fullName;
+ }
+ }
+ }
+
+ struct TPatterns {
+ TPatterns()
+ : Imm_(re2::StringPiece("\\s*movabs\\s+[0-9a-z]+\\s*,\\s*(\\d+)\\s*"))
+ , Jump_(re2::StringPiece("\\s*(?:j[a-z]+)\\s*(-?\\d+)\\s*"))
+ {}
+
+ re2::RE2 Imm_;
+ re2::RE2 Jump_;
+ };
+
+ void InitRegexps() {
+ if (!Patterns_) {
+ Patterns_.ConstructInPlace();
+ }
+ }
+
+ const ETarget Target_;
+ const ESanitize Sanitize_;
+ ETarget EffectiveTarget_;
+ ESanitize EffectiveSanitize_;
+ llvm::LLVMContext Context_;
+ std::string Diagnostic_;
+ std::string Triple_;
+ llvm::Module* Module_;
+#ifdef __linux__
+ llvm::JITEventListener* PerfListener_ = nullptr;
+#endif
+ std::unique_ptr<llvm::ExecutionEngine> Engine_;
+ std::vector<std::pair<llvm::object::SectionRef, ui64>> CodeSections_;
+ ui64 TotalObjectSize = 0;
+ std::vector<std::pair<ui64, llvm::Function*>> SortedFuncs_;
+ TMaybe<THashSet<TString>> ExportedSymbols;
+ THashMap<const void*, TString> ReverseGlobalMapping_;
+ TMaybe<TPatterns> Patterns_;
+ TTlsManager TlsManager_;
+ THashSet<TString> LoadedModules_;
+};
+
+ICodegen::TPtr
+ICodegen::Make(ETarget target, ESanitize sanitize) {
+ return std::make_unique<TCodegen>(target, sanitize);
+}
+
+ICodegen::TSharedPtr
+ICodegen::MakeShared(ETarget target, ESanitize sanitize) {
+ return std::make_shared<TCodegen>(target, sanitize);
+}
+
+}
+}