codegen.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795
  1. #include "codegen.h"
  2. Y_PRAGMA_DIAGNOSTIC_PUSH
  3. Y_PRAGMA("GCC diagnostic ignored \"-Wbitwise-instead-of-logical\"")
  4. #include "codegen_llvm_deps.h" // Y_IGNORE
  5. Y_PRAGMA_DIAGNOSTIC_POP
  6. #include <contrib/libs/re2/re2/re2.h>
  7. #include <util/generic/maybe.h>
  8. #include <util/generic/singleton.h>
  9. #include <util/generic/hash_set.h>
  10. #include <util/generic/hash.h>
  11. #include <util/generic/yexception.h>
  12. #include <util/generic/strbuf.h>
  13. #include <util/generic/string.h>
  14. #include <util/stream/format.h>
  15. #include <util/system/defaults.h>
  16. #include <util/system/platform.h>
  17. #include <util/datetime/base.h>
  18. typedef struct __emutls_control {
  19. size_t size; /* size of the object in bytes */
  20. size_t align; /* alignment of the object in bytes */
  21. union {
  22. uintptr_t index; /* data[index-1] is the object address */
  23. void* address; /* object address, when in single thread env */
  24. } object;
  25. void* value; /* null or non-zero initial value for the object */
  26. } __emutls_control;
  27. #if defined(_msan_enabled_)
  28. extern "C" void* __emutls_get_address(__emutls_control* control);
  29. #endif
  30. class TTlsManager {
  31. public:
  32. void* Add(const TString& name, size_t size, size_t align) {
  33. //Cerr << "name: " << name << ", size: " << size << ", align: " << align << "\n";
  34. auto pair = Tls_.insert(std::make_pair(name, __emutls_control()));
  35. if (pair.second) {
  36. Zero(pair.first->second);
  37. pair.first->second.size = size;
  38. pair.first->second.align = align;
  39. }
  40. return &pair.first->second;
  41. }
  42. private:
  43. THashMap<TString, __emutls_control> Tls_;
  44. };
  45. #if !defined(_win_) || defined(__clang__)
  46. extern "C" void __divti3();
  47. extern "C" void __fixdfti();
  48. extern "C" void __fixsfti();
  49. extern "C" void __fixunsdfti();
  50. extern "C" void __floattidf();
  51. extern "C" void __floattisf();
  52. extern "C" void __floatuntidf();
  53. extern "C" void __floatuntisf();
  54. extern "C" void __modti3();
  55. extern "C" void __muloti4();
  56. extern "C" void __udivti3();
  57. extern "C" void __umodti3();
  58. #else
  59. #include <yql/essentials/public/decimal/yql_decimal.h>
  60. #define CRT_HAS_128BIT
  61. #define INT_LIB_H
  62. #define COMPILER_RT_ABI
  63. typedef NYql::NDecimal::TInt128 ti_int;
  64. typedef NYql::NDecimal::TUint128 tu_int;
  65. typedef int si_int;
  66. typedef unsigned su_int;
  67. typedef long long di_int;
  68. typedef unsigned long long du_int;
  69. typedef union
  70. {
  71. tu_int all;
  72. struct
  73. {
  74. du_int low;
  75. du_int high;
  76. }s;
  77. } utwords;
  78. typedef union
  79. {
  80. ti_int all;
  81. struct
  82. {
  83. du_int low;
  84. di_int high;
  85. }s;
  86. } twords;
  87. typedef union
  88. {
  89. du_int all;
  90. struct
  91. {
  92. su_int low;
  93. su_int high;
  94. }s;
  95. } udwords;
  96. typedef union
  97. {
  98. su_int u;
  99. float f;
  100. } float_bits;
  101. typedef union
  102. {
  103. udwords u;
  104. double f;
  105. } double_bits;
  106. int __builtin_ctzll(ui64 value) {
  107. DWORD trailing_zero = 0;
  108. if (_BitScanForward64(&trailing_zero, value)) {
  109. return trailing_zero;
  110. } else {
  111. return 64;
  112. }
  113. }
  114. int __builtin_clzll(ui64 value) {
  115. DWORD leading_zero = 0;
  116. if (_BitScanReverse64(&leading_zero, value)) {
  117. return 63 - leading_zero;
  118. } else {
  119. return 64;
  120. }
  121. }
  122. #define __divti3 __divti3impl
  123. #define __udivmodti4 __udivmodti4impl
  124. #define __modti3 __modti3impl
  125. #define __clzti2 __clzti2impl
  126. #define __floattisf __floattisfimpl
  127. #define __floattidf __floattidfimpl
  128. #include <contrib/libs/cxxsupp/builtins/udivmodti4.c>
  129. #include <contrib/libs/cxxsupp/builtins/divti3.c>
  130. #include <contrib/libs/cxxsupp/builtins/modti3.c>
  131. #include <contrib/libs/cxxsupp/builtins/clzti2.c>
  132. #include <contrib/libs/cxxsupp/builtins/floattisf.c>
  133. #include <contrib/libs/cxxsupp/builtins/floattidf.c>
  134. #include <intrin.h>
  135. #include <xmmintrin.h>
  136. // Return value in XMM0
  137. __m128 __vectorcall __divti3abi(ti_int* x, ti_int* y) {
  138. __m128 ret;
  139. auto z = __divti3(*x, *y);
  140. memcpy(&ret, &z, sizeof(ti_int));
  141. return ret;
  142. }
  143. // Return value in XMM0
  144. __m128 __vectorcall __modti3abi(ti_int* x, ti_int* y) {
  145. __m128 ret;
  146. auto z = __modti3(*x, *y);
  147. memcpy(&ret, &z, sizeof(ti_int));
  148. return ret;
  149. }
  150. float __floattisfabi(du_int x, du_int y) {
  151. utwords t;
  152. t.s.low = x;
  153. t.s.high = y;
  154. return __floattisf(t.all);
  155. }
  156. double __floattidfabi(du_int x, du_int y) {
  157. utwords t;
  158. t.s.low = x;
  159. t.s.high = y;
  160. return __floattidf(t.all);
  161. }
  162. #endif
  163. namespace NYql {
  164. namespace NCodegen {
  165. namespace {
  166. void FatalErrorHandler(void* user_data, const char* reason, bool gen_crash_diag) {
  167. Y_UNUSED(user_data);
  168. Y_UNUSED(gen_crash_diag);
  169. ythrow yexception() << "LLVM fatal error: " << reason;
  170. }
  171. #if LLVM_VERSION_MAJOR < 16
  172. void AddAddressSanitizerPasses(const llvm::PassManagerBuilder& builder, llvm::legacy::PassManagerBase& pm) {
  173. Y_UNUSED(builder);
  174. pm.add(llvm::createAddressSanitizerFunctionPass());
  175. pm.add(llvm::createModuleAddressSanitizerLegacyPassPass());
  176. }
  177. void AddMemorySanitizerPass(const llvm::PassManagerBuilder& builder, llvm::legacy::PassManagerBase& pm) {
  178. Y_UNUSED(builder);
  179. pm.add(llvm::createMemorySanitizerLegacyPassPass());
  180. }
  181. void AddThreadSanitizerPass(const llvm::PassManagerBuilder& builder, llvm::legacy::PassManagerBase& pm) {
  182. Y_UNUSED(builder);
  183. pm.add(llvm::createThreadSanitizerLegacyPassPass());
  184. }
  185. #endif
  186. struct TCodegenInit {
  187. TCodegenInit() {
  188. llvm::InitializeNativeTarget();
  189. llvm::InitializeNativeTargetAsmPrinter();
  190. llvm::InitializeNativeTargetAsmParser();
  191. llvm::InitializeNativeTargetDisassembler();
  192. llvm::install_fatal_error_handler(&FatalErrorHandler, nullptr);
  193. }
  194. };
  195. bool CompareFuncOffsets(const std::pair<ui64, llvm::Function*>& lhs,
  196. const std::pair<ui64, llvm::Function*>& rhs) {
  197. return lhs.first < rhs.first;
  198. }
  199. }
  200. bool ICodegen::IsCodegenAvailable() {
  201. return true;
  202. }
  203. class TCodegen : public ICodegen, private llvm::JITEventListener {
  204. public:
  205. TCodegen(ETarget target, ESanitize sanitize)
  206. : Target_(target), Sanitize_(sanitize)
  207. , EffectiveTarget_(Target_), EffectiveSanitize_(Sanitize_)
  208. {
  209. Singleton<TCodegenInit>();
  210. Context_.setDiagnosticHandlerCallBack(&DiagnosticHandler, this);
  211. std::unique_ptr<llvm::Module> module(new llvm::Module("yql", Context_));
  212. Module_ = module.get();
  213. std::string triple;
  214. if (EffectiveTarget_ == ETarget::Native && EffectiveSanitize_ == ESanitize::Auto) {
  215. #if defined(_asan_enabled_)
  216. EffectiveSanitize_ = ESanitize::Asan;
  217. #elif defined(_tsan_enabled_)
  218. EffectiveSanitize_ = ESanitize::Tsan;
  219. #elif defined(_msan_enabled_)
  220. EffectiveSanitize_ = ESanitize::Msan;
  221. #endif
  222. }
  223. if (EffectiveTarget_ == ETarget::CurrentOS || EffectiveTarget_ == ETarget::Native) {
  224. #if defined(_linux_)
  225. EffectiveTarget_ = ETarget::Linux;
  226. #elif defined(_darwin_)
  227. EffectiveTarget_ = ETarget::Darwin;
  228. #elif defined(_win_)
  229. EffectiveTarget_ = ETarget::Windows;
  230. #else
  231. #error Unsupported OS
  232. #endif
  233. }
  234. switch (EffectiveTarget_) {
  235. case ETarget::Linux:
  236. triple = "x86_64-unknown-linux-gnu";
  237. break;
  238. case ETarget::Darwin:
  239. triple = "x86_64-apple-darwin";
  240. break;
  241. case ETarget::Windows:
  242. triple = "x86_64-unknown-windows-msvc";
  243. break;
  244. default:
  245. ythrow yexception() << "Failed to select target";
  246. }
  247. Triple_ = llvm::Triple::normalize(triple);
  248. Module_->setTargetTriple(Triple_);
  249. Module_->addModuleFlag(llvm::Module::Warning, "Dwarf Version", llvm::dwarf::DWARF_VERSION);
  250. Module_->addModuleFlag(llvm::Module::Warning, "Debug Info Version", llvm::DEBUG_METADATA_VERSION);
  251. llvm::TargetOptions targetOptions;
  252. targetOptions.EnableFastISel = true;
  253. std::string what;
  254. auto&& engineBuilder = llvm::EngineBuilder(std::move(module));
  255. engineBuilder
  256. .setEngineKind(llvm::EngineKind::JIT)
  257. .setOptLevel(llvm::CodeGenOpt::Default)
  258. .setErrorStr(&what)
  259. .setTargetOptions(targetOptions);
  260. if (Target_ == ETarget::Native) {
  261. auto hostCpu = llvm::sys::getHostCPUName();
  262. engineBuilder.setMCPU(hostCpu);
  263. }
  264. Engine_.reset(engineBuilder.create());
  265. if (!Engine_)
  266. ythrow yexception() << "Failed to construct ExecutionEngine: " << what;
  267. Module_->setDataLayout(Engine_->getDataLayout().getStringRepresentation());
  268. Engine_->RegisterJITEventListener(this);
  269. }
  270. void TogglePerfJITEventListener() override {
  271. #ifdef __linux__
  272. PerfListener_ = llvm::JITEventListener::createPerfJITEventListener();
  273. Engine_->RegisterJITEventListener(PerfListener_);
  274. #endif
  275. }
  276. ~TCodegen() {
  277. #ifdef __linux__
  278. if (PerfListener_) {
  279. Engine_->UnregisterJITEventListener(PerfListener_);
  280. }
  281. #endif
  282. Engine_->UnregisterJITEventListener(this);
  283. }
  284. ETarget GetEffectiveTarget() const override {
  285. return EffectiveTarget_;
  286. }
  287. llvm::LLVMContext& GetContext() override {
  288. return Context_;
  289. }
  290. llvm::Module& GetModule() override {
  291. return *Module_;
  292. }
  293. llvm::ExecutionEngine& GetEngine() override {
  294. return *Engine_;
  295. }
  296. void Verify() override {
  297. std::string what;
  298. llvm::raw_string_ostream os(what);
  299. if (llvm::verifyModule(*Module_, &os)) {
  300. ythrow yexception() << "Verification error: " << what;
  301. }
  302. }
  303. void GetStats(TCodegenStats& stats) override {
  304. TCodegenStats ret;
  305. for (auto& func : Module_->functions()) {
  306. if (func.isDeclaration()) {
  307. continue;
  308. }
  309. ui64 instructions = func.getInstructionCount();
  310. ret.TotalInstructions += instructions;
  311. ret.MaxFunctionInstructions = Max(ret.MaxFunctionInstructions, instructions);
  312. ++ret.TotalFunctions;
  313. }
  314. stats = ret;
  315. }
  316. void ExportSymbol(llvm::Function* function) override {
  317. if (!ExportedSymbols) {
  318. ExportedSymbols.ConstructInPlace();
  319. }
  320. auto name = function->getName();
  321. ExportedSymbols->emplace(TString(name.data(), name.size()));
  322. }
  323. void Compile(const TStringBuf compileOpts, TCompileStats* compileStats) override {
  324. bool dumpTimers = compileOpts.Contains("time-passes");
  325. bool disableOpt = compileOpts.Contains("disable-opt");
  326. #ifndef NDEBUG
  327. disableOpt = true;
  328. #endif
  329. #if defined(_msan_enabled_)
  330. ReverseGlobalMapping_[(const void*)&__emutls_get_address] = "__emutls_get_address";
  331. #endif
  332. #if defined(_win_)
  333. AddGlobalMapping("__security_check_cookie", (const void*)&__security_check_cookie);
  334. AddGlobalMapping("__security_cookie", (const void*)&__security_cookie);
  335. #endif
  336. AddGlobalMapping("__divti3", (const void*)&__divti3);
  337. AddGlobalMapping("__fixdfti", (const void*)&__fixdfti);
  338. AddGlobalMapping("__fixsfti", (const void*)&__fixsfti);
  339. AddGlobalMapping("__fixunsdfti", (const void*)&__fixunsdfti);
  340. AddGlobalMapping("__floattidf", (const void*)&__floattidf);
  341. AddGlobalMapping("__floattisf", (const void*)&__floattisf);
  342. AddGlobalMapping("__floatuntidf", (const void*)&__floatuntidf);
  343. AddGlobalMapping("__floatuntisf", (const void*)&__floatuntisf);
  344. AddGlobalMapping("__modti3", (const void*)&__modti3);
  345. AddGlobalMapping("__muloti4", (const void*)&__muloti4);
  346. AddGlobalMapping("__udivti3", (const void*)&__udivti3);
  347. AddGlobalMapping("__umodti3", (const void*)&__umodti3);
  348. for (auto& function : Module_->getFunctionList()) {
  349. function.addFnAttr("target-cpu", "x86-64");
  350. function.addFnAttr("target-features", "+sse,+sse2");
  351. }
  352. if (dumpTimers) {
  353. llvm::TimePassesIsEnabled = true;
  354. }
  355. if (ExportedSymbols) {
  356. std::unique_ptr<llvm::legacy::PassManager> modulePassManager;
  357. std::unique_ptr<llvm::legacy::FunctionPassManager> functionPassManager;
  358. modulePassManager = std::make_unique<llvm::legacy::PassManager>();
  359. modulePassManager->add(llvm::createInternalizePass([&](const llvm::GlobalValue& gv) -> bool {
  360. auto name = TString(gv.getName().str());
  361. return ExportedSymbols->contains(name);
  362. }));
  363. modulePassManager->add(llvm::createGlobalDCEPass());
  364. modulePassManager->run(*Module_);
  365. }
  366. #if LLVM_VERSION_MAJOR < 16
  367. llvm::PassManagerBuilder passManagerBuilder;
  368. passManagerBuilder.OptLevel = disableOpt ? 0 : 2;
  369. passManagerBuilder.SizeLevel = 0;
  370. passManagerBuilder.Inliner = llvm::createFunctionInliningPass();
  371. if (EffectiveSanitize_ == ESanitize::Asan) {
  372. passManagerBuilder.addExtension(llvm::PassManagerBuilder::EP_OptimizerLast,
  373. AddAddressSanitizerPasses);
  374. passManagerBuilder.addExtension(llvm::PassManagerBuilder::EP_EnabledOnOptLevel0,
  375. AddAddressSanitizerPasses);
  376. }
  377. if (EffectiveSanitize_ == ESanitize::Msan) {
  378. passManagerBuilder.addExtension(llvm::PassManagerBuilder::EP_OptimizerLast,
  379. AddMemorySanitizerPass);
  380. passManagerBuilder.addExtension(llvm::PassManagerBuilder::EP_EnabledOnOptLevel0,
  381. AddMemorySanitizerPass);
  382. }
  383. if (EffectiveSanitize_ == ESanitize::Tsan) {
  384. passManagerBuilder.addExtension(llvm::PassManagerBuilder::EP_OptimizerLast,
  385. AddThreadSanitizerPass);
  386. passManagerBuilder.addExtension(llvm::PassManagerBuilder::EP_EnabledOnOptLevel0,
  387. AddThreadSanitizerPass);
  388. }
  389. auto functionPassManager = std::make_unique<llvm::legacy::FunctionPassManager>(Module_);
  390. auto modulePassManager = std::make_unique<llvm::legacy::PassManager>();
  391. passManagerBuilder.populateModulePassManager(*modulePassManager);
  392. passManagerBuilder.populateFunctionPassManager(*functionPassManager);
  393. auto functionPassStart = Now();
  394. functionPassManager->doInitialization();
  395. for (auto it = Module_->begin(), jt = Module_->end(); it != jt; ++it) {
  396. if (!it->isDeclaration()) {
  397. functionPassManager->run(*it);
  398. }
  399. }
  400. functionPassManager->doFinalization();
  401. if (compileStats) {
  402. compileStats->FunctionPassTime = (Now() - functionPassStart).MilliSeconds();
  403. }
  404. auto modulePassStart = Now();
  405. modulePassManager->run(*Module_);
  406. if (compileStats) {
  407. compileStats->ModulePassTime = (Now() - modulePassStart).MilliSeconds();
  408. }
  409. #else
  410. llvm::PassBuilder passBuilder;
  411. llvm::LoopAnalysisManager lam;
  412. llvm::FunctionAnalysisManager fam;
  413. llvm::CGSCCAnalysisManager cgam;
  414. llvm::ModuleAnalysisManager mam;
  415. // Register the target library analysis directly and give it a customized
  416. // preset TLI.
  417. std::unique_ptr<llvm::TargetLibraryInfoImpl> tlii(new llvm::TargetLibraryInfoImpl(llvm::Triple(Triple_)));
  418. fam.registerPass([&] { return llvm::TargetLibraryAnalysis(*tlii); });
  419. // Register all the basic analyses with the managers.
  420. passBuilder.registerModuleAnalyses(mam);
  421. passBuilder.registerCGSCCAnalyses(cgam);
  422. passBuilder.registerFunctionAnalyses(fam);
  423. passBuilder.registerLoopAnalyses(lam);
  424. passBuilder.crossRegisterProxies(lam, fam, cgam, mam);
  425. auto sanitizersCallback = [&](llvm::ModulePassManager& mpm, llvm::OptimizationLevel level) {
  426. Y_UNUSED(level);
  427. if (EffectiveSanitize_ == ESanitize::Asan) {
  428. llvm::AddressSanitizerOptions options;
  429. mpm.addPass(llvm::AddressSanitizerPass(options));
  430. }
  431. if (EffectiveSanitize_ == ESanitize::Msan) {
  432. llvm::MemorySanitizerOptions options;
  433. mpm.addPass(llvm::MemorySanitizerPass(options));
  434. }
  435. if (EffectiveSanitize_ == ESanitize::Tsan) {
  436. mpm.addPass(llvm::ModuleThreadSanitizerPass());
  437. mpm.addPass(llvm::createModuleToFunctionPassAdaptor(llvm::ThreadSanitizerPass()));
  438. }
  439. };
  440. passBuilder.registerOptimizerLastEPCallback(sanitizersCallback);
  441. llvm::ModulePassManager modulePassManager;
  442. if (disableOpt) {
  443. modulePassManager = passBuilder.buildO0DefaultPipeline(llvm::OptimizationLevel::O0, false);
  444. } else {
  445. modulePassManager = passBuilder.buildPerModuleDefaultPipeline(llvm::OptimizationLevel::O2);
  446. }
  447. auto modulePassStart = Now();
  448. modulePassManager.run(*Module_, mam);
  449. if (compileStats) {
  450. compileStats->ModulePassTime = (Now() - modulePassStart).MilliSeconds();
  451. }
  452. #endif
  453. AllocateTls();
  454. auto finalizeStart = Now();
  455. Engine_->finalizeObject();
  456. if (compileStats) {
  457. compileStats->FinalizeTime = (Now() - finalizeStart).MilliSeconds();
  458. }
  459. for (const auto& secEntry : CodeSections_) {
  460. for (auto& func : Module_->functions()) {
  461. if (func.isDeclaration()) {
  462. continue;
  463. }
  464. auto addr = (ui64)Engine_->getPointerToFunction(&func);
  465. if (addr < secEntry.second || addr >= secEntry.second + secEntry.first.getSize()) {
  466. continue;
  467. }
  468. SortedFuncs_.emplace_back(addr, &func);
  469. }
  470. SortedFuncs_.emplace_back(secEntry.second + secEntry.first.getSize(), nullptr);
  471. }
  472. std::sort(SortedFuncs_.begin(), SortedFuncs_.end(), CompareFuncOffsets);
  473. if (dumpTimers) {
  474. llvm::TimerGroup::printAll(llvm::errs());
  475. llvm::TimePassesIsEnabled = false;
  476. }
  477. if (compileStats) {
  478. compileStats->TotalObjectSize = TotalObjectSize;
  479. }
  480. }
  481. void* GetPointerToFunction(llvm::Function* function) override {
  482. return Engine_->getPointerToFunction(function);
  483. }
  484. ui64 GetFunctionCodeSize(llvm::Function* function) override {
  485. auto addr = (ui64)Engine_->getPointerToFunction(function);
  486. auto it = std::upper_bound(SortedFuncs_.begin(), SortedFuncs_.end(), std::make_pair(addr, nullptr), CompareFuncOffsets);
  487. return it->first - addr;
  488. }
  489. void ShowGeneratedFunctions(IOutputStream* out) override {
  490. *out << "--- functions begin ---\n";
  491. for (const auto& secEntry : CodeSections_) {
  492. auto expName = secEntry.first.getName();
  493. auto name = expName.get();
  494. auto sectionName = TStringBuf(name.data(), name.size());
  495. *out << "section: " << sectionName << ", addr: " << (void*)secEntry.second << ", size: " << secEntry.first.getSize() << "\n";
  496. }
  497. for (const auto& funcEntry : SortedFuncs_) {
  498. if (!funcEntry.second) {
  499. continue;
  500. }
  501. const auto& name = funcEntry.second->getName();
  502. auto funcName = TStringBuf(name.data(), name.size());
  503. auto codeSize = GetFunctionCodeSize(funcEntry.second);
  504. *out << "function: " << funcName << ", addr: " << (void*)funcEntry.first << ", size: " <<
  505. codeSize << "\n";
  506. Disassemble(out, (const unsigned char*)funcEntry.first, codeSize);
  507. }
  508. *out << "--- functions end ---\n";
  509. }
  510. void Disassemble(IOutputStream* out, const unsigned char* buf, size_t size) {
  511. InitRegexps();
  512. auto dis = LLVMCreateDisasm(Triple_.c_str(), nullptr, 0, nullptr, nullptr);
  513. if (!dis) {
  514. ythrow yexception() << "Cannot create disassembler";
  515. }
  516. std::unique_ptr<void, void(*)(void*)> delDis(dis, LLVMDisasmDispose);
  517. LLVMSetDisasmOptions(dis, LLVMDisassembler_Option_AsmPrinterVariant);
  518. char outline[1024];
  519. size_t pos = 0;
  520. while (pos < size) {
  521. size_t l = LLVMDisasmInstruction(dis, (uint8_t*)buf + pos, size - pos, 0, outline, sizeof(outline));
  522. if (!l) {
  523. *out << " " << LeftPad(pos, 4, '0') << "\t???";
  524. ++pos;
  525. } else {
  526. *out << " " << LeftPad(pos, 4, '0') << outline;
  527. TStringBuf s(outline);
  528. const re2::StringPiece piece(s.data(), s.size());
  529. std::array<re2::StringPiece, 2> captures;
  530. if (Patterns_->Imm_.Match(piece, 0, s.size(), re2::RE2::UNANCHORED, captures.data(), captures.size())) {
  531. auto numBuf = TStringBuf(captures[1].data(), captures[1].size());
  532. ui64 addr = FromString<ui64>(numBuf);
  533. auto it = ReverseGlobalMapping_.find((void*)addr);
  534. if (it != ReverseGlobalMapping_.end()) {
  535. *out << " ; &" << it->second;
  536. }
  537. } else if (Patterns_->Jump_.Match(piece, 0, s.size(), re2::RE2::UNANCHORED, captures.data(), captures.size())) {
  538. auto numBuf = TStringBuf(captures[1].data(), captures[1].size());
  539. i64 offset = FromString<i64>(numBuf);
  540. *out << " ; -> " << pos + l + offset;
  541. }
  542. pos += l;
  543. }
  544. *out << '\n';
  545. }
  546. }
  547. void LoadBitCode(TStringBuf bitcode, TStringBuf uniqId) override {
  548. if (uniqId && LoadedModules_.contains(uniqId)) {
  549. return;
  550. }
  551. llvm::SMDiagnostic error;
  552. auto buffer = llvm::MemoryBuffer::getMemBuffer(
  553. llvm::StringRef(bitcode.data(), bitcode.size()));
  554. std::unique_ptr<llvm::Module> module = llvm::parseIR(buffer->getMemBufferRef(), error, Context_);
  555. if (!module) {
  556. std::string what;
  557. llvm::raw_string_ostream os(what);
  558. error.print("error after ParseIR()", os);
  559. ythrow yexception() << what;
  560. }
  561. module->setTargetTriple(Triple_);
  562. module->setDataLayout(Engine_->getDataLayout().getStringRepresentation());
  563. if (uniqId) {
  564. module->setModuleIdentifier(llvm::StringRef(uniqId.data(), uniqId.size()));
  565. }
  566. if (llvm::Linker::linkModules(*Module_, std::move(module))) {
  567. TString err;
  568. err.append("LLVM: error linking module");
  569. if (uniqId) {
  570. err.append(' ').append(uniqId);
  571. }
  572. if (Diagnostic_.size()) {
  573. err.append(": ").append(Diagnostic_.c_str(), Diagnostic_.size());
  574. }
  575. ythrow yexception() << err;
  576. }
  577. if (uniqId) {
  578. LoadedModules_.emplace(uniqId);
  579. }
  580. }
  581. void AddGlobalMapping(TStringBuf name, const void* address) override {
  582. ReverseGlobalMapping_[address] = TString(name);
  583. Engine_->updateGlobalMapping(llvm::StringRef(name.data(), name.size()), (uint64_t)address);
  584. }
  585. void notifyObjectLoaded(ObjectKey key, const llvm::object::ObjectFile &obj,
  586. const llvm::RuntimeDyld::LoadedObjectInfo &loi) override
  587. {
  588. Y_UNUSED(key);
  589. TotalObjectSize += obj.getData().size();
  590. for (const auto& section : obj.sections()) {
  591. //auto nameExp = section.getName();
  592. //auto name = nameExp.get();
  593. //auto nameStr = TStringBuf(name.data(), name.size());
  594. //Cerr << nameStr << "\n";
  595. if (section.isText()) {
  596. CodeSections_.emplace_back(section, loi.getSectionLoadAddress(section));
  597. }
  598. }
  599. }
  600. private:
  601. void OnDiagnosticInfo(const llvm::DiagnosticInfo &info) {
  602. llvm::raw_string_ostream ostream(Diagnostic_);
  603. llvm::DiagnosticPrinterRawOStream printer(ostream);
  604. info.print(printer);
  605. }
  606. static void DiagnosticHandler(const llvm::DiagnosticInfo &info, void* context) {
  607. return static_cast<TCodegen*>(context)->OnDiagnosticInfo(info);
  608. }
  609. void AllocateTls() {
  610. for (const auto& glob : Module_->globals()) {
  611. auto nameRef = glob.getName();
  612. if (glob.isThreadLocal()) {
  613. llvm::Type* type = glob.getValueType();
  614. const llvm::DataLayout& dataLayout = Module_->getDataLayout();
  615. auto size = dataLayout.getTypeStoreSize(type);
  616. auto align = glob.getAlignment();
  617. if (!align) {
  618. // When LLVM IL declares a variable without alignment, use
  619. // the ABI default alignment for the type.
  620. align = dataLayout.getABITypeAlign(type).value();
  621. }
  622. TStringBuf name(nameRef.data(), nameRef.size());
  623. TString fullName = TString("__emutls_v.") + name;
  624. auto ctl = TlsManager_.Add(fullName, size, align);
  625. Engine_->updateGlobalMapping(llvm::StringRef(fullName.data(), fullName.size()), (uint64_t)ctl);
  626. ReverseGlobalMapping_[&ctl] = fullName;
  627. }
  628. }
  629. }
  630. struct TPatterns {
  631. TPatterns()
  632. : Imm_(re2::StringPiece("\\s*movabs\\s+[0-9a-z]+\\s*,\\s*(\\d+)\\s*"))
  633. , Jump_(re2::StringPiece("\\s*(?:j[a-z]+)\\s*(-?\\d+)\\s*"))
  634. {}
  635. re2::RE2 Imm_;
  636. re2::RE2 Jump_;
  637. };
  638. void InitRegexps() {
  639. if (!Patterns_) {
  640. Patterns_.ConstructInPlace();
  641. }
  642. }
  643. const ETarget Target_;
  644. const ESanitize Sanitize_;
  645. ETarget EffectiveTarget_;
  646. ESanitize EffectiveSanitize_;
  647. llvm::LLVMContext Context_;
  648. std::string Diagnostic_;
  649. std::string Triple_;
  650. llvm::Module* Module_;
  651. #ifdef __linux__
  652. llvm::JITEventListener* PerfListener_ = nullptr;
  653. #endif
  654. std::unique_ptr<llvm::ExecutionEngine> Engine_;
  655. std::vector<std::pair<llvm::object::SectionRef, ui64>> CodeSections_;
  656. ui64 TotalObjectSize = 0;
  657. std::vector<std::pair<ui64, llvm::Function*>> SortedFuncs_;
  658. TMaybe<THashSet<TString>> ExportedSymbols;
  659. THashMap<const void*, TString> ReverseGlobalMapping_;
  660. TMaybe<TPatterns> Patterns_;
  661. TTlsManager TlsManager_;
  662. THashSet<TString> LoadedModules_;
  663. };
  664. ICodegen::TPtr
  665. ICodegen::Make(ETarget target, ESanitize sanitize) {
  666. return std::make_unique<TCodegen>(target, sanitize);
  667. }
  668. ICodegen::TSharedPtr
  669. ICodegen::MakeShared(ETarget target, ESanitize sanitize) {
  670. return std::make_shared<TCodegen>(target, sanitize);
  671. }
  672. }
  673. }