mkql_computation_node_codegen.cpp 117 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543
  1. #include "mkql_computation_node_codegen.h" // Y_IGNORE
  2. #include "mkql_computation_node_holders.h"
  3. #include <yql/essentials/minikql/codegen/codegen.h>
  4. #include <yql/essentials/public/decimal/yql_decimal.h>
  5. #include <util/string/cast.h>
  6. #include <util/folder/path.h>
  7. #ifndef MKQL_DISABLE_CODEGEN
  8. extern "C" void DeleteBoxed(NKikimr::NUdf::IBoxedValue *const boxed) {
  9. delete boxed;
  10. }
  11. extern "C" void DeleteString(void* strData) {
  12. auto& str = *(NKikimr::NUdf::TStringValue*)(&strData);
  13. UdfFreeWithSize(strData, 16 + str.Capacity());
  14. }
  15. namespace NKikimr {
  16. namespace NMiniKQL {
  17. constexpr bool EnableStaticRefcount = true;
  18. using namespace llvm;
  19. Type* GetStringRefType(LLVMContext &context) {
  20. const auto stringRefType = StructType::get(context, {
  21. Type::getInt8PtrTy(context),
  22. Type::getInt32Ty(context),
  23. Type::getInt32Ty(context)
  24. });
  25. return stringRefType;
  26. }
  27. Type* GetSourcePosType(LLVMContext &context) {
  28. const auto sourcePosType = StructType::get(context, {
  29. Type::getInt32Ty(context),
  30. Type::getInt32Ty(context),
  31. GetStringRefType(context)
  32. });
  33. return sourcePosType;
  34. }
  35. Type* GetCompContextType(LLVMContext &context) {
  36. const auto ptrValueType = PointerType::getUnqual(Type::getInt128Ty(context));
  37. const auto structPtrType = PointerType::getUnqual(StructType::get(context));
  38. const auto sourcePosType = GetSourcePosType(context);
  39. return StructType::get(context, {
  40. structPtrType, // factory
  41. structPtrType, // stats
  42. ptrValueType, // mutables
  43. structPtrType, // builder
  44. Type::getFloatTy(context), // adjustor
  45. Type::getInt32Ty(context), // rsscounter
  46. PointerType::getUnqual(sourcePosType)
  47. });
  48. }
  49. Value* TCodegenContext::GetFactory() const {
  50. if (!Factory) {
  51. auto& context = Codegen.GetContext();
  52. const auto indexType = Type::getInt32Ty(context);
  53. const auto ptrType = PointerType::getUnqual(StructType::get(context));
  54. if (Func->getEntryBlock().empty()) {
  55. const auto ptr = GetElementPtrInst::CreateInBounds(GetCompContextType(context), Ctx, {ConstantInt::get(indexType, 0), ConstantInt::get(indexType, 0)}, "factory_ptr", &Func->getEntryBlock());
  56. const_cast<Value*&>(Factory) = new LoadInst(ptrType, ptr, "factory", &Func->getEntryBlock());
  57. } else {
  58. const auto ptr = GetElementPtrInst::CreateInBounds(GetCompContextType(context), Ctx, {ConstantInt::get(indexType, 0), ConstantInt::get(indexType, 0)}, "factory_ptr", &Func->getEntryBlock().front());
  59. const_cast<Value*&>(Factory) = new LoadInst(ptrType, ptr, "factory", &Func->getEntryBlock().back());
  60. }
  61. }
  62. return Factory;
  63. }
  64. Value* TCodegenContext::GetStat() const {
  65. if (!Stat) {
  66. auto& context = Codegen.GetContext();
  67. const auto indexType = Type::getInt32Ty(context);
  68. const auto ptrType = PointerType::getUnqual(StructType::get(context));
  69. if (Func->getEntryBlock().empty()) {
  70. const auto ptr = GetElementPtrInst::CreateInBounds(GetCompContextType(context), Ctx, {ConstantInt::get(indexType, 0), ConstantInt::get(indexType, 1)}, "stat_ptr", &Func->getEntryBlock());
  71. const_cast<Value*&>(Stat) = new LoadInst(ptrType, ptr, "stat", &Func->getEntryBlock());
  72. } else {
  73. const auto ptr = GetElementPtrInst::CreateInBounds(GetCompContextType(context), Ctx, {ConstantInt::get(indexType, 0), ConstantInt::get(indexType, 1)}, "stat_ptr", &Func->getEntryBlock().front());
  74. const_cast<Value*&>(Stat) = new LoadInst(ptrType, ptr, "stat", &Func->getEntryBlock().back());
  75. }
  76. }
  77. return Stat;
  78. }
  79. Value* TCodegenContext::GetMutables() const {
  80. if (!Mutables) {
  81. auto& context = Codegen.GetContext();
  82. const auto indexType = Type::getInt32Ty(context);
  83. const auto ptrType = PointerType::getUnqual(Type::getInt128Ty(context));
  84. if (Func->getEntryBlock().empty()) {
  85. const auto ptr = GetElementPtrInst::CreateInBounds(GetCompContextType(context), Ctx, {ConstantInt::get(indexType, 0), ConstantInt::get(indexType, 2)}, "mutables_ptr", &Func->getEntryBlock());
  86. const_cast<Value*&>(Mutables) = new LoadInst(ptrType, ptr, "mutables", &Func->getEntryBlock());
  87. } else {
  88. const auto ptr = GetElementPtrInst::CreateInBounds(GetCompContextType(context), Ctx, {ConstantInt::get(indexType, 0), ConstantInt::get(indexType, 2)}, "mutables_ptr", &Func->getEntryBlock().front());
  89. const_cast<Value*&>(Mutables) = new LoadInst(ptrType, ptr, "mutables", &Func->getEntryBlock().back());
  90. }
  91. }
  92. return Mutables;
  93. }
  94. Value* TCodegenContext::GetBuilder() const {
  95. if (!Builder) {
  96. auto& context = Codegen.GetContext();
  97. const auto indexType = Type::getInt32Ty(context);
  98. const auto ptrType = PointerType::getUnqual(StructType::get(context));
  99. if (Func->getEntryBlock().empty()) {
  100. const auto ptr = GetElementPtrInst::CreateInBounds(GetCompContextType(context), Ctx, {ConstantInt::get(indexType, 0), ConstantInt::get(indexType, 3)}, "builder_ptr", &Func->getEntryBlock());
  101. const_cast<Value*&>(Builder) = new LoadInst(ptrType, ptr, "builder", &Func->getEntryBlock());
  102. } else {
  103. const auto ptr = GetElementPtrInst::CreateInBounds(GetCompContextType(context), Ctx, {ConstantInt::get(indexType, 0), ConstantInt::get(indexType, 3)}, "builder_ptr", &Func->getEntryBlock().front());
  104. const_cast<Value*&>(Builder) = new LoadInst(ptrType, ptr, "builder", &Func->getEntryBlock().back());
  105. }
  106. }
  107. return Builder;
  108. }
  109. Function* GenerateCompareFunction(NYql::NCodegen::ICodegen& codegen, const TString& name, IComputationExternalNode* left,
  110. IComputationExternalNode* right, IComputationNode* compare) {
  111. auto& module = codegen.GetModule();
  112. if (const auto f = module.getFunction(name.c_str()))
  113. return f;
  114. const auto codegenLeft = dynamic_cast<ICodegeneratorExternalNode*>(left);
  115. const auto codegenRight = dynamic_cast<ICodegeneratorExternalNode*>(right);
  116. MKQL_ENSURE(codegenLeft, "Left must be codegenerator node.");
  117. MKQL_ENSURE(codegenRight, "Right must be codegenerator node.");
  118. auto& context = codegen.GetContext();
  119. const auto valueType = Type::getInt128Ty(context);
  120. const auto returnType = Type::getInt1Ty(context);
  121. const auto contextType = GetCompContextType(context);
  122. const auto funcType =
  123. FunctionType::get(returnType, {PointerType::getUnqual(contextType), valueType, valueType}, false);
  124. TCodegenContext ctx(codegen);
  125. ctx.AlwaysInline = true;
  126. ctx.Func = cast<Function>(module.getOrInsertFunction(name.c_str(), funcType).getCallee());
  127. DISubprogramAnnotator annotator(ctx, ctx.Func);
  128. auto args = ctx.Func->arg_begin();
  129. const auto main = BasicBlock::Create(context, "main", ctx.Func);
  130. auto block = main;
  131. ctx.Ctx = &*args;
  132. ctx.Ctx->addAttr(Attribute::NonNull);
  133. const auto lv = &*++args;
  134. const auto rv = &*++args;
  135. const auto lvType = funcType->getParamType(1);
  136. const auto rvType = funcType->getParamType(2);
  137. codegenLeft->SetValueBuilder([lv, lvType](const TCodegenContext&) { return std::make_pair(lv, lvType); });
  138. codegenRight->SetValueBuilder([rv, rvType](const TCodegenContext&) { return std::make_pair(rv, rvType); });
  139. codegenLeft->CreateInvalidate(ctx, block);
  140. codegenRight->CreateInvalidate(ctx, block);
  141. const auto res = GetNodeValue(compare, ctx, block);
  142. const auto cast = CastInst::Create(Instruction::Trunc, res, returnType, "bool", block);
  143. ReturnInst::Create(context, cast, block);
  144. codegenLeft->SetValueBuilder({});
  145. codegenRight->SetValueBuilder({});
  146. return ctx.Func;
  147. }
  148. Value* GetterFor(NUdf::EDataSlot slot, Value* value, LLVMContext &context, BasicBlock* block) {
  149. switch (slot) {
  150. case NUdf::EDataSlot::Bool: return GetterFor<bool>(value, context, block);
  151. case NUdf::EDataSlot::Decimal: return GetterForInt128(value, block);
  152. case NUdf::EDataSlot::Float: return GetterFor<float>(value, context, block);
  153. case NUdf::EDataSlot::Double: return GetterFor<double>(value, context, block);
  154. default: break;
  155. }
  156. const auto trunc = CastInst::Create(Instruction::Trunc, value, IntegerType::get(context, NUdf::GetDataTypeInfo(slot).FixedSize << 3U), "trunc", block);
  157. return trunc;
  158. }
  159. namespace {
  160. Value* GetMarkFromUnboxed(Value* value, const TCodegenContext& ctx, BasicBlock* block) {
  161. auto& context = ctx.Codegen.GetContext();
  162. const auto type8 = Type::getInt8Ty(context);
  163. if (value->getType()->isPointerTy()) {
  164. const auto type = StructType::get(context, {PointerType::getUnqual(StructType::get(context)), ArrayType::get(type8, 8U)});
  165. const auto cast = CastInst::Create(Instruction::BitCast, value, PointerType::getUnqual(type), "cast", block);
  166. const auto type32 = Type::getInt32Ty(context);
  167. const auto metaptr = GetElementPtrInst::CreateInBounds(type, cast, {ConstantInt::get(type32, 0), ConstantInt::get(type32, 1), ConstantInt::get(type32, 7)}, "metaptr", block);
  168. const auto meta = new LoadInst(type8, metaptr, "meta", block);
  169. const auto mark = BinaryOperator::CreateAnd(meta, ConstantInt::get(meta->getType(), 3), "mark", block);
  170. return mark;
  171. } else {
  172. const auto lshr = BinaryOperator::CreateLShr(value, ConstantInt::get(value->getType(), 120), "lshr", block);
  173. const auto meta = CastInst::Create(Instruction::Trunc, lshr, type8, "meta", block);
  174. const auto mark = BinaryOperator::CreateAnd(ConstantInt::get(meta->getType(), 3), meta, "mark", block);
  175. return mark;
  176. }
  177. }
  178. template<bool BoxedOrString>
  179. std::pair<Value*,Type*> GetPointerFromUnboxed(Value* value, const TCodegenContext& ctx, BasicBlock* block) {
  180. auto& context = ctx.Codegen.GetContext();
  181. const auto type32 = Type::getInt32Ty(context);
  182. const auto type64 = Type::getInt64Ty(context);
  183. const auto elemType = BoxedOrString ?
  184. StructType::get(context, {PointerType::getUnqual(StructType::get(context)), type32, Type::getInt16Ty(context)}):
  185. StructType::get(context, {type32, type32, type32, type32});
  186. const auto type = PointerType::getUnqual(elemType);
  187. if (value->getType()->isPointerTy()) {
  188. const auto strType = StructType::get(context, {type, type64});
  189. const auto cast = CastInst::Create(Instruction::BitCast, value, PointerType::getUnqual(strType), "cast", block);
  190. const auto ptr = GetElementPtrInst::CreateInBounds(strType, cast, {ConstantInt::get(type32, 0), ConstantInt::get(type32, 0)}, "ptr", block);
  191. const auto pointer = new LoadInst(type, ptr, "pointer", block);
  192. return {pointer, elemType};
  193. } else {
  194. const auto half = CastInst::Create(Instruction::Trunc, value, type64, "half", block);
  195. const auto pointer = CastInst::Create(Instruction::IntToPtr, half, type, "pointer", block);
  196. return {pointer, elemType};
  197. }
  198. }
  199. ui32 MyCompareStrings(NUdf::TUnboxedValuePod lhs, NUdf::TUnboxedValuePod rhs) {
  200. return NUdf::CompareStrings(lhs, rhs);
  201. }
  202. bool MyEquteStrings(NUdf::TUnboxedValuePod lhs, NUdf::TUnboxedValuePod rhs) {
  203. return NUdf::EquateStrings(lhs, rhs);
  204. }
  205. NUdf::THashType MyHashString(NUdf::TUnboxedValuePod val) {
  206. return NUdf::GetStringHash(val);
  207. }
  208. template <bool IsOptional>
  209. Value* GenEqualsFunction(NUdf::EDataSlot slot, Value* lv, Value* rv, TCodegenContext& ctx, BasicBlock*& block);
  210. template <>
  211. Value* GenEqualsFunction<false>(NUdf::EDataSlot slot, Value* lv, Value* rv, TCodegenContext& ctx, BasicBlock*& block) {
  212. auto& context = ctx.Codegen.GetContext();
  213. const auto& info = NUdf::GetDataTypeInfo(slot);
  214. if ((info.Features & NUdf::EDataTypeFeatures::CommonType) && (info.Features & NUdf::EDataTypeFeatures::StringType || NUdf::EDataSlot::Uuid == slot || NUdf::EDataSlot::DyNumber == slot)) {
  215. return CallBinaryUnboxedValueFunction(&MyEquteStrings, Type::getInt1Ty(context), lv, rv, ctx.Codegen, block);
  216. }
  217. const auto lhs = GetterFor(slot, lv, context, block);
  218. const auto rhs = GetterFor(slot, rv, context, block);
  219. if (info.Features & (NUdf::EDataTypeFeatures::IntegralType | NUdf::EDataTypeFeatures::DateType | NUdf::EDataTypeFeatures::TimeIntervalType | NUdf::EDataTypeFeatures::DecimalType) || NUdf::EDataSlot::Bool == slot) {
  220. const auto equal = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_EQ, lhs, rhs, "equal", block);
  221. return equal;
  222. }
  223. if (info.Features & NUdf::EDataTypeFeatures::FloatType) {
  224. const auto ueq = CmpInst::Create(Instruction::FCmp, FCmpInst::FCMP_UEQ, lhs, rhs, "equals", block);
  225. const auto lord = CmpInst::Create(Instruction::FCmp, FCmpInst::FCMP_ORD, ConstantFP::get(lhs->getType(), 0.0), lhs, "lord", block);
  226. const auto runo = CmpInst::Create(Instruction::FCmp, FCmpInst::FCMP_UNO, ConstantFP::get(rhs->getType(), 0.0), rhs, "runo", block);
  227. const auto once = BinaryOperator::CreateXor(lord, runo, "xor", block);
  228. return BinaryOperator::CreateAnd(ueq, once, "and", block);
  229. }
  230. if (info.Features & NUdf::EDataTypeFeatures::TzDateType) {
  231. const auto ltz = GetterForTimezone(context, lv, block);
  232. const auto rtz = GetterForTimezone(context, rv, block);
  233. const auto one = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_EQ, lhs, rhs, "one", block);
  234. const auto two = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_EQ, ltz, rtz, "two", block);
  235. return BinaryOperator::CreateAnd(one, two, "and", block);
  236. }
  237. return nullptr;
  238. }
  239. template <>
  240. Value* GenEqualsFunction<true>(NUdf::EDataSlot slot, Value* lv, Value* rv, TCodegenContext& ctx, BasicBlock*& block) {
  241. auto& context = ctx.Codegen.GetContext();
  242. const auto tiny = BasicBlock::Create(context, "tiny", ctx.Func);
  243. const auto test = BasicBlock::Create(context, "test", ctx.Func);
  244. const auto done = BasicBlock::Create(context, "done", ctx.Func);
  245. const auto res = PHINode::Create(Type::getInt1Ty(context), 2U, "result", done);
  246. const auto le = IsEmpty(lv, block, context);
  247. const auto re = IsEmpty(rv, block, context);
  248. const auto any = BinaryOperator::CreateOr(le, re, "or", block);
  249. BranchInst::Create(tiny, test, any, block);
  250. block = tiny;
  251. const auto both = BinaryOperator::CreateAnd(le, re, "and", block);
  252. res->addIncoming(both, block);
  253. BranchInst::Create(done, block);
  254. block = test;
  255. const auto comp = GenEqualsFunction<false>(slot, lv, rv, ctx, block);
  256. res->addIncoming(comp, block);
  257. BranchInst::Create(done, block);
  258. block = done;
  259. return res;
  260. }
  261. Value* GenEqualsFunction(NUdf::EDataSlot slot, bool isOptional, Value* lv, Value* rv, TCodegenContext& ctx, BasicBlock*& block) {
  262. return isOptional ? GenEqualsFunction<true>(slot, lv, rv, ctx, block) : GenEqualsFunction<false>(slot, lv, rv, ctx, block);
  263. }
  264. template <bool IsOptional>
  265. Value* GenCompareFunction(NUdf::EDataSlot slot, Value* lv, Value* rv, TCodegenContext& ctx, BasicBlock*& block);
  266. template <>
  267. Value* GenCompareFunction<false>(NUdf::EDataSlot slot, Value* lv, Value* rv, TCodegenContext& ctx, BasicBlock*& block) {
  268. auto& context = ctx.Codegen.GetContext();
  269. const auto& info = NUdf::GetDataTypeInfo(slot);
  270. if ((info.Features & NUdf::EDataTypeFeatures::CommonType) && (info.Features & NUdf::EDataTypeFeatures::StringType || NUdf::EDataSlot::Uuid == slot || NUdf::EDataSlot::DyNumber == slot)) {
  271. return CallBinaryUnboxedValueFunction(&MyCompareStrings, Type::getInt32Ty(context), lv, rv, ctx.Codegen, block);
  272. }
  273. const bool extra = info.Features & (NUdf::EDataTypeFeatures::FloatType | NUdf::EDataTypeFeatures::TzDateType);
  274. const auto resultType = Type::getInt32Ty(context);
  275. const auto exit = BasicBlock::Create(context, "exit", ctx.Func);
  276. const auto test = BasicBlock::Create(context, "test", ctx.Func);
  277. const auto res = PHINode::Create(resultType, extra ? 3U : 2U, "result", exit);
  278. const auto lhs = GetterFor(slot, lv, context, block);
  279. const auto rhs = GetterFor(slot, rv, context, block);
  280. if (info.Features & NUdf::EDataTypeFeatures::FloatType) {
  281. const auto more = BasicBlock::Create(context, "more", ctx.Func);
  282. const auto next = BasicBlock::Create(context, "next", ctx.Func);
  283. const auto uno = CmpInst::Create(Instruction::FCmp, FCmpInst::FCMP_UNO, lhs, rhs, "unorded", block);
  284. BranchInst::Create(more, next, uno, block);
  285. block = more;
  286. const auto luno = CmpInst::Create(Instruction::FCmp, FCmpInst::FCMP_UNO, ConstantFP::get(lhs->getType(), 0.0), lhs, "luno", block);
  287. const auto runo = CmpInst::Create(Instruction::FCmp, FCmpInst::FCMP_UNO, ConstantFP::get(rhs->getType(), 0.0), rhs, "runo", block);
  288. const auto once = BinaryOperator::CreateXor(luno, runo, "xor", block);
  289. const auto left = SelectInst::Create(luno, ConstantInt::get(resultType, 1), ConstantInt::get(resultType, -1), "left", block);
  290. const auto both = SelectInst::Create(once, left, ConstantInt::get(resultType, 0), "both", block);
  291. res->addIncoming(both, block);
  292. BranchInst::Create(exit, block);
  293. block = next;
  294. }
  295. const auto equals = info.Features & NUdf::EDataTypeFeatures::FloatType ?
  296. CmpInst::Create(Instruction::FCmp, FCmpInst::FCMP_OEQ, lhs, rhs, "equals", block):
  297. CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_EQ, lhs, rhs, "equals", block);
  298. if (info.Features & NUdf::EDataTypeFeatures::TzDateType) {
  299. const auto more = BasicBlock::Create(context, "more", ctx.Func);
  300. const auto next = BasicBlock::Create(context, "next", ctx.Func);
  301. BranchInst::Create(more, test, equals, block);
  302. block = more;
  303. const auto ltz = GetterForTimezone(context, lv, block);
  304. const auto rtz = GetterForTimezone(context, rv, block);
  305. const auto tzeq = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_EQ, ltz, rtz, "tzeq", block);
  306. res->addIncoming(ConstantInt::get(resultType, 0), block);
  307. BranchInst::Create(exit, next, tzeq, block);
  308. block = next;
  309. const auto tzlt = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_ULT, ltz, rtz, "tzlt", block);
  310. const auto tzout = SelectInst::Create(tzlt, ConstantInt::get(resultType, -1), ConstantInt::get(resultType, 1), "tzout", block);
  311. res->addIncoming(tzout, block);
  312. BranchInst::Create(exit, block);
  313. } else {
  314. res->addIncoming(ConstantInt::get(resultType, 0), block);
  315. BranchInst::Create(exit, test, equals, block);
  316. }
  317. block = test;
  318. const auto less = info.Features & NUdf::EDataTypeFeatures::FloatType ?
  319. CmpInst::Create(Instruction::FCmp, FCmpInst::FCMP_OLT, lhs, rhs, "less", block): // float
  320. info.Features & (NUdf::EDataTypeFeatures::SignedIntegralType | NUdf::EDataTypeFeatures::TimeIntervalType | NUdf::EDataTypeFeatures::DecimalType) ?
  321. CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_SLT, lhs, rhs, "less", block): // signed
  322. info.Features & (NUdf::EDataTypeFeatures::UnsignedIntegralType | NUdf::EDataTypeFeatures::DateType | NUdf::EDataTypeFeatures::TzDateType) ?
  323. CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_ULT, lhs, rhs, "less", block): // unsigned
  324. rhs; // bool
  325. const auto out = SelectInst::Create(less, ConstantInt::get(resultType, -1), ConstantInt::get(resultType, 1), "out", block);
  326. res->addIncoming(out, block);
  327. BranchInst::Create(exit, block);
  328. block = exit;
  329. return res;
  330. }
  331. template <>
  332. Value* GenCompareFunction<true>(NUdf::EDataSlot slot, Value* lv, Value* rv, TCodegenContext& ctx, BasicBlock*& block) {
  333. auto& context = ctx.Codegen.GetContext();
  334. const auto tiny = BasicBlock::Create(context, "tiny", ctx.Func);
  335. const auto side = BasicBlock::Create(context, "side", ctx.Func);
  336. const auto test = BasicBlock::Create(context, "test", ctx.Func);
  337. const auto done = BasicBlock::Create(context, "done", ctx.Func);
  338. const auto resultType = Type::getInt32Ty(context);
  339. const auto res = PHINode::Create(resultType, 3U, "result", done);
  340. const auto le = IsEmpty(lv, block, context);
  341. const auto re = IsEmpty(rv, block, context);
  342. const auto any = BinaryOperator::CreateOr(le, re, "or", block);
  343. BranchInst::Create(tiny, test, any, block);
  344. block = tiny;
  345. const auto both = BinaryOperator::CreateAnd(le, re, "and", block);
  346. res->addIncoming(ConstantInt::get(resultType, 0), block);
  347. BranchInst::Create(done, side, both, block);
  348. block = side;
  349. const auto out = SelectInst::Create(le, ConstantInt::get(resultType, -1), ConstantInt::get(resultType, 1), "out", block);
  350. res->addIncoming(out, block);
  351. BranchInst::Create(done, block);
  352. block = test;
  353. const auto comp = GenCompareFunction<false>(slot, lv, rv, ctx, block);
  354. res->addIncoming(comp, block);
  355. BranchInst::Create(done, block);
  356. block = done;
  357. return res;
  358. }
  359. Value* GenCompareFunction(NUdf::EDataSlot slot, bool isOptional, Value* lv, Value* rv, TCodegenContext& ctx, BasicBlock*& block) {
  360. return isOptional ? GenCompareFunction<true>(slot, lv, rv, ctx, block) : GenCompareFunction<false>(slot, lv, rv, ctx, block);
  361. }
  362. Value* GenCombineHashes(Value* first, Value* second, BasicBlock* block) {
  363. // key += ~(key << 32);
  364. const auto x01 = BinaryOperator::CreateShl(first, ConstantInt::get(first->getType(), 32), "x01", block);
  365. const auto x02 = BinaryOperator::CreateXor(x01, ConstantInt::get(x01->getType(), ~0), "x02", block);
  366. const auto x03 = BinaryOperator::CreateAdd(x02, first, "x03", block);
  367. // key ^= (key >> 22);
  368. const auto x04 = BinaryOperator::CreateLShr(x03, ConstantInt::get(x03->getType(), 22), "x04", block);
  369. const auto x05 = BinaryOperator::CreateXor(x04, x03, "x05", block);
  370. // key += ~(key << 13);
  371. const auto x06 = BinaryOperator::CreateShl(x05, ConstantInt::get(x05->getType(), 13), "x06", block);
  372. const auto x07 = BinaryOperator::CreateXor(x06, ConstantInt::get(x06->getType(), ~0), "x07", block);
  373. const auto x08 = BinaryOperator::CreateAdd(x05, x07, "x08", block);
  374. // key ^= (key >> 8);
  375. const auto x09 = BinaryOperator::CreateLShr(x08, ConstantInt::get(x08->getType(), 8), "x09", block);
  376. const auto x10 = BinaryOperator::CreateXor(x08, x09, "x10", block);
  377. // key += (key << 3);
  378. const auto x11 = BinaryOperator::CreateShl(x10, ConstantInt::get(x10->getType(), 3), "x11", block);
  379. const auto x12 = BinaryOperator::CreateAdd(x10, x11, "x12", block);
  380. // key ^= (key >> 15);
  381. const auto x13 = BinaryOperator::CreateLShr(x12, ConstantInt::get(x12->getType(), 15), "x13", block);
  382. const auto x14 = BinaryOperator::CreateXor(x13, x12, "x14", block);
  383. // key += ~(key << 27);
  384. const auto x15 = BinaryOperator::CreateShl(x14, ConstantInt::get(x14->getType(), 27), "x15", block);
  385. const auto x16 = BinaryOperator::CreateXor(x15, ConstantInt::get(x15->getType(), ~0), "x16", block);
  386. const auto x17 = BinaryOperator::CreateAdd(x14, x16, "x17", block);
  387. // key ^= (key >> 31);
  388. const auto x18 = BinaryOperator::CreateLShr(x17, ConstantInt::get(x17->getType(), 31), "x18", block);
  389. const auto x19 = BinaryOperator::CreateXor(x17, x18, "x19", block);
  390. return BinaryOperator::CreateXor(x19, second, "both", block);
  391. }
  392. template <bool IsOptional>
  393. Value* GenHashFunction(NUdf::EDataSlot slot, Value* value, TCodegenContext& ctx, BasicBlock*& block);
  394. template <>
  395. Value* GenHashFunction<false>(NUdf::EDataSlot slot, Value* value, TCodegenContext& ctx, BasicBlock*& block) {
  396. auto& context = ctx.Codegen.GetContext();
  397. const auto& info = NUdf::GetDataTypeInfo(slot);
  398. if ((info.Features & NUdf::EDataTypeFeatures::CommonType) && (info.Features & NUdf::EDataTypeFeatures::StringType || NUdf::EDataSlot::Uuid == slot || NUdf::EDataSlot::DyNumber == slot)) {
  399. return CallUnaryUnboxedValueFunction(&MyHashString, Type::getInt64Ty(context), value, ctx.Codegen, block);
  400. }
  401. const auto val = GetterFor(slot, value, context, block);
  402. const auto hashType = Type::getInt64Ty(context);
  403. if (info.Features & (NUdf::EDataTypeFeatures::IntegralType | NUdf::EDataTypeFeatures::DateType | NUdf::EDataTypeFeatures::TimeIntervalType) || NUdf::EDataSlot::Bool == slot) {
  404. if (val->getType() == hashType) {
  405. return val;
  406. }
  407. const auto ext = CastInst::Create(Instruction::ZExt, val, hashType, "ext", block);
  408. return ext;
  409. }
  410. if (info.Features & NUdf::EDataTypeFeatures::FloatType) {
  411. const auto nan = CmpInst::Create(Instruction::FCmp, FCmpInst::FCMP_UNO, val, val, "nan", block);
  412. const auto zero = CmpInst::Create(Instruction::FCmp, FCmpInst::FCMP_OEQ, val, ConstantFP::get(val->getType(), 0), "zero", block);
  413. if (NUdf::EDataSlot::Float == slot) {
  414. const auto cast = CastInst::Create(Instruction::BitCast, val, Type::getInt32Ty(context), "cast", block);
  415. const auto ext = CastInst::Create(Instruction::ZExt, cast, hashType, "ext", block);
  416. const auto first = SelectInst::Create(nan, ConstantInt::get(hashType, ~0), ext, "first", block);
  417. const auto second = SelectInst::Create(zero, ConstantInt::get(hashType, 0), first, "second", block);
  418. return second;
  419. } else {
  420. const auto cast = CastInst::Create(Instruction::BitCast, val, hashType, "cast", block);
  421. const auto first = SelectInst::Create(nan, ConstantInt::get(hashType, ~0), cast, "first", block);
  422. const auto second = SelectInst::Create(zero, ConstantInt::get(hashType, 0), first, "second", block);
  423. return second;
  424. }
  425. }
  426. if (info.Features & NUdf::EDataTypeFeatures::TzDateType) {
  427. const auto tz = GetterForTimezone(context, value, block);
  428. const auto ext = val->getType() == hashType ? val : CastInst::Create(Instruction::ZExt, val, hashType, "ext", block);
  429. const auto etz = CastInst::Create(Instruction::ZExt, tz, hashType, "etz", block);
  430. return GenCombineHashes(ext, etz, block);
  431. }
  432. if (info.Features & NUdf::EDataTypeFeatures::DecimalType) {
  433. const auto low = CastInst::Create(Instruction::Trunc, val, hashType, "low", block);
  434. const auto lshr = BinaryOperator::CreateLShr(val, ConstantInt::get(val->getType(), 64), "lshr", block);
  435. const auto high = CastInst::Create(Instruction::Trunc, lshr, hashType, "high", block);
  436. return GenCombineHashes(low, high, block);
  437. }
  438. return nullptr;
  439. }
  440. template <>
  441. Value* GenHashFunction<true>(NUdf::EDataSlot slot, Value* value, TCodegenContext& ctx, BasicBlock*& block) {
  442. auto& context = ctx.Codegen.GetContext();
  443. const auto tiny = BasicBlock::Create(context, "tiny", ctx.Func);
  444. const auto test = BasicBlock::Create(context, "test", ctx.Func);
  445. const auto done = BasicBlock::Create(context, "done", ctx.Func);
  446. const auto res = PHINode::Create(Type::getInt64Ty(context), 2U, "result", done);
  447. BranchInst::Create(tiny, test, IsEmpty(value, block, context), block);
  448. block = tiny;
  449. res->addIncoming(ConstantInt::get(Type::getInt64Ty(context), ~0ULL), block);
  450. BranchInst::Create(done, block);
  451. block = test;
  452. const auto comp = GenHashFunction<false>(slot, value, ctx, block);
  453. res->addIncoming(comp, block);
  454. BranchInst::Create(done, block);
  455. block = done;
  456. return res;
  457. }
  458. Value* GenHashFunction(NUdf::EDataSlot slot, bool isOptional, Value* value, TCodegenContext& ctx, BasicBlock*& block) {
  459. return isOptional ? GenHashFunction<true>(slot, value, ctx, block) : GenHashFunction<false>(slot, value, ctx, block);
  460. }
  461. Value* LoadIfPointer(Value* value, Type* itemType, BasicBlock* block) {
  462. return value->getType()->isPointerTy() ? new LoadInst(itemType, value, "load_value", block) : value;
  463. }
  464. }
  465. Function* GenerateEqualsFunction(NYql::NCodegen::ICodegen& codegen, const TString& name, bool isTuple, const TKeyTypes& types) {
  466. auto& module = codegen.GetModule();
  467. if (const auto f = module.getFunction(name.c_str()))
  468. return f;
  469. auto& context = codegen.GetContext();
  470. const auto valueType = Type::getInt128Ty(context);
  471. const auto returnType = Type::getInt1Ty(context);
  472. const auto funcType =
  473. FunctionType::get(returnType, {valueType, valueType}, false);
  474. TCodegenContext ctx(codegen);
  475. ctx.AlwaysInline = true;
  476. ctx.Func = cast<Function>(module.getOrInsertFunction(name.c_str(), funcType).getCallee());
  477. DISubprogramAnnotator annotator(ctx, ctx.Func);
  478. auto args = ctx.Func->arg_begin();
  479. const auto main = BasicBlock::Create(context, "main", ctx.Func);
  480. auto block = main;
  481. const auto lv = LoadIfPointer(&*args, funcType->getParamType(0), block);
  482. const auto rv = LoadIfPointer(&*++args, funcType->getParamType(1), block);
  483. if (isTuple) {
  484. if (types.empty()) {
  485. ReturnInst::Create(context, ConstantInt::getTrue(context), block);
  486. return ctx.Func;
  487. }
  488. const auto fast = BasicBlock::Create(context, "fast", ctx.Func);
  489. const auto slow = BasicBlock::Create(context, "slow", ctx.Func);
  490. const auto stop = BasicBlock::Create(context, "stop", ctx.Func);
  491. const auto elementsType = ArrayType::get(valueType, types.size());
  492. const auto elementsPtrType = PointerType::getUnqual(elementsType);
  493. const auto elementsPtrOne = CallBoxedValueVirtualMethod<NUdf::TBoxedValueAccessor::EMethod::GetElements>(elementsPtrType, lv, ctx.Codegen, block);
  494. const auto elementsPtrTwo = CallBoxedValueVirtualMethod<NUdf::TBoxedValueAccessor::EMethod::GetElements>(elementsPtrType, rv, ctx.Codegen, block);
  495. const auto goodOne = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_NE, elementsPtrOne, ConstantPointerNull::get(elementsPtrType), "good_one", block);
  496. const auto goodTwo = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_NE, elementsPtrTwo, ConstantPointerNull::get(elementsPtrType), "good_two", block);
  497. const auto good = BinaryOperator::CreateAnd(goodOne, goodTwo, "good", block);
  498. BranchInst::Create(fast, slow, good, block);
  499. const auto last = types.size() - 1U;
  500. {
  501. block = fast;
  502. const auto elementsOne = new LoadInst(elementsType, elementsPtrOne, "elements_one", block);
  503. const auto elementsTwo = new LoadInst(elementsType, elementsPtrTwo, "elements_two", block);
  504. for (ui32 i = 0U; i < last; ++i) {
  505. const auto nextOne = ExtractValueInst::Create(elementsOne, i, (TString("next_one_") += ToString(i)).c_str(), block);
  506. const auto nextTwo = ExtractValueInst::Create(elementsTwo, i, (TString("next_two_") += ToString(i)).c_str(), block);
  507. const auto step = BasicBlock::Create(context, (TString("step") += ToString(i)).c_str(), ctx.Func);
  508. const auto test = GenEqualsFunction(types[i].first, types[i].second, nextOne, nextTwo, ctx, block);
  509. BranchInst::Create(step, stop, test, block);
  510. block = step;
  511. }
  512. const auto backOne = ExtractValueInst::Create(elementsOne, last, "back_one", block);
  513. const auto backTwo = ExtractValueInst::Create(elementsTwo, last, "back_two", block);
  514. const auto result = GenEqualsFunction(types.back().first, types.back().second, backOne, backTwo, ctx, block);
  515. ReturnInst::Create(context, result, block);
  516. }
  517. {
  518. block = slow;
  519. const auto elementOne = new AllocaInst(valueType, 0U, "element_one", block);
  520. const auto elementTwo = new AllocaInst(valueType, 0U, "element_two", block);
  521. const auto indexType = Type::getInt32Ty(context);
  522. for (ui32 i = 0U; i < last; ++i) {
  523. CallBoxedValueVirtualMethod<NUdf::TBoxedValueAccessor::EMethod::GetElement>(elementOne, lv, ctx.Codegen, block, ConstantInt::get(indexType, i));
  524. CallBoxedValueVirtualMethod<NUdf::TBoxedValueAccessor::EMethod::GetElement>(elementTwo, rv, ctx.Codegen, block, ConstantInt::get(indexType, i));
  525. const auto nextOne = new LoadInst(valueType, elementOne, (TString("next_one_") += ToString(i)).c_str(), block);
  526. const auto nextTwo = new LoadInst(valueType, elementTwo, (TString("next_two_") += ToString(i)).c_str(), block);
  527. if (NUdf::GetDataTypeInfo(types[i].first).Features & NUdf::EDataTypeFeatures::StringType) {
  528. ValueRelease(EValueRepresentation::String, nextOne, ctx, block);
  529. ValueRelease(EValueRepresentation::String, nextTwo, ctx, block);
  530. }
  531. const auto step = BasicBlock::Create(context, (TString("step") += ToString(i)).c_str(), ctx.Func);
  532. const auto test = GenEqualsFunction(types[i].first, types[i].second, nextOne, nextTwo, ctx, block);
  533. BranchInst::Create(step, stop, test, block);
  534. block = step;
  535. }
  536. CallBoxedValueVirtualMethod<NUdf::TBoxedValueAccessor::EMethod::GetElement>(elementOne, lv, ctx.Codegen, block, ConstantInt::get(indexType, last));
  537. CallBoxedValueVirtualMethod<NUdf::TBoxedValueAccessor::EMethod::GetElement>(elementTwo, rv, ctx.Codegen, block, ConstantInt::get(indexType, last));
  538. const auto backOne = new LoadInst(valueType, elementOne, "back_one", block);
  539. const auto backTwo = new LoadInst(valueType, elementTwo, "back_two", block);
  540. if (NUdf::GetDataTypeInfo(types.back().first).Features & NUdf::EDataTypeFeatures::StringType) {
  541. ValueRelease(EValueRepresentation::String, backOne, ctx, block);
  542. ValueRelease(EValueRepresentation::String, backTwo, ctx, block);
  543. }
  544. const auto result = GenEqualsFunction(types.back().first, types.back().second, backOne, backTwo, ctx, block);
  545. ReturnInst::Create(context, result, block);
  546. }
  547. block = stop;
  548. ReturnInst::Create(context, ConstantInt::getFalse(context), block);
  549. } else {
  550. const auto result = GenEqualsFunction(types.front().first, types.front().second, lv, rv, ctx, block);
  551. ReturnInst::Create(context, result, block);
  552. }
  553. return ctx.Func;
  554. }
  555. Function* GenerateHashFunction(NYql::NCodegen::ICodegen& codegen, const TString& name, bool isTuple, const TKeyTypes& types) {
  556. auto& module = codegen.GetModule();
  557. if (const auto f = module.getFunction(name.c_str()))
  558. return f;
  559. auto& context = codegen.GetContext();
  560. const auto valueType = Type::getInt128Ty(context);
  561. const auto returnType = Type::getInt64Ty(context);
  562. const auto funcType =
  563. FunctionType::get(returnType, {valueType}, false);
  564. TCodegenContext ctx(codegen);
  565. ctx.AlwaysInline = true;
  566. ctx.Func = cast<Function>(module.getOrInsertFunction(name.c_str(), funcType).getCallee());
  567. DISubprogramAnnotator annotator(ctx, ctx.Func);
  568. const auto main = BasicBlock::Create(context, "main", ctx.Func);
  569. auto block = main;
  570. const auto arg = LoadIfPointer(&*ctx.Func->arg_begin(), funcType->getParamType(0), block);
  571. if (isTuple) {
  572. if (types.empty()) {
  573. ReturnInst::Create(context, ConstantInt::get(returnType, 0), block);
  574. return ctx.Func;
  575. }
  576. const auto fast = BasicBlock::Create(context, "fast", ctx.Func);
  577. const auto slow = BasicBlock::Create(context, "slow", ctx.Func);
  578. const auto elementsType = ArrayType::get(valueType, types.size());
  579. const auto elementsPtrType = PointerType::getUnqual(elementsType);
  580. const auto elementsPtr = CallBoxedValueVirtualMethod<NUdf::TBoxedValueAccessor::EMethod::GetElements>(elementsPtrType, arg, ctx.Codegen, block);
  581. const auto null = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_EQ, elementsPtr, ConstantPointerNull::get(elementsPtrType), "null", block);
  582. BranchInst::Create(slow, fast, null, block);
  583. {
  584. block = fast;
  585. const auto elements = new LoadInst(elementsType, elementsPtr, "elements", block);
  586. auto result = static_cast<Value*>(ConstantInt::get(returnType, 0));
  587. for (auto i = 0U; i < types.size(); ++i) {
  588. const auto next = ExtractValueInst::Create(elements, i, (TString("next_") += ToString(i)).c_str(), block);
  589. const auto plus = GenHashFunction(types[i].first, types[i].second, next, ctx, block);
  590. result = GenCombineHashes(result, plus, block);
  591. }
  592. ReturnInst::Create(context, result, block);
  593. }
  594. {
  595. block = slow;
  596. const auto element = new AllocaInst(valueType, 0U, "element", block);
  597. auto result = static_cast<Value*>(ConstantInt::get(returnType, 0));
  598. for (auto i = 0U; i < types.size(); ++i) {
  599. CallBoxedValueVirtualMethod<NUdf::TBoxedValueAccessor::EMethod::GetElement>(element, arg, ctx.Codegen, block, ConstantInt::get(Type::getInt32Ty(context), i));
  600. const auto next = new LoadInst(valueType, element, (TString("next_") += ToString(i)).c_str(), block);
  601. if (NUdf::GetDataTypeInfo(types[i].first).Features & NUdf::EDataTypeFeatures::StringType) {
  602. ValueRelease(EValueRepresentation::String, next, ctx, block);
  603. }
  604. const auto plus = GenHashFunction(types[i].first, types[i].second, next, ctx, block);
  605. result = GenCombineHashes(result, plus, block);
  606. }
  607. ReturnInst::Create(context, result, block);
  608. }
  609. } else {
  610. const auto result = GenHashFunction(types.front().first, types.front().second, arg, ctx, block);
  611. ReturnInst::Create(context, result, block);
  612. }
  613. return ctx.Func;
  614. }
  615. Function* GenerateEqualsFunction(NYql::NCodegen::ICodegen& codegen, const TString& name, const TKeyTypes& types) {
  616. auto& module = codegen.GetModule();
  617. if (const auto f = module.getFunction(name.c_str()))
  618. return f;
  619. auto& context = codegen.GetContext();
  620. const auto valueType = Type::getInt128Ty(context);
  621. const auto elementsType = ArrayType::get(valueType, types.size());
  622. const auto ptrType = PointerType::getUnqual(elementsType);
  623. const auto returnType = Type::getInt1Ty(context);
  624. const auto funcType = FunctionType::get(returnType, {ptrType, ptrType}, false);
  625. TCodegenContext ctx(codegen);
  626. ctx.AlwaysInline = true;
  627. ctx.Func = cast<Function>(module.getOrInsertFunction(name.c_str(), funcType).getCallee());
  628. DISubprogramAnnotator annotator(ctx, ctx.Func);
  629. auto args = ctx.Func->arg_begin();
  630. const auto main = BasicBlock::Create(context, "main", ctx.Func);
  631. auto block = main;
  632. const auto lv = &*args;
  633. const auto rv = &*++args;
  634. if (types.empty()) {
  635. ReturnInst::Create(context, ConstantInt::getTrue(context), block);
  636. return ctx.Func;
  637. }
  638. const auto elementsOne = new LoadInst(elementsType, lv, "elements_one", block);
  639. const auto elementsTwo = new LoadInst(elementsType, rv, "elements_two", block);
  640. const auto stop = BasicBlock::Create(context, "stop", ctx.Func);
  641. ReturnInst::Create(context, ConstantInt::getFalse(context), stop);
  642. const auto last = types.size() - 1U;
  643. for (ui32 i = 0U; i < last; ++i) {
  644. const auto nextOne = ExtractValueInst::Create(elementsOne, i, (TString("next_one_") += ToString(i)).c_str(), block);
  645. const auto nextTwo = ExtractValueInst::Create(elementsTwo, i, (TString("next_two_") += ToString(i)).c_str(), block);
  646. const auto step = BasicBlock::Create(context, (TString("step_") += ToString(i)).c_str(), ctx.Func);
  647. const auto test = GenEqualsFunction(types[i].first, types[i].second, nextOne, nextTwo, ctx, block);
  648. BranchInst::Create(step, stop, test, block);
  649. block = step;
  650. }
  651. const auto backOne = ExtractValueInst::Create(elementsOne, last, "back_one", block);
  652. const auto backTwo = ExtractValueInst::Create(elementsTwo, last, "back_two", block);
  653. const auto result = GenEqualsFunction(types.back().first, types.back().second, backOne, backTwo, ctx, block);
  654. ReturnInst::Create(context, result, block);
  655. return ctx.Func;
  656. }
  657. Function* GenerateHashFunction(NYql::NCodegen::ICodegen& codegen, const TString& name, const TKeyTypes& types) {
  658. auto& module = codegen.GetModule();
  659. if (const auto f = module.getFunction(name.c_str()))
  660. return f;
  661. auto& context = codegen.GetContext();
  662. const auto valueType = Type::getInt128Ty(context);
  663. const auto elementsType = ArrayType::get(valueType, types.size());
  664. const auto ptrType = PointerType::getUnqual(elementsType);
  665. const auto returnType = Type::getInt64Ty(context);
  666. const auto funcType = FunctionType::get(returnType, {ptrType}, false);
  667. TCodegenContext ctx(codegen);
  668. ctx.AlwaysInline = true;
  669. ctx.Func = cast<Function>(module.getOrInsertFunction(name.c_str(), funcType).getCallee());
  670. DISubprogramAnnotator annotator(ctx, ctx.Func);
  671. const auto main = BasicBlock::Create(context, "main", ctx.Func);
  672. auto block = main;
  673. if (types.empty()) {
  674. ReturnInst::Create(context, ConstantInt::get(returnType, 0), block);
  675. return ctx.Func;
  676. }
  677. const auto arg = &*ctx.Func->arg_begin();
  678. const auto elements = new LoadInst(elementsType, arg, "elements", block);
  679. if (types.size() > 1U) {
  680. auto result = static_cast<Value*>(ConstantInt::get(returnType, 0));
  681. for (auto i = 0U; i < types.size(); ++i) {
  682. const auto item = ExtractValueInst::Create(elements, i, (TString("item_") += ToString(i)).c_str(), block);
  683. const auto plus = GenHashFunction(types[i].first, types[i].second, item, ctx, block);
  684. result = GenCombineHashes(result, plus, block);
  685. }
  686. ReturnInst::Create(context, result, block);
  687. } else {
  688. const auto value = ExtractValueInst::Create(elements, 0, "value", block);
  689. const auto result = GenHashFunction(types.front().first, types.front().second, value, ctx, block);
  690. ReturnInst::Create(context, result, block);
  691. }
  692. return ctx.Func;
  693. }
  694. Function* GenerateCompareFunction(NYql::NCodegen::ICodegen& codegen, const TString& name, const TKeyTypes& types) {
  695. auto& module = codegen.GetModule();
  696. if (const auto f = module.getFunction(name.c_str()))
  697. return f;
  698. auto& context = codegen.GetContext();
  699. const auto valueType = Type::getInt128Ty(context);
  700. const auto elementsType = ArrayType::get(valueType, types.size());
  701. const auto ptrType = PointerType::getUnqual(elementsType);
  702. const auto dirsType = ArrayType::get(Type::getInt1Ty(context), types.size());
  703. const auto ptrDirsType = PointerType::getUnqual(dirsType);
  704. const auto returnType = Type::getInt32Ty(context);
  705. const auto funcType = FunctionType::get(returnType, {ptrDirsType, ptrType, ptrType}, false);
  706. TCodegenContext ctx(codegen);
  707. ctx.AlwaysInline = true;
  708. ctx.Func = cast<Function>(module.getOrInsertFunction(name.c_str(), funcType).getCallee());
  709. DISubprogramAnnotator annotator(ctx, ctx.Func);
  710. auto args = ctx.Func->arg_begin();
  711. const auto main = BasicBlock::Create(context, "main", ctx.Func);
  712. auto block = main;
  713. const auto dp = &*args;
  714. const auto lv = &*++args;
  715. const auto rv = &*++args;
  716. if (types.empty()) {
  717. ReturnInst::Create(context, ConstantInt::get(returnType, 0), block);
  718. return ctx.Func;
  719. }
  720. const auto directions = new LoadInst(dirsType, dp, "directions", block);
  721. const auto elementsOne = new LoadInst(elementsType, lv, "elements_one", block);
  722. const auto elementsTwo = new LoadInst(elementsType, rv, "elements_two", block);
  723. const auto zero = ConstantInt::get(returnType, 0);
  724. for (auto i = 0U; i < types.size(); ++i) {
  725. const auto nextOne = ExtractValueInst::Create(elementsOne, i, (TString("next_one_") += ToString(i)).c_str(), block);
  726. const auto nextTwo = ExtractValueInst::Create(elementsTwo, i, (TString("next_two_") += ToString(i)).c_str(), block);
  727. const auto exit = BasicBlock::Create(context, (TString("exit_") += ToString(i)).c_str(), ctx.Func);
  728. const auto step = BasicBlock::Create(context, (TString("step_") += ToString(i)).c_str(), ctx.Func);
  729. const auto test = GenCompareFunction(types[i].first, types[i].second, nextOne, nextTwo, ctx, block);
  730. const auto skip = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_EQ, zero, test, (TString("skip_") += ToString(i)).c_str(), block);
  731. BranchInst::Create(step, exit, skip, block);
  732. block = exit;
  733. const auto dir = ExtractValueInst::Create(directions, i, (TString("dir_") += ToString(i)).c_str(), block);
  734. const auto neg = BinaryOperator::CreateNeg(test, (TString("neg_") += ToString(i)).c_str(), block);
  735. const auto out = SelectInst::Create(dir, test, neg, (TString("neg_") += ToString(i)).c_str(), block);
  736. ReturnInst::Create(context, out, block);
  737. block = step;
  738. }
  739. ReturnInst::Create(context, zero, block);
  740. return ctx.Func;
  741. }
  742. void GenInvalidate(const TCodegenContext& ctx, const std::vector<std::pair<ui32, EValueRepresentation>>& invalidationSet, BasicBlock*& block) {
  743. auto& context = ctx.Codegen.GetContext();
  744. const auto indexType = Type::getInt32Ty(context);
  745. const auto valueType = Type::getInt128Ty(context);
  746. const auto values = ctx.GetMutables();
  747. for (const auto& index : invalidationSet) {
  748. const auto invPtr = GetElementPtrInst::CreateInBounds(valueType, values, {ConstantInt::get(indexType, index.first)}, "inv_ptr", block);
  749. ValueUnRef(index.second, invPtr, ctx, block);
  750. new StoreInst(GetInvalid(context), invPtr, block);
  751. }
  752. }
  753. TUnboxedImmutableCodegeneratorNode::TUnboxedImmutableCodegeneratorNode(TMemoryUsageInfo* memInfo, NUdf::TUnboxedValue&& value)
  754. : TUnboxedImmutableComputationNode(memInfo, std::move(value))
  755. {}
  756. Value* TUnboxedImmutableCodegeneratorNode::CreateGetValue(const TCodegenContext& ctx, BasicBlock*&) const {
  757. return ConstantInt::get(Type::getInt128Ty(ctx.Codegen.GetContext()), APInt(128, 2, reinterpret_cast<const uint64_t*>(&UnboxedValue)));
  758. }
  759. TExternalCodegeneratorNode::TExternalCodegeneratorNode(TComputationMutables& mutables, EValueRepresentation kind)
  760. : TExternalComputationNode(mutables, kind)
  761. {}
  762. TExternalCodegeneratorRootNode::TExternalCodegeneratorRootNode(TComputationMutables& mutables, EValueRepresentation kind)
  763. : TExternalCodegeneratorNode(mutables, kind)
  764. {}
  765. NUdf::TUnboxedValue TExternalCodegeneratorRootNode::GetValue(TComputationContext& compCtx) const {
  766. if (compCtx.ExecuteLLVM && GetFunction)
  767. return GetFunction(&compCtx);
  768. return TExternalComputationNode::GetValue(compCtx);
  769. }
  770. void TExternalCodegeneratorRootNode::SetValue(TComputationContext& compCtx, NUdf::TUnboxedValue&& newValue) const {
  771. if (compCtx.ExecuteLLVM && SetFunction)
  772. return SetFunction(&compCtx, newValue.Release());
  773. TExternalComputationNode::SetValue(compCtx, std::move(newValue));
  774. }
  775. TString TExternalCodegeneratorRootNode::MakeName(const TString& method) const {
  776. TStringStream out;
  777. out << DebugString() << "::" << method << "_(" << static_cast<const void*>(this) << ").";
  778. return out.Str();
  779. }
  780. void TExternalCodegeneratorRootNode::FinalizeFunctions(NYql::NCodegen::ICodegen& codegen) {
  781. if (GetValueFunc)
  782. GetFunction = reinterpret_cast<TGetPtr>(codegen.GetPointerToFunction(GetValueFunc));
  783. if (SetValueFunc)
  784. SetFunction = reinterpret_cast<TSetPtr>(codegen.GetPointerToFunction(SetValueFunc));
  785. }
  786. void TExternalCodegeneratorRootNode::GenerateFunctions(NYql::NCodegen::ICodegen& codegen) {
  787. GetValueFunc = GenerateGetValue(codegen);
  788. SetValueFunc = GenerateSetValue(codegen);
  789. codegen.ExportSymbol(GetValueFunc);
  790. codegen.ExportSymbol(SetValueFunc);
  791. }
  792. Function* TExternalCodegeneratorRootNode::GenerateGetValue(NYql::NCodegen::ICodegen& codegen) {
  793. auto& module = codegen.GetModule();
  794. auto& context = codegen.GetContext();
  795. const auto& name = MakeName("Get");
  796. if (const auto f = module.getFunction(name.c_str()))
  797. return f;
  798. const auto valueType = Type::getInt128Ty(context);
  799. const auto contextType = GetCompContextType(context);
  800. const auto funcType =
  801. FunctionType::get(valueType, {PointerType::getUnqual(contextType)}, false);
  802. TCodegenContext ctx(codegen);
  803. ctx.Func = cast<Function>(module.getOrInsertFunction(name.c_str(), funcType).getCallee());
  804. DISubprogramAnnotator annotator(ctx, ctx.Func);
  805. auto args = ctx.Func->arg_begin();
  806. auto main = BasicBlock::Create(context, "main", ctx.Func);
  807. ctx.Ctx = &*args;
  808. ctx.Ctx->addAttr(Attribute::NonNull);
  809. const auto get = CreateGetValue(ctx, main);
  810. ReturnInst::Create(context, get, main);
  811. return ctx.Func;
  812. }
  813. Function* TExternalCodegeneratorRootNode::GenerateSetValue(NYql::NCodegen::ICodegen& codegen) {
  814. auto& module = codegen.GetModule();
  815. auto& context = codegen.GetContext();
  816. const auto& name = MakeName("Set");
  817. if (const auto f = module.getFunction(name.c_str()))
  818. return f;
  819. const auto intType = Type::getInt128Ty(context);
  820. const auto contextType = GetCompContextType(context);
  821. const auto valueType = (Type*)intType;
  822. const auto funcType = FunctionType::get(Type::getVoidTy(context), {PointerType::getUnqual(contextType), valueType}, false);
  823. TCodegenContext ctx(codegen);
  824. ctx.Func = cast<Function>(module.getOrInsertFunction(name.c_str(), funcType).getCallee());
  825. DISubprogramAnnotator annotator(ctx, ctx.Func);
  826. auto args = ctx.Func->arg_begin();
  827. auto main = BasicBlock::Create(context, "main", ctx.Func);
  828. ctx.Ctx = &*args;
  829. ctx.Ctx->addAttr(Attribute::NonNull);
  830. const auto valueArg = &*++args;
  831. CreateSetValue(ctx, main, valueArg);
  832. ReturnInst::Create(context, main);
  833. return ctx.Func;
  834. }
  835. Value* TExternalCodegeneratorNode::CreateGetValue(const TCodegenContext& ctx, BasicBlock*& block) const {
  836. if (ValueGetterBuilder) {
  837. llvm::Function* valueGetter = ValueGetterBuilder(ctx);
  838. return CallInst::Create(valueGetter, {ctx.Ctx}, "getter", block);
  839. }
  840. if (ValueBuilder) {
  841. auto [temporaryValue, itemType] = ValueBuilder(ctx);
  842. return LoadIfPointer(temporaryValue, itemType, block);
  843. }
  844. MKQL_ENSURE(!Getter, "Wrong LLVM function generation order.");
  845. auto& context = ctx.Codegen.GetContext();
  846. const auto indexType = Type::getInt32Ty(context);
  847. const auto valueType = Type::getInt128Ty(context);
  848. const auto valuePtr = GetElementPtrInst::CreateInBounds(valueType, ctx.GetMutables(), {ConstantInt::get(indexType, ValueIndex)}, "value_ptr", block);
  849. const auto value = new LoadInst(valueType, valuePtr, "value", block);
  850. return value;
  851. }
  852. Value* TExternalCodegeneratorNode::CreateRefValue(const TCodegenContext& ctx, BasicBlock*& block) const {
  853. CreateInvalidate(ctx, block);
  854. auto& context = ctx.Codegen.GetContext();
  855. const auto indexType = Type::getInt32Ty(context);
  856. const auto valueType = Type::getInt128Ty(context);
  857. const auto values = ctx.GetMutables();
  858. const auto valuePtr = GetElementPtrInst::CreateInBounds(valueType, values, {ConstantInt::get(indexType, ValueIndex)}, "value_ptr", block);
  859. return valuePtr;
  860. }
  861. void TExternalCodegeneratorNode::CreateSetValue(const TCodegenContext& ctx, BasicBlock*& block, Value* value) const {
  862. auto& context = ctx.Codegen.GetContext();
  863. const auto indexType = Type::getInt32Ty(context);
  864. const auto valueType = Type::getInt128Ty(context);
  865. const auto values = ctx.GetMutables();
  866. const auto valuePtr = GetElementPtrInst::CreateInBounds(valueType, values, {ConstantInt::get(indexType, ValueIndex)}, "value_ptr", block);
  867. if (value->getType()->isPointerTy()) {
  868. ValueUnRef(RepresentationKind, valuePtr, ctx, block);
  869. const auto load = new LoadInst(valueType, value, "value", block);
  870. new StoreInst(load, valuePtr, block);
  871. new StoreInst(ConstantInt::get(load->getType(), 0), value, block);
  872. } else {
  873. if (EValueRepresentation::Embedded == RepresentationKind) {
  874. new StoreInst(value, valuePtr, block);
  875. } else {
  876. const auto load = new LoadInst(valueType, valuePtr, "value", block);
  877. const auto equal = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_EQ, value, load, "equal", block);
  878. const auto skip = BasicBlock::Create(context, "skip", ctx.Func);
  879. const auto refs = BasicBlock::Create(context, "refs", ctx.Func);
  880. BranchInst::Create(skip, refs, equal, block);
  881. block = refs;
  882. ValueUnRef(RepresentationKind, valuePtr, ctx, block);
  883. new StoreInst(value, valuePtr, block);
  884. ValueAddRef(RepresentationKind, valuePtr, ctx, block);
  885. BranchInst::Create(skip, block);
  886. block = skip;
  887. }
  888. }
  889. CreateInvalidate(ctx, block);
  890. }
  891. Value* TExternalCodegeneratorNode::CreateSwapValue(const TCodegenContext& ctx, BasicBlock*& block, Value* value) const {
  892. auto& context = ctx.Codegen.GetContext();
  893. const auto indexType = Type::getInt32Ty(context);
  894. const auto valueType = Type::getInt128Ty(context);
  895. const auto values = ctx.GetMutables();
  896. const auto valuePtr = GetElementPtrInst::CreateInBounds(valueType, values, {ConstantInt::get(indexType, ValueIndex)}, "value_ptr", block);
  897. const auto output = new LoadInst(valueType, valuePtr, "output", block);
  898. ValueRelease(RepresentationKind, output, ctx, block);
  899. if (value->getType()->isPointerTy()) {
  900. const auto load = new LoadInst(valueType, value, "load", block);
  901. new StoreInst(load, valuePtr, block);
  902. new StoreInst(ConstantInt::get(load->getType(), 0), value, block);
  903. } else {
  904. ValueAddRef(RepresentationKind, value, ctx, block);
  905. new StoreInst(value, valuePtr, block);
  906. }
  907. CreateInvalidate(ctx, block);
  908. return output;
  909. }
  910. void TExternalCodegeneratorNode::CreateInvalidate(const TCodegenContext& ctx, BasicBlock*& block) const {
  911. GenInvalidate(ctx, InvalidationSet, block);
  912. }
  913. void TExternalCodegeneratorNode::SetValueBuilder(TValueBuilder valueBuilder)
  914. {
  915. ValueBuilder = std::move(valueBuilder);
  916. }
  917. void TExternalCodegeneratorNode::SetValueGetterBuilder(TValueGetterBuilder valueGetterBuilder)
  918. {
  919. ValueGetterBuilder = std::move(valueGetterBuilder);
  920. }
  921. void TWideFlowProxyCodegeneratorNode::CreateInvalidate(const TCodegenContext& ctx, BasicBlock*& block) const {
  922. GenInvalidate(ctx, InvalidationSet, block);
  923. }
  924. void TWideFlowProxyCodegeneratorNode::SetGenerator(TGenerator&& generator) {
  925. Generator = std::move(generator);
  926. }
  927. ICodegeneratorInlineWideNode::TGenerateResult
  928. TWideFlowProxyCodegeneratorNode::GenGetValues(const TCodegenContext& ctx, BasicBlock*& block) const {
  929. return Generator(ctx, block);
  930. }
  931. Value* GetOptionalValue(LLVMContext& context, Value* value, BasicBlock* block) {
  932. const auto type = Type::getInt128Ty(context);
  933. const auto data = ConstantInt::get(type, 0xFFFFFFFFFFFFFFFFULL);
  934. const auto check = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_UGT, value, data, "check", block);
  935. const auto decr = BinaryOperator::CreateSub(value, ConstantInt::get(type, 1), "decr", block);
  936. const auto result = SelectInst::Create(check, value, decr, "result", block);
  937. return result;
  938. }
  939. Value* MakeOptional(LLVMContext& context, Value* value, BasicBlock* block) {
  940. const auto type = Type::getInt128Ty(context);
  941. const auto data = ConstantInt::get(type, 0xFFFFFFFFFFFFFFFFULL);
  942. const auto check = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_UGT, value, data, "check", block);
  943. const auto incr = BinaryOperator::CreateAdd(value, ConstantInt::get(type, 1), "incr", block);
  944. const auto result = SelectInst::Create(check, value, incr, "result", block);
  945. return result;
  946. }
  947. ConstantInt* GetTrue(LLVMContext &context) {
  948. const uint64_t init[] = {1ULL, 0x100000000000000ULL};
  949. return ConstantInt::get(context, APInt(128, 2, init));
  950. }
  951. ConstantInt* GetFalse(LLVMContext &context) {
  952. const uint64_t init[] = {0ULL, 0x100000000000000ULL};
  953. return ConstantInt::get(context, APInt(128, 2, init));
  954. }
  955. ConstantInt* GetDecimalPlusInf(LLVMContext &context) {
  956. const auto& pair = NYql::NDecimal::MakePair(+NYql::NDecimal::Inf());
  957. const uint64_t init[] = {pair.first, pair.second};
  958. return ConstantInt::get(context, APInt(128, 2, init));
  959. }
  960. ConstantInt* GetDecimalMinusInf(LLVMContext &context) {
  961. const auto& pair = NYql::NDecimal::MakePair(-NYql::NDecimal::Inf());
  962. const uint64_t init[] = {pair.first, pair.second};
  963. return ConstantInt::get(context, APInt(128, 2, init));
  964. }
  965. ConstantInt* GetDecimalNan(LLVMContext &context) {
  966. const auto& pair = NYql::NDecimal::MakePair(NYql::NDecimal::Nan());
  967. const uint64_t init[] = {pair.first, pair.second};
  968. return ConstantInt::get(context, APInt(128, 2, init));
  969. }
  970. ConstantInt* GetDecimalMinusNan(LLVMContext &context) {
  971. const auto& pair = NYql::NDecimal::MakePair(-NYql::NDecimal::Nan());
  972. const uint64_t init[] = {pair.first, pair.second};
  973. return ConstantInt::get(context, APInt(128, 2, init));
  974. }
  975. static constexpr ui64 InvalidData = std::numeric_limits<ui64>::max();
  976. static constexpr ui64 FinishData = InvalidData - 1ULL;
  977. static constexpr ui64 YieldData = InvalidData;
  978. ConstantInt* GetEmpty(LLVMContext &context) {
  979. return ConstantInt::get(Type::getInt128Ty(context), 0ULL);
  980. }
  981. ConstantInt* GetInvalid(LLVMContext &context) {
  982. return ConstantInt::get(Type::getInt128Ty(context), InvalidData);
  983. }
  984. ConstantInt* GetFinish(LLVMContext &context) {
  985. return ConstantInt::get(Type::getInt128Ty(context), FinishData);
  986. }
  987. ConstantInt* GetYield(LLVMContext &context) {
  988. return ConstantInt::get(Type::getInt128Ty(context), YieldData);
  989. }
  990. ConstantInt* GetConstant(ui64 value, LLVMContext &context) {
  991. const uint64_t init[] = {value, 0x100000000000000ULL};
  992. return ConstantInt::get(context, APInt(128, 2, init));
  993. }
  994. Value* IsExists(Value* value, BasicBlock* block, LLVMContext &context) {
  995. auto itemType = Type::getInt128Ty(context);
  996. const auto v = LoadIfPointer(value, itemType, block);
  997. return CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_NE, v, ConstantInt::get(v->getType(), 0ULL), "exists", block);
  998. }
  999. Value* IsEmpty(Value* value, BasicBlock* block, LLVMContext &context) {
  1000. auto itemType = Type::getInt128Ty(context);
  1001. const auto v = LoadIfPointer(value, itemType, block);
  1002. return CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_EQ, v, ConstantInt::get(v->getType(), 0ULL), "empty", block);
  1003. }
  1004. Value* IsInvalid(Value* value, BasicBlock* block, LLVMContext &context) {
  1005. auto itemType = Type::getInt128Ty(context);
  1006. const auto v = LoadIfPointer(value, itemType, block);
  1007. return CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_EQ, v, ConstantInt::get(v->getType(), InvalidData), "invalid", block);
  1008. }
  1009. Value* IsValid(Value* value, BasicBlock* block, LLVMContext &context) {
  1010. auto itemType = Type::getInt128Ty(context);
  1011. const auto v = LoadIfPointer(value, itemType, block);
  1012. return CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_NE, v, ConstantInt::get(v->getType(), InvalidData), "valid", block);
  1013. }
  1014. Value* IsFinish(Value* value, BasicBlock* block, LLVMContext &context) {
  1015. auto itemType = Type::getInt128Ty(context);
  1016. const auto v = LoadIfPointer(value, itemType, block);
  1017. return CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_EQ, v, ConstantInt::get(v->getType(), FinishData), "finish", block);
  1018. }
  1019. Value* IsYield(Value* value, BasicBlock* block, LLVMContext &context) {
  1020. auto itemType = Type::getInt128Ty(context);
  1021. const auto v = LoadIfPointer(value, itemType, block);
  1022. return CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_EQ, v, ConstantInt::get(v->getType(), YieldData), "yield", block);
  1023. }
  1024. Value* IsSpecial(Value* value, BasicBlock* block, LLVMContext &context) {
  1025. auto itemType = Type::getInt128Ty(context);
  1026. const auto v = LoadIfPointer(value, itemType, block);
  1027. return BinaryOperator::CreateOr(IsFinish(v, block, context), IsYield(v, block, context), "special", block);
  1028. }
  1029. Value* HasValue(Value* value, BasicBlock* block, LLVMContext &context) {
  1030. auto itemType = Type::getInt128Ty(context);
  1031. const auto v = LoadIfPointer(value, itemType, block);
  1032. return CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_UGT, v, ConstantInt::get(v->getType(), InvalidData), "has", block);
  1033. }
  1034. Value* MakeBoolean(Value* boolean , LLVMContext &context, BasicBlock* block) {
  1035. return SelectInst::Create(boolean, GetTrue(context), GetFalse(context), "result", block);
  1036. }
  1037. Value* SetterForInt128(Value* value, BasicBlock* block) {
  1038. const uint64_t mask[] = {0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFULL};
  1039. const auto drop = ConstantInt::get(value->getType(), APInt(128, 2, mask));
  1040. const auto data = BinaryOperator::CreateAnd(value, drop, "and", block);
  1041. const uint64_t init[] = {0ULL, 0x100000000000000ULL}; // Embedded
  1042. const auto meta = ConstantInt::get(value->getType(), APInt(128, 2, init));
  1043. const auto full = BinaryOperator::CreateOr(data, meta, "or", block);
  1044. return full;
  1045. }
  1046. Value* GetterForInt128(Value* value, BasicBlock* block) {
  1047. const uint64_t init[] = {0ULL, 0x80000000000000ULL};
  1048. const auto test = ConstantInt::get(value->getType(), APInt(128, 2, init));
  1049. const auto sign = BinaryOperator::CreateAnd(value, test, "and", block);
  1050. const uint64_t fill[] = {0ULL, 0xFF00000000000000ULL};
  1051. const auto sext = ConstantInt::get(value->getType(), APInt(128, 2, fill));
  1052. const auto minus = BinaryOperator::CreateOr(value, sext, "or", block);
  1053. const uint64_t mask[] = {0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFULL};
  1054. const auto trun = ConstantInt::get(value->getType(), APInt(128, 2, mask));
  1055. const auto plus = BinaryOperator::CreateAnd(value, trun, "and", block);
  1056. const auto check = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_EQ, sign, ConstantInt::get(sign->getType(), 0), "check", block);
  1057. const auto result = SelectInst::Create(check, plus, minus, "result", block);
  1058. return result;
  1059. }
  1060. Value* GetterForTimezone(LLVMContext& context, Value* value, BasicBlock* block) {
  1061. const auto lshr = BinaryOperator::CreateLShr(value, ConstantInt::get(value->getType(), 64ULL), "lshr", block);
  1062. const auto trunc = CastInst::Create(Instruction::Trunc, lshr, Type::getInt16Ty(context), "trunc", block);
  1063. return trunc;
  1064. }
  1065. template<> Type* GetTypeFor<bool>(LLVMContext &context) { return Type::getInt1Ty(context); }
  1066. template<> Type* GetTypeFor<ui8>(LLVMContext &context) { return Type::getInt8Ty(context); }
  1067. template<> Type* GetTypeFor<i8>(LLVMContext &context) { return Type::getInt8Ty(context); }
  1068. template<> Type* GetTypeFor<i16>(LLVMContext &context) { return Type::getInt16Ty(context); }
  1069. template<> Type* GetTypeFor<ui16>(LLVMContext &context) { return Type::getInt16Ty(context); }
  1070. template<> Type* GetTypeFor<i32>(LLVMContext &context) { return Type::getInt32Ty(context); }
  1071. template<> Type* GetTypeFor<ui32>(LLVMContext &context) { return Type::getInt32Ty(context); }
  1072. template<> Type* GetTypeFor<i64>(LLVMContext &context) { return Type::getInt64Ty(context); }
  1073. template<> Type* GetTypeFor<ui64>(LLVMContext &context) { return Type::getInt64Ty(context); }
  1074. template<> Type* GetTypeFor<float>(LLVMContext &context) { return Type::getFloatTy(context); }
  1075. template<> Type* GetTypeFor<double>(LLVMContext &context) { return Type::getDoubleTy(context); }
  1076. void AddRefBoxed(Value* value, const TCodegenContext& ctx, BasicBlock*& block) {
  1077. auto& context = ctx.Codegen.GetContext();
  1078. const auto load = value->getType()->isPointerTy() ? new LoadInst(Type::getInt128Ty(context), value, "load", block) : value;
  1079. const auto half = CastInst::Create(Instruction::Trunc, load, Type::getInt64Ty(context), "half", block);
  1080. const auto counterType = Type::getInt32Ty(context);
  1081. const auto type = StructType::get(context, {PointerType::getUnqual(StructType::get(context)), counterType, Type::getInt16Ty(context)});
  1082. const auto boxptr = CastInst::Create(Instruction::IntToPtr, half, PointerType::getUnqual(type), "boxptr", block);
  1083. const auto cntptr = GetElementPtrInst::CreateInBounds(type, boxptr, {ConstantInt::get(Type::getInt32Ty(context), 0), ConstantInt::get(Type::getInt32Ty(context), 1)}, "cntptr", block);
  1084. const auto refs = new LoadInst(counterType, cntptr, "refs", block);
  1085. #if UDF_ABI_COMPATIBILITY_VERSION_CURRENT >= UDF_ABI_COMPATIBILITY_VERSION(2, 4)
  1086. if constexpr (EnableStaticRefcount) {
  1087. const auto work = BasicBlock::Create(context, "work", ctx.Func);
  1088. const auto skip = BasicBlock::Create(context, "skip", ctx.Func);
  1089. const auto magic = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_SLT, refs, ConstantInt::get(refs->getType(), 0), "magic", block);
  1090. BranchInst::Create(skip, work, magic, block);
  1091. block = work;
  1092. const auto incr = BinaryOperator::CreateAdd(refs, ConstantInt::get(refs->getType(), 1), "incr", block);
  1093. new StoreInst(incr, cntptr, block);
  1094. BranchInst::Create(skip, block);
  1095. block = skip;
  1096. } else {
  1097. const auto incr = BinaryOperator::CreateAdd(refs, ConstantInt::get(refs->getType(), 1), "incr", block);
  1098. new StoreInst(incr, cntptr, block);
  1099. }
  1100. #else
  1101. const auto incr = BinaryOperator::CreateAdd(refs, ConstantInt::get(refs->getType(), 1), "incr", block);
  1102. new StoreInst(incr, cntptr, block);
  1103. #endif
  1104. }
  1105. void UnRefBoxed(Value* value, const TCodegenContext& ctx, BasicBlock*& block) {
  1106. auto& context = ctx.Codegen.GetContext();
  1107. const auto load = value->getType()->isPointerTy() ? new LoadInst(Type::getInt128Ty(context), value, "load", block) : value;
  1108. const auto half = CastInst::Create(Instruction::Trunc, load, Type::getInt64Ty(context), "half", block);
  1109. const auto counterType = Type::getInt32Ty(context);
  1110. const auto type = StructType::get(context, {PointerType::getUnqual(StructType::get(context)), counterType, Type::getInt16Ty(context)});
  1111. const auto boxptr = CastInst::Create(Instruction::IntToPtr, half, PointerType::getUnqual(type), "boxptr", block);
  1112. const auto cntptr = GetElementPtrInst::CreateInBounds(type, boxptr, {ConstantInt::get(Type::getInt32Ty(context), 0), ConstantInt::get(Type::getInt32Ty(context), 1)}, "cntptr", block);
  1113. const auto refs = new LoadInst(counterType, cntptr, "refs", block);
  1114. const auto live = BasicBlock::Create(context, "live", ctx.Func);
  1115. #if UDF_ABI_COMPATIBILITY_VERSION_CURRENT >= UDF_ABI_COMPATIBILITY_VERSION(2, 4)
  1116. if constexpr (EnableStaticRefcount) {
  1117. const auto magic = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_SLT, refs, ConstantInt::get(refs->getType(), 0), "magic", block);
  1118. const auto work = BasicBlock::Create(context, "work", ctx.Func);
  1119. BranchInst::Create(live, work, magic, block);
  1120. block = work;
  1121. }
  1122. #endif
  1123. const auto decr = BinaryOperator::CreateSub(refs, ConstantInt::get(refs->getType(), 1), "decr", block);
  1124. new StoreInst(decr, cntptr, block);
  1125. const auto test = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_UGT, decr, ConstantInt::get(decr->getType(), 0), "many", block);
  1126. const auto kill = BasicBlock::Create(context, "kill", ctx.Func);
  1127. BranchInst::Create(live, kill, test, block);
  1128. block = kill;
  1129. const auto fnType = FunctionType::get(Type::getVoidTy(context), {boxptr->getType()}, false);
  1130. const auto name = "DeleteBoxed";
  1131. ctx.Codegen.AddGlobalMapping(name, reinterpret_cast<const void*>(&DeleteBoxed));
  1132. const auto func = ctx.Codegen.GetModule().getOrInsertFunction(name, fnType).getCallee();
  1133. CallInst::Create(fnType, func, {boxptr}, "", block);
  1134. BranchInst::Create(live, block);
  1135. block = live;
  1136. }
  1137. void CleanupBoxed(Value* value, const TCodegenContext& ctx, BasicBlock*& block) {
  1138. auto& context = ctx.Codegen.GetContext();
  1139. const auto load = value->getType()->isPointerTy() ? new LoadInst(Type::getInt128Ty(context), value, "load", block) : value;
  1140. const auto half = CastInst::Create(Instruction::Trunc, load, Type::getInt64Ty(context), "half", block);
  1141. const auto counterType = Type::getInt32Ty(context);
  1142. const auto type = StructType::get(context, {PointerType::getUnqual(StructType::get(context)), counterType, Type::getInt16Ty(context)});
  1143. const auto boxptr = CastInst::Create(Instruction::IntToPtr, half, PointerType::getUnqual(type), "boxptr", block);
  1144. const auto cntptr = GetElementPtrInst::CreateInBounds(type, boxptr, {ConstantInt::get(Type::getInt32Ty(context), 0), ConstantInt::get(Type::getInt32Ty(context), 1)}, "cntptr", block);
  1145. const auto refs = new LoadInst(counterType, cntptr, "refs", block);
  1146. const auto test = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_NE, refs, ConstantInt::get(refs->getType(), 0), "many", block);
  1147. const auto live = BasicBlock::Create(context, "live", ctx.Func);
  1148. const auto kill = BasicBlock::Create(context, "kill", ctx.Func);
  1149. BranchInst::Create(live, kill, test, block);
  1150. block = kill;
  1151. const auto fnType = FunctionType::get(Type::getVoidTy(context), {boxptr->getType()}, false);
  1152. const auto name = "DeleteBoxed";
  1153. ctx.Codegen.AddGlobalMapping(name, reinterpret_cast<const void*>(&DeleteBoxed));
  1154. const auto func = ctx.Codegen.GetModule().getOrInsertFunction(name, fnType).getCallee();
  1155. CallInst::Create(fnType, func, {boxptr}, "", block);
  1156. BranchInst::Create(live, block);
  1157. block = live;
  1158. }
  1159. template<bool IncOrDec>
  1160. void ChangeRefUnboxed(Value* value, const TCodegenContext& ctx, BasicBlock*& block) {
  1161. auto& context = ctx.Codegen.GetContext();
  1162. const auto type8 = Type::getInt8Ty(context);
  1163. const auto type32 = Type::getInt32Ty(context);
  1164. const auto mark = GetMarkFromUnboxed(value, ctx, block);
  1165. const auto boxb = BasicBlock::Create(context, "boxb", ctx.Func);
  1166. const auto strb = BasicBlock::Create(context, "strb", ctx.Func);
  1167. const auto doit = BasicBlock::Create(context, "doit", ctx.Func);
  1168. const auto done = BasicBlock::Create(context, "done", ctx.Func);
  1169. const auto refsPtrType = PointerType::getUnqual(type32);
  1170. const auto refsptr = PHINode::Create(refsPtrType, 2U, "refsptr", doit);
  1171. const auto choise = SwitchInst::Create(mark, done, 2U, block);
  1172. choise->addCase(ConstantInt::get(type8, 2), strb);
  1173. choise->addCase(ConstantInt::get(type8, 3), boxb);
  1174. {
  1175. block = strb;
  1176. const auto [strptr, strtype] = GetPointerFromUnboxed<false>(value, ctx, block);
  1177. const auto elemptr = GetElementPtrInst::CreateInBounds(strtype, strptr, {ConstantInt::get(type32, 0), ConstantInt::get(type32, 1)}, "elemptr", block);
  1178. refsptr->addIncoming(elemptr, block);
  1179. BranchInst::Create(doit, block);
  1180. }
  1181. {
  1182. block = boxb;
  1183. const auto [boxptr, boxtype] = GetPointerFromUnboxed<true>(value, ctx, block);
  1184. const auto elemptr = GetElementPtrInst::CreateInBounds(boxtype, boxptr, {ConstantInt::get(type32, 0), ConstantInt::get(type32, 1)}, "elemptr", block);
  1185. refsptr->addIncoming(elemptr, block);
  1186. BranchInst::Create(doit, block);
  1187. }
  1188. block = doit;
  1189. const auto refs = new LoadInst(type32, refsptr, "refs", block);
  1190. #if UDF_ABI_COMPATIBILITY_VERSION_CURRENT >= UDF_ABI_COMPATIBILITY_VERSION(2, 4)
  1191. if constexpr (EnableStaticRefcount) {
  1192. const auto magic = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_SLT, refs, ConstantInt::get(refs->getType(), 0), "magic", block);
  1193. const auto work = BasicBlock::Create(context, "work", ctx.Func);
  1194. BranchInst::Create(done, work, magic, block);
  1195. block = work;
  1196. }
  1197. #endif
  1198. const auto next = IncOrDec ?
  1199. BinaryOperator::CreateAdd(refs, ConstantInt::get(refs->getType(), 1), "incr", block):
  1200. BinaryOperator::CreateSub(refs, ConstantInt::get(refs->getType(), 1), "decr", block);
  1201. new StoreInst(next, refsptr, block);
  1202. BranchInst::Create(done, block);
  1203. block = done;
  1204. }
  1205. template<bool Decrement>
  1206. void CheckRefUnboxed(Value* value, const TCodegenContext& ctx, BasicBlock*& block) {
  1207. auto& context = ctx.Codegen.GetContext();
  1208. const auto type8 = Type::getInt8Ty(context);
  1209. const auto type32 = Type::getInt32Ty(context);
  1210. const auto mark = GetMarkFromUnboxed(value, ctx, block);
  1211. const auto boxb = BasicBlock::Create(context, "boxb", ctx.Func);
  1212. const auto strb = BasicBlock::Create(context, "strb", ctx.Func);
  1213. const auto nope = BasicBlock::Create(context, "nope", ctx.Func);
  1214. const auto choise = SwitchInst::Create(mark, nope, 2U, block);
  1215. choise->addCase(ConstantInt::get(type8, 2), strb);
  1216. choise->addCase(ConstantInt::get(type8, 3), boxb);
  1217. {
  1218. block = strb;
  1219. const auto [strptr, strtype] = GetPointerFromUnboxed<false>(value, ctx, block);
  1220. const auto refptr = GetElementPtrInst::CreateInBounds(strtype, strptr, {ConstantInt::get(type32, 0), ConstantInt::get(type32, 1)}, "refptr", block);
  1221. const auto refs = new LoadInst(type32, refptr, "refs", block);
  1222. #if UDF_ABI_COMPATIBILITY_VERSION_CURRENT >= UDF_ABI_COMPATIBILITY_VERSION(2, 4)
  1223. if constexpr (EnableStaticRefcount) {
  1224. const auto magic = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_SLT, refs, ConstantInt::get(refs->getType(), 0), "magic", block);
  1225. const auto work = BasicBlock::Create(context, "work", ctx.Func);
  1226. BranchInst::Create(nope, work, magic, block);
  1227. block = work;
  1228. }
  1229. #endif
  1230. Value* test = refs;
  1231. if constexpr (Decrement) {
  1232. const auto decr = BinaryOperator::CreateSub(refs, ConstantInt::get(refs->getType(), 1), "decr", block);
  1233. new StoreInst(decr, refptr, block);
  1234. test = decr;
  1235. }
  1236. const auto good = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_UGT, test, ConstantInt::get(test->getType(), 0), "test", block);
  1237. const auto free = BasicBlock::Create(context, "free", ctx.Func);
  1238. BranchInst::Create(nope, free, good, block);
  1239. block = free;
  1240. const auto fnType = FunctionType::get(Type::getVoidTy(context), {strptr->getType()}, false);
  1241. const auto name = "DeleteString";
  1242. ctx.Codegen.AddGlobalMapping(name, reinterpret_cast<const void*>(&DeleteString));
  1243. const auto func = ctx.Codegen.GetModule().getOrInsertFunction(name, fnType).getCallee();
  1244. CallInst::Create(fnType, func, {strptr}, "", block);
  1245. BranchInst::Create(nope, block);
  1246. }
  1247. {
  1248. block = boxb;
  1249. const auto [boxptr, boxtype] = GetPointerFromUnboxed<true>(value, ctx, block);;
  1250. const auto refptr = GetElementPtrInst::CreateInBounds(boxtype, boxptr, {ConstantInt::get(type32, 0), ConstantInt::get(type32, 1)}, "cntptr", block);
  1251. const auto refs = new LoadInst(type32, refptr, "refs", block);
  1252. #if UDF_ABI_COMPATIBILITY_VERSION_CURRENT >= UDF_ABI_COMPATIBILITY_VERSION(2, 4)
  1253. if constexpr (EnableStaticRefcount) {
  1254. const auto magic = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_SLT, refs, ConstantInt::get(refs->getType(), 0), "magic", block);
  1255. const auto work = BasicBlock::Create(context, "work", ctx.Func);
  1256. BranchInst::Create(nope, work, magic, block);
  1257. block = work;
  1258. }
  1259. #endif
  1260. Value* test = refs;
  1261. if constexpr (Decrement) {
  1262. const auto decr = BinaryOperator::CreateSub(refs, ConstantInt::get(refs->getType(), 1), "decr", block);
  1263. new StoreInst(decr, refptr, block);
  1264. test = decr;
  1265. }
  1266. const auto good = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_UGT, test, ConstantInt::get(test->getType(), 0), "test", block);
  1267. const auto kill = BasicBlock::Create(context, "kill", ctx.Func);
  1268. BranchInst::Create(nope, kill, good, block);
  1269. block = kill;
  1270. const auto fnType = FunctionType::get(Type::getVoidTy(context), {boxptr->getType()}, false);
  1271. const auto name = "DeleteBoxed";
  1272. ctx.Codegen.AddGlobalMapping(name, reinterpret_cast<const void*>(&DeleteBoxed));
  1273. const auto func = ctx.Codegen.GetModule().getOrInsertFunction(name, fnType).getCallee();
  1274. CallInst::Create(fnType, func, {boxptr}, "", block);
  1275. BranchInst::Create(nope, block);
  1276. }
  1277. block = nope;
  1278. }
  1279. #ifdef MAKE_UNBOXED_VALUE_LLVM_REFCOUNTION_FUNCTIONS
  1280. Function* GenRefCountFunction(const char* label, void (*func)(Value*, const TCodegenContext&, BasicBlock*&), Type* type, NYql::NCodegen::ICodegen& codegen) {
  1281. auto& module = codegen.GetModule();
  1282. auto& context = codegen.GetContext();
  1283. const auto name = TString(label) += (type->isPointerTy() ? "Ptr" : "Val");
  1284. if (const auto f = module.getFunction(name.c_str()))
  1285. return f;
  1286. const auto funcType = FunctionType::get(Type::getVoidTy(context), {type}, false);
  1287. TCodegenContext ctx(codegen);
  1288. ctx.Func = cast<Function>(module.getOrInsertFunction(name.c_str(), funcType).getCallee()).getCallee();
  1289. auto main = BasicBlock::Create(context, "main", ctx.Func);
  1290. auto value = &*ctx.Func->arg_begin();
  1291. func(value, ctx, main);
  1292. ReturnInst::Create(context, main);
  1293. return ctx.Func;
  1294. }
  1295. void AddRefUnboxed(Value* value, const TCodegenContext& ctx, BasicBlock*& block) {
  1296. CallInst::Create(GenRefCountFunction(__func__, &ChangeRefUnboxed<true>, value->getType(), ctx.Codegen), {value}, "", block);
  1297. }
  1298. void ReleaseUnboxed(Value* value, const TCodegenContext& ctx, BasicBlock*& block) {
  1299. CallInst::Create(GenRefCountFunction(__func__, &ChangeRefUnboxed<false>, value->getType(), ctx.Codegen), {value}, "", block);
  1300. }
  1301. void UnRefUnboxed(Value* value, const TCodegenContext& ctx, BasicBlock*& block) {
  1302. CallInst::Create(GenRefCountFunction(__func__, &CheckRefUnboxed<true>, value->getType(), ctx.Codegen), {value}, "", block);
  1303. }
  1304. void CleanupUnboxed(Value* value, const TCodegenContext& ctx, BasicBlock*& block) {
  1305. CallInst::Create(GenRefCountFunction(__func__, &CheckRefUnboxed<false>, value->getType(), ctx.Codegen), {value}, "", block);
  1306. }
  1307. #else
  1308. void AddRefUnboxed(Value* value, const TCodegenContext& ctx, BasicBlock*& block) {
  1309. return ChangeRefUnboxed<true>(value, ctx, block);
  1310. }
  1311. void ReleaseUnboxed(Value* value, const TCodegenContext& ctx, BasicBlock*& block) {
  1312. return ChangeRefUnboxed<false>(value, ctx, block);
  1313. }
  1314. void UnRefUnboxed(Value* value, const TCodegenContext& ctx, BasicBlock*& block) {
  1315. return CheckRefUnboxed<true>(value, ctx, block);
  1316. }
  1317. void CleanupUnboxed(Value* value, const TCodegenContext& ctx, BasicBlock*& block) {
  1318. return CheckRefUnboxed<false>(value, ctx, block);
  1319. }
  1320. #endif
  1321. void SafeUnRefUnboxedOne(Value* pointer, const TCodegenContext& ctx, BasicBlock*& block) {
  1322. auto itemType = Type::getInt128Ty(ctx.Codegen.GetContext());
  1323. UnRefUnboxed(pointer, ctx, block);
  1324. new StoreInst(ConstantInt::get(itemType, 0), pointer, block);
  1325. }
  1326. void SafeUnRefUnboxedArray(Value* pointer, ArrayType* arrayType, const TCodegenContext& ctx, BasicBlock*& block) {
  1327. auto itemType = arrayType->getElementType();
  1328. const auto indexType = Type::getInt64Ty(ctx.Codegen.GetContext());
  1329. Value* zeros = UndefValue::get(itemType);
  1330. for (ui32 idx = 0U; idx < arrayType->getNumElements(); ++idx) {
  1331. const auto item = GetElementPtrInst::CreateInBounds(itemType, pointer, { ConstantInt::get(indexType, 0), ConstantInt::get(indexType, idx) }, (TString("item_") += ToString(idx)).c_str(), block);
  1332. UnRefUnboxed(item, ctx, block);
  1333. zeros = InsertValueInst::Create(zeros, ConstantInt::get(itemType->getArrayElementType(), 0), {idx}, (TString("zero_") += ToString(idx)).c_str(), block);
  1334. }
  1335. new StoreInst(zeros, pointer, block);
  1336. }
  1337. void ValueAddRef(EValueRepresentation kind, Value* pointer, const TCodegenContext& ctx, BasicBlock*& block) {
  1338. switch (kind) {
  1339. case EValueRepresentation::Embedded: return;
  1340. case EValueRepresentation::Boxed: // TODO
  1341. case EValueRepresentation::String: // TODO
  1342. case EValueRepresentation::Any: return AddRefUnboxed(pointer, ctx, block);
  1343. }
  1344. }
  1345. void ValueUnRef(EValueRepresentation kind, Value* pointer, const TCodegenContext& ctx, BasicBlock*& block) {
  1346. switch (kind) {
  1347. case EValueRepresentation::Embedded: return;
  1348. case EValueRepresentation::Boxed: // TODO
  1349. case EValueRepresentation::String: // TODO
  1350. case EValueRepresentation::Any: return UnRefUnboxed(pointer, ctx, block);
  1351. }
  1352. }
  1353. void ValueCleanup(EValueRepresentation kind, Value* pointer, const TCodegenContext& ctx, BasicBlock*& block) {
  1354. switch (kind) {
  1355. case EValueRepresentation::Embedded: return;
  1356. case EValueRepresentation::Boxed: // TODO
  1357. case EValueRepresentation::String: // TODO
  1358. case EValueRepresentation::Any: return CleanupUnboxed(pointer, ctx, block);
  1359. }
  1360. }
  1361. void ValueRelease(EValueRepresentation kind, Value* pointer, const TCodegenContext& ctx, BasicBlock*& block) {
  1362. switch (kind) {
  1363. case EValueRepresentation::Embedded: return;
  1364. case EValueRepresentation::Boxed: // TODO
  1365. case EValueRepresentation::String: // TODO
  1366. case EValueRepresentation::Any: return ReleaseUnboxed(pointer, ctx, block);
  1367. }
  1368. }
  1369. std::pair<Value*, Value*> GetVariantParts(Value* variant, const TCodegenContext& ctx, BasicBlock*& block) {
  1370. auto& context = ctx.Codegen.GetContext();
  1371. const auto type = Type::getInt32Ty(context);
  1372. const auto lshr = BinaryOperator::CreateLShr(variant, ConstantInt::get(variant->getType(), 122), "lshr", block);
  1373. const auto trunc = CastInst::Create(Instruction::Trunc, lshr, type, "trunc", block);
  1374. const auto check = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_NE, trunc, ConstantInt::get(type , 0), "check", block);
  1375. const auto boxed = BasicBlock::Create(context, "boxed", ctx.Func);
  1376. const auto embed = BasicBlock::Create(context, "embed", ctx.Func);
  1377. const auto done = BasicBlock::Create(context, "done", ctx.Func);
  1378. const auto index = PHINode::Create(type, 2U, "index", done);
  1379. const auto item = PHINode::Create(variant->getType(), 2U, "index", done);
  1380. BranchInst::Create(embed, boxed, check, block);
  1381. {
  1382. block = embed;
  1383. const uint64_t init[] = {0xFFFFFFFFFFFFFFFFULL, 0x3FFFFFFFFFFFFFFULL};
  1384. const auto mask = ConstantInt::get(variant->getType(), APInt(128, 2, init));
  1385. const auto clean = BinaryOperator::CreateAnd(variant, mask, "clean", block);
  1386. const auto dec = BinaryOperator::CreateSub(trunc, ConstantInt::get(type, 1), "dec", block);
  1387. index->addIncoming(dec, block);
  1388. item->addIncoming(clean, block);
  1389. BranchInst::Create(done, block);
  1390. }
  1391. {
  1392. block = boxed;
  1393. const auto place = new AllocaInst(item->getType(), 0U, "place", &ctx.Func->getEntryBlock().back());
  1394. const auto idx = CallBoxedValueVirtualMethod<NUdf::TBoxedValueAccessor::EMethod::GetVariantIndex>(type, variant, ctx.Codegen, block);
  1395. CallBoxedValueVirtualMethod<NUdf::TBoxedValueAccessor::EMethod::GetVariantItem>(place, variant, ctx.Codegen, block);
  1396. const auto clean = new LoadInst(item->getType(), place, "clean", block);
  1397. ValueRelease(EValueRepresentation::Any, clean, ctx, block);
  1398. index->addIncoming(idx, block);
  1399. item->addIncoming(clean, block);
  1400. BranchInst::Create(done, block);
  1401. }
  1402. block = done;
  1403. return std::make_pair(index, item);
  1404. }
  1405. Value* MakeVariant(Value* item, Value* variant, const TCodegenContext& ctx, BasicBlock*& block) {
  1406. auto& context = ctx.Codegen.GetContext();
  1407. const auto boxed = BasicBlock::Create(context, "boxed", ctx.Func);
  1408. const auto embed = BasicBlock::Create(context, "embed", ctx.Func);
  1409. const auto done = BasicBlock::Create(context, "done", ctx.Func);
  1410. const auto result = PHINode::Create(item->getType(), 1U, "index", done);
  1411. const auto offset = ConstantInt::get(item->getType(), 122);
  1412. const auto lshr = BinaryOperator::CreateLShr(item, offset, "lshr", block);
  1413. const auto checkItem = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_EQ, lshr, ConstantInt::get(lshr->getType(), 0), "check_item", block);
  1414. const auto checkIndex = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_ULT, variant, ConstantInt::get(variant->getType(), (1U << 6U) - 1U), "check_index", block);
  1415. const auto check = BinaryOperator::CreateAnd(checkItem, checkIndex, "and", block);
  1416. BranchInst::Create(embed, boxed, check, block);
  1417. {
  1418. block = embed;
  1419. const auto index = BinaryOperator::CreateAdd(variant, ConstantInt::get(variant->getType(), 1), "index", block);
  1420. const auto extend = CastInst::Create(Instruction::ZExt, index, item->getType(), "extend", block);
  1421. const auto shift = BinaryOperator::CreateShl(extend, offset, "shift", block);
  1422. const auto output = BinaryOperator::CreateOr(item, shift, "output", block);
  1423. result->addIncoming(output, block);
  1424. BranchInst::Create(done, block);
  1425. }
  1426. {
  1427. block = boxed;
  1428. const auto factory = ctx.GetFactory();
  1429. const auto func = ConstantInt::get(Type::getInt64Ty(context), GetMethodPtr(&THolderFactory::CreateBoxedVariantHolder));
  1430. const auto signature = FunctionType::get(item->getType(), {factory->getType(), item->getType(), variant->getType()}, false);
  1431. const auto creator = CastInst::Create(Instruction::IntToPtr, func, PointerType::getUnqual(signature), "creator", block);
  1432. const auto output = CallInst::Create(signature, creator, {factory, item, variant}, "output", block);
  1433. result->addIncoming(output, block);
  1434. BranchInst::Create(done, block);
  1435. }
  1436. block = done;
  1437. return result;
  1438. }
  1439. Value* GetNodeValue(IComputationNode* node, const TCodegenContext& ctx, BasicBlock*& block) {
  1440. if (const auto codegen = dynamic_cast<ICodegeneratorInlineNode*>(node))
  1441. return codegen->CreateGetValue(ctx, block);
  1442. auto& context = ctx.Codegen.GetContext();
  1443. const auto ptr = ConstantInt::get(Type::getInt64Ty(context), intptr_t(node));
  1444. const auto ptrType = PointerType::getUnqual(StructType::get(context));
  1445. const auto nodeThis = CastInst::Create(Instruction::IntToPtr, ptr, ptrType, "node_this", block);
  1446. const auto valueType = Type::getInt128Ty(context);
  1447. const auto retPtr = new AllocaInst(valueType, 0U, "return_ptr", &ctx.Func->getEntryBlock().back());
  1448. const auto funType =
  1449. FunctionType::get(Type::getVoidTy(context), {retPtr->getType(), nodeThis->getType(), ctx.Ctx->getType()}, false);
  1450. const auto ptrFunType = PointerType::getUnqual(funType);
  1451. const auto tableType = PointerType::getUnqual(ptrFunType);
  1452. const auto nodeVTable = CastInst::Create(Instruction::IntToPtr, ptr, PointerType::getUnqual(tableType), "node_vtable", block);
  1453. const auto table = new LoadInst(tableType, nodeVTable, "table", false, block);
  1454. const auto elem = GetElementPtrInst::CreateInBounds(ptrFunType, table, {ConstantInt::get(Type::getInt64Ty(context), GetMethodIndex(&IComputationNode::GetValue))}, "element", block);
  1455. const auto func = new LoadInst(ptrFunType, elem, "func", false, block);
  1456. CallInst::Create(funType, func, {retPtr, nodeThis, ctx.Ctx}, "", block);
  1457. ValueRelease(node->GetRepresentation(), retPtr, ctx, block);
  1458. const auto result = new LoadInst(valueType, retPtr, "return", false, block);
  1459. return result;
  1460. }
  1461. void GetNodeValue(Value* value, IComputationNode* node, const TCodegenContext& ctx, BasicBlock*& block) {
  1462. if (const auto codegen = dynamic_cast<ICodegeneratorInlineNode*>(node)) {
  1463. const auto v = codegen->CreateGetValue(ctx, block);
  1464. new StoreInst(v, value, block);
  1465. ValueAddRef(node->GetRepresentation(), value, ctx, block);
  1466. return;
  1467. }
  1468. auto& context = ctx.Codegen.GetContext();
  1469. const auto ptr = ConstantInt::get(Type::getInt64Ty(context), intptr_t(node));
  1470. const auto ptrType = PointerType::getUnqual(StructType::get(context));
  1471. const auto nodeThis = CastInst::Create(Instruction::IntToPtr, ptr, ptrType, "node_this", block);
  1472. const auto funType =
  1473. FunctionType::get(Type::getVoidTy(context), {value->getType(), nodeThis->getType(), ctx.Ctx->getType()}, false);
  1474. const auto ptrFunType = PointerType::getUnqual(funType);
  1475. const auto tableType = PointerType::getUnqual(ptrFunType);
  1476. const auto nodeVTable = CastInst::Create(Instruction::IntToPtr, ptr, PointerType::getUnqual(tableType), "node_vtable", block);
  1477. const auto table = new LoadInst(tableType, nodeVTable, "table", false, block);
  1478. const auto elem = GetElementPtrInst::CreateInBounds(ptrFunType, table, {ConstantInt::get(Type::getInt64Ty(context), GetMethodIndex(&IComputationNode::GetValue))}, "element", block);
  1479. const auto func = new LoadInst(ptrFunType, elem, "func", false, block);
  1480. CallInst::Create(funType, func, {value, nodeThis, ctx.Ctx}, "", block);
  1481. }
  1482. ICodegeneratorInlineWideNode::TGenerateResult GetNodeValues(IComputationWideFlowNode* node, const TCodegenContext& ctx, BasicBlock*& block) {
  1483. if (const auto codegen = dynamic_cast<ICodegeneratorInlineWideNode*>(node))
  1484. return codegen->GenGetValues(ctx, block);
  1485. throw TNoCodegen();
  1486. }
  1487. Value* GenNewArray(const TCodegenContext& ctx, Value* size, Value* items, BasicBlock* block) {
  1488. auto& context = ctx.Codegen.GetContext();
  1489. const auto fact = ctx.GetFactory();
  1490. const auto func = ConstantInt::get(Type::getInt64Ty(context), GetMethodPtr(&THolderFactory::CreateDirectArrayHolder));
  1491. const auto valueType = Type::getInt128Ty(context);
  1492. const auto funType = FunctionType::get(valueType, {fact->getType(), size->getType(), items->getType()}, false);
  1493. const auto funcPtr = CastInst::Create(Instruction::IntToPtr, func, PointerType::getUnqual(funType), "function", block);
  1494. return CallInst::Create(funType, funcPtr, {fact, size, items}, "array", block);
  1495. }
  1496. Value* GetMemoryUsed(ui64 limit, const TCodegenContext& ctx, BasicBlock* block) {
  1497. if (!limit) {
  1498. return nullptr;
  1499. }
  1500. auto& context = ctx.Codegen.GetContext();
  1501. const auto fact = ctx.GetFactory();
  1502. const auto func = ConstantInt::get(Type::getInt64Ty(context), GetMethodPtr(&THolderFactory::GetMemoryUsed));
  1503. const auto funType = FunctionType::get(Type::getInt64Ty(context), {fact->getType()}, false);
  1504. const auto funcPtr = CastInst::Create(Instruction::IntToPtr, func, PointerType::getUnqual(funType), "get_used", block);
  1505. return CallInst::Create(funType, funcPtr, {fact}, "mem_used", block);
  1506. }
  1507. template <bool TrackRss>
  1508. Value* CheckAdjustedMemLimit(ui64 limit, Value* init, const TCodegenContext& ctx, BasicBlock*& block) {
  1509. auto& context = ctx.Codegen.GetContext();
  1510. if (!limit || !init) {
  1511. return ConstantInt::getFalse(context);
  1512. }
  1513. const auto indexType = Type::getInt32Ty(context);
  1514. if constexpr (TrackRss) {
  1515. const auto rssPtr = GetElementPtrInst::CreateInBounds(GetCompContextType(context), ctx.Ctx, {ConstantInt::get(indexType, 0), ConstantInt::get(indexType, 5)}, "rss_ptr", block);
  1516. const auto rss = new LoadInst(Type::getInt32Ty(context), rssPtr, "rsscounter", block);
  1517. const auto inc = BinaryOperator::CreateAdd(rss, ConstantInt::get(rss->getType(), 1), "inc", block);
  1518. new StoreInst(inc, rssPtr, block);
  1519. const auto mod = BinaryOperator::CreateURem(rss, ConstantInt::get(rss->getType(), STEP_FOR_RSS_CHECK), "mod", block);
  1520. const auto now = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_EQ, mod, ConstantInt::get(mod->getType() , 0), "now", block);
  1521. const auto call = BasicBlock::Create(context, "call", ctx.Func);
  1522. const auto skip = BasicBlock::Create(context, "skip", ctx.Func);
  1523. BranchInst::Create(call, skip, now, block);
  1524. block = call;
  1525. const auto func = ConstantInt::get(Type::getInt64Ty(context), GetMethodPtr(&TComputationContext::UpdateUsageAdjustor));
  1526. const auto funType = FunctionType::get(Type::getVoidTy(context), {ctx.Ctx->getType(), Type::getInt64Ty(context)}, false);
  1527. const auto funcPtr = CastInst::Create(Instruction::IntToPtr, func, PointerType::getUnqual(funType), "update", block);
  1528. CallInst::Create(funType, funcPtr, {ctx.Ctx, ConstantInt::get(init->getType(), limit)}, "", block);
  1529. BranchInst::Create(skip, block);
  1530. block = skip;
  1531. }
  1532. const auto adjPtr = GetElementPtrInst::CreateInBounds(GetCompContextType(context), ctx.Ctx, {ConstantInt::get(indexType, 0), ConstantInt::get(indexType, 4)}, "adj_ptr", block);
  1533. const auto adjustor = new LoadInst(Type::getFloatTy(context), adjPtr, "adjustor", block);
  1534. const auto curr = GetMemoryUsed(limit, ctx, block);
  1535. const auto cast = CastInst::Create(Instruction::UIToFP, curr, adjustor->getType(), "cast", block);
  1536. const auto used = BinaryOperator::CreateFMul(cast, adjustor, "used", block);
  1537. const auto add = BinaryOperator::CreateAdd(init, ConstantInt::get(init->getType(), limit), "add", block);
  1538. const auto upper = CastInst::Create(Instruction::UIToFP, add, adjustor->getType(), "upper", block);
  1539. return CmpInst::Create(Instruction::FCmp, FCmpInst::FCMP_OGE, used, upper, "enough", block);
  1540. }
  1541. template Value* CheckAdjustedMemLimit<false>(ui64 limit, Value* init, const TCodegenContext& ctx, BasicBlock*& block);
  1542. template Value* CheckAdjustedMemLimit<true>(ui64 limit, Value* init, const TCodegenContext& ctx, BasicBlock*& block);
  1543. Value* CallBoxedValueVirtualMethodImpl(uintptr_t methodPtr, Type* returnType, Value* value, NYql::NCodegen::ICodegen& codegen, BasicBlock* block) {
  1544. auto& context = codegen.GetContext();
  1545. const auto data = CastInst::Create(Instruction::Trunc, value, Type::getInt64Ty(context), "data", block);
  1546. const auto ptrStructType = PointerType::getUnqual(StructType::get(context));
  1547. const auto boxed = CastInst::Create(Instruction::IntToPtr, data, ptrStructType, "boxed", block);
  1548. const auto funType = FunctionType::get(returnType, {boxed->getType()}, false);
  1549. const auto ptrFunType = PointerType::getUnqual(funType);
  1550. const auto tableType = PointerType::getUnqual(ptrFunType);
  1551. const auto vTable = CastInst::Create(Instruction::IntToPtr, data, PointerType::getUnqual(tableType), "vtable", block);
  1552. const auto table = new LoadInst(tableType, vTable, "table", false, block);
  1553. const auto elem = GetElementPtrInst::CreateInBounds(ptrFunType, table, {ConstantInt::get(Type::getInt64Ty(context), GetMethodPtrIndex(methodPtr))}, "element", block);
  1554. const auto func = new LoadInst(ptrFunType, elem, "func", false, block);
  1555. const auto call = CallInst::Create(funType, func, {boxed}, returnType->isVoidTy() ? "" : "return", block);
  1556. return call;
  1557. }
  1558. void CallBoxedValueVirtualMethodImpl(uintptr_t methodPtr, Value* output, Value* value, NYql::NCodegen::ICodegen& codegen, BasicBlock* block) {
  1559. auto& context = codegen.GetContext();
  1560. const auto data = CastInst::Create(Instruction::Trunc, value, Type::getInt64Ty(context), "data", block);
  1561. const auto ptrStructType = PointerType::getUnqual(StructType::get(context));
  1562. const auto boxed = CastInst::Create(Instruction::IntToPtr, data, ptrStructType, "boxed", block);
  1563. const auto funType =
  1564. FunctionType::get(Type::getVoidTy(context), {output->getType(), boxed->getType()}, false);
  1565. const auto ptrFunType = PointerType::getUnqual(funType);
  1566. const auto tableType = PointerType::getUnqual(ptrFunType);
  1567. const auto vTable = CastInst::Create(Instruction::IntToPtr, data, PointerType::getUnqual(tableType), "vtable", block);
  1568. const auto table = new LoadInst(tableType, vTable, "table", false, block);
  1569. const auto elem = GetElementPtrInst::CreateInBounds(ptrFunType, table, {ConstantInt::get(Type::getInt64Ty(context), GetMethodPtrIndex(methodPtr))}, "element", block);
  1570. const auto func = new LoadInst(ptrFunType, elem, "func", false, block);
  1571. CallInst::Create(funType, func, {output, boxed}, "", block);
  1572. }
  1573. void CallBoxedValueVirtualMethodImpl(uintptr_t methodPtr, Value* output, Value* value, NYql::NCodegen::ICodegen& codegen, BasicBlock* block, Value* argument) {
  1574. auto& context = codegen.GetContext();
  1575. const auto data = CastInst::Create(Instruction::Trunc, value, Type::getInt64Ty(context), "data", block);
  1576. const auto ptrStructType = PointerType::getUnqual(StructType::get(context));
  1577. const auto boxed = CastInst::Create(Instruction::IntToPtr, data, ptrStructType, "boxed", block);
  1578. const auto funType =
  1579. FunctionType::get(Type::getVoidTy(context), {output->getType(), boxed->getType(), argument->getType()}, false);
  1580. const auto ptrFunType = PointerType::getUnqual(funType);
  1581. const auto tableType = PointerType::getUnqual(ptrFunType);
  1582. const auto vTable = CastInst::Create(Instruction::IntToPtr, data, PointerType::getUnqual(tableType), "vtable", block);
  1583. const auto table = new LoadInst(tableType, vTable, "table", false, block);
  1584. const auto elem = GetElementPtrInst::CreateInBounds(ptrFunType, table, {ConstantInt::get(Type::getInt64Ty(context), GetMethodPtrIndex(methodPtr))}, "element", block);
  1585. const auto func = new LoadInst(ptrFunType, elem, "func", false, block);
  1586. CallInst::Create(funType, func, {output, boxed, argument}, "", block);
  1587. }
  1588. Value* CallBoxedValueVirtualMethodImpl(uintptr_t methodPtr, Type* returnType, Value* value, NYql::NCodegen::ICodegen& codegen, BasicBlock* block, Value* argument) {
  1589. auto& context = codegen.GetContext();
  1590. const auto data = CastInst::Create(Instruction::Trunc, value, Type::getInt64Ty(context), "data", block);
  1591. const auto ptrStructType = PointerType::getUnqual(StructType::get(context));
  1592. const auto boxed = CastInst::Create(Instruction::IntToPtr, data, ptrStructType, "boxed", block);
  1593. const auto funType = FunctionType::get(returnType, {boxed->getType(), argument->getType()}, false);
  1594. const auto ptrFunType = PointerType::getUnqual(funType);
  1595. const auto tableType = PointerType::getUnqual(ptrFunType);
  1596. const auto vTable = CastInst::Create(Instruction::IntToPtr, data, PointerType::getUnqual(tableType), "vtable", block);
  1597. const auto table = new LoadInst(tableType, vTable, "table", false, block);
  1598. const auto elem = GetElementPtrInst::CreateInBounds(ptrFunType, table, {ConstantInt::get(Type::getInt64Ty(context), GetMethodPtrIndex(methodPtr))}, "element", block);
  1599. const auto func = new LoadInst(ptrFunType, elem, "func", false, block);
  1600. const auto call = CallInst::Create(funType, func, {boxed, argument}, returnType->isVoidTy() ? "" : "return", block);
  1601. return call;
  1602. }
  1603. void CallBoxedValueVirtualMethodImpl(uintptr_t methodPtr, Value* output, Value* value, NYql::NCodegen::ICodegen& codegen, BasicBlock* block, Value* arg1, Value* arg2) {
  1604. auto& context = codegen.GetContext();
  1605. const auto data = CastInst::Create(Instruction::Trunc, value, Type::getInt64Ty(context), "data", block);
  1606. const auto ptrStructType = PointerType::getUnqual(StructType::get(context));
  1607. const auto boxed = CastInst::Create(Instruction::IntToPtr, data, ptrStructType, "boxed", block);
  1608. const auto funType =
  1609. FunctionType::get(Type::getVoidTy(context), {output->getType(), boxed->getType(), arg1->getType(), arg2->getType()}, false);
  1610. const auto ptrFunType = PointerType::getUnqual(funType);
  1611. const auto tableType = PointerType::getUnqual(ptrFunType);
  1612. const auto vTable = CastInst::Create(Instruction::IntToPtr, data, PointerType::getUnqual(tableType), "vtable", block);
  1613. const auto table = new LoadInst(tableType, vTable, "table", false, block);
  1614. const auto elem = GetElementPtrInst::CreateInBounds(ptrFunType, table, {ConstantInt::get(Type::getInt64Ty(context), GetMethodPtrIndex(methodPtr))}, "element", block);
  1615. const auto func = new LoadInst(ptrFunType, elem, "func", false, block);
  1616. CallInst::Create(funType, func, {output, boxed, arg1, arg2}, "", block);
  1617. }
  1618. Value* CallBoxedValueVirtualMethodImpl(uintptr_t methodPtr, Type* returnType, Value* value, NYql::NCodegen::ICodegen& codegen, BasicBlock* block, Value* arg1, Value* arg2) {
  1619. auto& context = codegen.GetContext();
  1620. const auto data = CastInst::Create(Instruction::Trunc, value, Type::getInt64Ty(context), "data", block);
  1621. const auto ptrStructType = PointerType::getUnqual(StructType::get(context));
  1622. const auto boxed = CastInst::Create(Instruction::IntToPtr, data, ptrStructType, "boxed", block);
  1623. const auto funType = FunctionType::get(returnType, {boxed->getType(), arg1->getType(), arg2->getType()}, false);
  1624. const auto ptrFunType = PointerType::getUnqual(funType);
  1625. const auto tableType = PointerType::getUnqual(ptrFunType);
  1626. const auto vTable = CastInst::Create(Instruction::IntToPtr, data, PointerType::getUnqual(tableType), "vtable", block);
  1627. const auto table = new LoadInst(tableType, vTable, "table", false, block);
  1628. const auto elem = GetElementPtrInst::CreateInBounds(ptrFunType, table, {ConstantInt::get(Type::getInt64Ty(context), GetMethodPtrIndex(methodPtr))}, "element", block);
  1629. const auto func = new LoadInst(ptrFunType, elem, "func", false, block);
  1630. const auto call = CallInst::Create(funType, func, {boxed, arg1, arg2}, returnType->isVoidTy() ? "" : "return", block);
  1631. return call;
  1632. }
  1633. Value* CallUnaryUnboxedValueFunctionImpl(uintptr_t methodPtr, Type* result, Value* arg, NYql::NCodegen::ICodegen& codegen, BasicBlock* block) {
  1634. auto& context = codegen.GetContext();
  1635. const auto doFunc = ConstantInt::get(Type::getInt64Ty(context), methodPtr);
  1636. const auto funType = FunctionType::get(result, {arg->getType()}, false);
  1637. const auto funcPtr = CastInst::Create(Instruction::IntToPtr, doFunc, PointerType::getUnqual(funType), "ptr", block);
  1638. const auto call = CallInst::Create(funType, funcPtr, {arg}, "call", block);
  1639. return call;
  1640. }
  1641. Value* CallBinaryUnboxedValueFunctionImpl(uintptr_t methodPtr, Type* result, Value* left, Value* right, NYql::NCodegen::ICodegen& codegen, BasicBlock* block) {
  1642. auto& context = codegen.GetContext();
  1643. const auto doFunc = ConstantInt::get(Type::getInt64Ty(context), methodPtr);
  1644. const auto funType = FunctionType::get(result, {left->getType(), right->getType()}, false);
  1645. const auto funcPtr = CastInst::Create(Instruction::IntToPtr, doFunc, PointerType::getUnqual(funType), "ptr", block);
  1646. const auto call = CallInst::Create(funType, funcPtr, {left, right}, "call", block);
  1647. return call;
  1648. }
  1649. Y_NO_INLINE Value* TDecoratorCodegeneratorNodeBase::CreateGetValueImpl(IComputationNode* node,
  1650. const TCodegenContext& ctx, BasicBlock*& block) const {
  1651. const auto arg = GetNodeValue(node, ctx, block);
  1652. const auto value = DoGenerateGetValue(ctx, arg, block);
  1653. if (value->getType()->isPointerTy()) {
  1654. const auto load = new LoadInst(Type::getInt128Ty(ctx.Codegen.GetContext()), value, "load", block);
  1655. ValueRelease(node->GetRepresentation(), load, ctx, block);
  1656. return load;
  1657. } else {
  1658. return value;
  1659. }
  1660. }
  1661. Y_NO_INLINE Value* TStatelessFlowCodegeneratorNodeBase::CreateGetValueImpl(const IComputationNode* node,
  1662. const TCodegenContext& ctx, BasicBlock*& block) const {
  1663. const auto value = DoGenerateGetValue(ctx, block);
  1664. if (value->getType()->isPointerTy()) {
  1665. const auto load = new LoadInst(Type::getInt128Ty(ctx.Codegen.GetContext()), value, "load", block);
  1666. ValueRelease(node->GetRepresentation(), load, ctx, block);
  1667. return load;
  1668. } else {
  1669. return value;
  1670. }
  1671. }
  1672. Y_NO_INLINE ICodegeneratorInlineWideNode::TGenerateResult TStatelessWideFlowCodegeneratorNodeBase::GenGetValuesImpl(
  1673. const TCodegenContext& ctx, BasicBlock*& block) const {
  1674. return DoGenGetValues(ctx, block);
  1675. }
  1676. Y_NO_INLINE Value* TFlowSourceCodegeneratorNodeBase::CreateGetValueImpl(
  1677. const IComputationNode* node, const TCodegenContext& ctx, BasicBlock*& block) const {
  1678. auto& context = ctx.Codegen.GetContext();
  1679. const auto valueType = Type::getInt128Ty(context);
  1680. const auto statePtr = GetElementPtrInst::CreateInBounds(valueType, ctx.GetMutables(), {ConstantInt::get(Type::getInt32Ty(context), node->GetIndex())}, "state_ptr", block);
  1681. const auto value = DoGenerateGetValue(ctx, statePtr, block);
  1682. if (value->getType()->isPointerTy()) {
  1683. const auto load = new LoadInst(valueType, value, "load", block);
  1684. ValueRelease(node->GetRepresentation(), load, ctx, block);
  1685. return load;
  1686. } else {
  1687. return value;
  1688. }
  1689. }
  1690. Y_NO_INLINE ICodegeneratorInlineWideNode::TGenerateResult TWideFlowSourceCodegeneratorNodeBase::GenGetValuesImpl(
  1691. const IComputationNode* node, const TCodegenContext& ctx, BasicBlock*& block) const {
  1692. auto& context = ctx.Codegen.GetContext();
  1693. const auto valueType = Type::getInt128Ty(context);
  1694. const auto statePtr = GetElementPtrInst::CreateInBounds(valueType, ctx.GetMutables(), {ConstantInt::get(Type::getInt32Ty(context), node->GetIndex())}, "state_ptr", block);
  1695. return DoGenGetValues(ctx, statePtr, block);
  1696. }
  1697. Y_NO_INLINE Value* TStatefulFlowCodegeneratorNodeBase::CreateGetValueImpl(
  1698. const IComputationNode* node, const TCodegenContext& ctx, BasicBlock*& block) const {
  1699. auto& context = ctx.Codegen.GetContext();
  1700. const auto valueType = Type::getInt128Ty(context);
  1701. const auto statePtr = GetElementPtrInst::CreateInBounds(valueType, ctx.GetMutables(), {ConstantInt::get(Type::getInt32Ty(context), node->GetIndex())}, "state_ptr", block);
  1702. const auto value = DoGenerateGetValue(ctx, statePtr, block);
  1703. if (value->getType()->isPointerTy()) {
  1704. const auto load = new LoadInst(valueType, value, "load", block);
  1705. ValueRelease(node->GetRepresentation(), load, ctx, block);
  1706. return load;
  1707. } else {
  1708. return value;
  1709. }
  1710. }
  1711. Y_NO_INLINE ICodegeneratorInlineWideNode::TGenerateResult TStatefulWideFlowCodegeneratorNodeBase::GenGetValuesImpl(
  1712. const IComputationNode* node, const TCodegenContext& ctx, BasicBlock*& block) const {
  1713. auto& context = ctx.Codegen.GetContext();
  1714. const auto valueType = Type::getInt128Ty(context);
  1715. const auto statePtr = GetElementPtrInst::CreateInBounds(valueType, ctx.GetMutables(), {ConstantInt::get(Type::getInt32Ty(context), node->GetIndex())}, "state_ptr", block);
  1716. return DoGenGetValues(ctx, statePtr, block);
  1717. }
  1718. Y_NO_INLINE ICodegeneratorInlineWideNode::TGenerateResult TPairStateWideFlowCodegeneratorNodeBase::GenGetValuesImpl(
  1719. const IComputationNode* node, const TCodegenContext& ctx, BasicBlock*& block) const {
  1720. auto& context = ctx.Codegen.GetContext();
  1721. auto idx = node->GetIndex();
  1722. const auto valueType = Type::getInt128Ty(context);
  1723. const auto firstPtr = GetElementPtrInst::CreateInBounds(valueType, ctx.GetMutables(), {ConstantInt::get(Type::getInt32Ty(context), idx)}, "first_ptr", block);
  1724. const auto secondPtr = GetElementPtrInst::CreateInBounds(valueType, ctx.GetMutables(), {ConstantInt::get(Type::getInt32Ty(context), ++idx)}, "second_ptr", block);
  1725. return DoGenGetValues(ctx, firstPtr, secondPtr, block);
  1726. }
  1727. Y_NO_INLINE Value* TPairStateFlowCodegeneratorNodeBase::CreateGetValueImpl(
  1728. const IComputationNode* node, const TCodegenContext& ctx, BasicBlock*& block) const {
  1729. auto& context = ctx.Codegen.GetContext();
  1730. auto idx = node->GetIndex();
  1731. const auto valueType = Type::getInt128Ty(context);
  1732. const auto firstPtr = GetElementPtrInst::CreateInBounds(valueType, ctx.GetMutables(), {ConstantInt::get(Type::getInt32Ty(context), idx)}, "first_ptr", block);
  1733. const auto secondPtr = GetElementPtrInst::CreateInBounds(valueType, ctx.GetMutables(), {ConstantInt::get(Type::getInt32Ty(context), ++idx)}, "second_ptr", block);
  1734. const auto value = DoGenerateGetValue(ctx, firstPtr, secondPtr, block);
  1735. if (value->getType()->isPointerTy()) {
  1736. const auto load = new LoadInst(valueType, value, "load", block);
  1737. ValueRelease(node->GetRepresentation(), load, ctx, block);
  1738. return load;
  1739. } else {
  1740. return value;
  1741. }
  1742. }
  1743. Y_NO_INLINE Value* TBinaryCodegeneratorNodeBase::CreateGetValueImpl(const IComputationNode* node,
  1744. const TCodegenContext& ctx, BasicBlock*& block) const {
  1745. const auto value = DoGenerateGetValue(ctx, block);
  1746. if (value->getType()->isPointerTy()) {
  1747. ValueRelease(node->GetRepresentation(), value, ctx, block);
  1748. const auto load = new LoadInst(Type::getInt128Ty(ctx.Codegen.GetContext()), value, "load", block);
  1749. return load;
  1750. } else {
  1751. return value;
  1752. }
  1753. }
  1754. Y_NO_INLINE Value* TMutableCodegeneratorNodeBase::CreateGetValueImpl(
  1755. bool stateless, EValueRepresentation representation, ui32 valueIndex,
  1756. const TString& name, const TCodegenContext& ctx, BasicBlock*& block) const {
  1757. if (stateless) {
  1758. const auto newValue = DoGenerateGetValue(ctx, block);
  1759. if (newValue->getType()->isPointerTy()) {
  1760. ValueRelease(representation, newValue, ctx, block);
  1761. const auto load = new LoadInst(Type::getInt128Ty(ctx.Codegen.GetContext()), newValue, "load", block);
  1762. return load;
  1763. } else {
  1764. return newValue;
  1765. }
  1766. }
  1767. return ctx.AlwaysInline ? MakeGetValueBody(representation, valueIndex, ctx, block) :
  1768. CallInst::Create(GenerateInternalGetValue(name, representation, valueIndex, ctx.Codegen), {ctx.Ctx}, "getter", block);
  1769. }
  1770. Function* TMutableCodegeneratorNodeBase::GenerateInternalGetValue(const TString& name,
  1771. EValueRepresentation representation, ui32 valueIndex, NYql::NCodegen::ICodegen& codegen) const {
  1772. auto& module = codegen.GetModule();
  1773. auto& context = codegen.GetContext();
  1774. if (const auto f = module.getFunction(name.c_str()))
  1775. return f;
  1776. const auto funcType = FunctionType::get(Type::getInt128Ty(context), {PointerType::getUnqual(GetCompContextType(context))}, false);
  1777. TCodegenContext ctx(codegen);
  1778. ctx.Func = cast<Function>(module.getOrInsertFunction(name.c_str(), funcType).getCallee());
  1779. DISubprogramAnnotator annotator(ctx, ctx.Func);
  1780. auto main = BasicBlock::Create(context, "main", ctx.Func);
  1781. ctx.Ctx = &*ctx.Func->arg_begin();
  1782. ctx.Ctx->addAttr(Attribute::NonNull);
  1783. const auto get = MakeGetValueBody(representation, valueIndex, ctx, main);
  1784. ReturnInst::Create(context, get, main);
  1785. return ctx.Func;
  1786. }
  1787. Value* TMutableCodegeneratorNodeBase::MakeGetValueBody(EValueRepresentation representation, ui32 valueIndex, const TCodegenContext& ctx, BasicBlock*& block) const {
  1788. auto& context = ctx.Codegen.GetContext();
  1789. const auto indexType = Type::getInt32Ty(context);
  1790. const auto valueType = Type::getInt128Ty(context);
  1791. const auto valuePtr = GetElementPtrInst::CreateInBounds(valueType, ctx.GetMutables(), {ConstantInt::get(indexType, valueIndex)}, "value_ptr", block);
  1792. const auto value = new LoadInst(valueType, valuePtr, "value", block);
  1793. const auto invv = ConstantInt::get(value->getType(), 0xFFFFFFFFFFFFFFFFULL);
  1794. const auto check = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_EQ, value, invv, "check", block);
  1795. const auto comp = BasicBlock::Create(context, "comp", ctx.Func);
  1796. const auto done = BasicBlock::Create(context, "done", ctx.Func);
  1797. BranchInst::Create(comp, done, check, block);
  1798. block = comp;
  1799. const auto newValue = DoGenerateGetValue(ctx, block);
  1800. if (newValue->getType()->isPointerTy()) {
  1801. const auto load = new LoadInst(valueType, newValue, "value", block);
  1802. new StoreInst(load, valuePtr, block);
  1803. new StoreInst(ConstantInt::get(load->getType(), 0), newValue, block);
  1804. } else {
  1805. new StoreInst(newValue, valuePtr, block);
  1806. ValueAddRef(representation, valuePtr, ctx, block);
  1807. }
  1808. BranchInst::Create(done, block);
  1809. block = done;
  1810. const auto result = new LoadInst(valueType, valuePtr, "result", false, block);
  1811. return result;
  1812. }
  1813. Y_NO_INLINE Value* TMutableCodegeneratorPtrNodeBase::CreateGetValueImpl(
  1814. bool stateless, EValueRepresentation representation, ui32 valueIndex,
  1815. const TString& name, const TCodegenContext& ctx, BasicBlock*& block) const {
  1816. if (stateless) {
  1817. const auto type = Type::getInt128Ty(ctx.Codegen.GetContext());
  1818. const auto pointer = ctx.Func->getEntryBlock().empty() ?
  1819. new AllocaInst(type, 0U, "output", &ctx.Func->getEntryBlock()):
  1820. new AllocaInst(type, 0U, "output", &ctx.Func->getEntryBlock().back());
  1821. DoGenerateGetValue(ctx, pointer, block);
  1822. ValueRelease(representation, pointer, ctx, block);
  1823. const auto load = new LoadInst(type, pointer, "load", block);
  1824. return load;
  1825. }
  1826. return ctx.AlwaysInline ? MakeGetValueBody(valueIndex, ctx, block) :
  1827. CallInst::Create(GenerateInternalGetValue(name, valueIndex, ctx.Codegen), {ctx.Ctx}, "getter", block);
  1828. }
  1829. Value* TMutableCodegeneratorPtrNodeBase::MakeGetValueBody(ui32 valueIndex, const TCodegenContext& ctx, BasicBlock*& block) const {
  1830. auto& context = ctx.Codegen.GetContext();
  1831. const auto indexType = Type::getInt32Ty(context);
  1832. const auto valueType = Type::getInt128Ty(context);
  1833. const auto valuePtr = GetElementPtrInst::CreateInBounds(valueType, ctx.GetMutables(), {ConstantInt::get(indexType, valueIndex)}, "value_ptr", block);
  1834. const auto value = new LoadInst(valueType, valuePtr, "value", block);
  1835. const auto invv = ConstantInt::get(value->getType(), 0xFFFFFFFFFFFFFFFFULL);
  1836. const auto check = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_EQ, value, invv, "check", block);
  1837. const auto comp = BasicBlock::Create(context, "comp", ctx.Func);
  1838. const auto done = BasicBlock::Create(context, "done", ctx.Func);
  1839. BranchInst::Create(comp, done, check, block);
  1840. block = comp;
  1841. DoGenerateGetValue(ctx, valuePtr, block);
  1842. BranchInst::Create(done, block);
  1843. block = done;
  1844. const auto result = new LoadInst(valueType, valuePtr, "result", false, block);
  1845. return result;
  1846. }
  1847. Function* TMutableCodegeneratorPtrNodeBase::GenerateInternalGetValue(const TString& name, ui32 valueIndex, NYql::NCodegen::ICodegen& codegen) const {
  1848. auto& module = codegen.GetModule();
  1849. auto& context = codegen.GetContext();
  1850. if (const auto f = module.getFunction(name.c_str()))
  1851. return f;
  1852. const auto contextType = GetCompContextType(context);
  1853. const auto funcType = FunctionType::get(Type::getInt128Ty(context), {PointerType::getUnqual(contextType)}, false);
  1854. TCodegenContext ctx(codegen);
  1855. ctx.Func = cast<Function>(module.getOrInsertFunction(name.c_str(), funcType).getCallee());
  1856. DISubprogramAnnotator annotator(ctx, ctx.Func);
  1857. auto main = BasicBlock::Create(context, "main", ctx.Func);
  1858. ctx.Ctx = &*ctx.Func->arg_begin();
  1859. ctx.Ctx->addAttr(Attribute::NonNull);
  1860. const auto get = MakeGetValueBody(valueIndex, ctx, main);
  1861. ReturnInst::Create(context, get, main);
  1862. return ctx.Func;
  1863. }
  1864. Y_NO_INLINE Value* TMutableCodegeneratorFallbackNodeBase::DoGenerateGetValueImpl(
  1865. uintptr_t methodPtr, uintptr_t thisPtr, const TCodegenContext& ctx, BasicBlock*& block) const {
  1866. auto& context = ctx.Codegen.GetContext();
  1867. const auto type = Type::getInt128Ty(context);
  1868. const auto ptrType = PointerType::getUnqual(StructType::get(context));
  1869. const auto doFunc = ConstantInt::get(Type::getInt64Ty(context), methodPtr);
  1870. const auto self = CastInst::Create(Instruction::IntToPtr, ConstantInt::get(Type::getInt64Ty(context), thisPtr), ptrType, "self", block);
  1871. const auto funType = FunctionType::get(type, {self->getType(), ctx.Ctx->getType()}, false);
  1872. const auto doFuncPtr = CastInst::Create(Instruction::IntToPtr, doFunc, PointerType::getUnqual(funType), "function", block);
  1873. const auto value = CallInst::Create(funType, doFuncPtr, {self, ctx.Ctx}, "value", block);
  1874. return value;
  1875. }
  1876. Y_NO_INLINE Function* TCodegeneratorRootNodeBase::GenerateGetValueImpl(
  1877. const TString& name, const ICodegeneratorInlineNode* gen, NYql::NCodegen::ICodegen& codegen) {
  1878. auto& module = codegen.GetModule();
  1879. auto& context = codegen.GetContext();
  1880. if (const auto f = module.getFunction(name.c_str()))
  1881. return f;
  1882. const auto valueType = Type::getInt128Ty(context);
  1883. const auto contextType = GetCompContextType(context);
  1884. const auto funcType =
  1885. FunctionType::get(valueType, {PointerType::getUnqual(contextType)}, false);
  1886. TCodegenContext ctx(codegen);
  1887. ctx.Func = cast<Function>(module.getOrInsertFunction(name.c_str(), funcType).getCallee());
  1888. DISubprogramAnnotator annotator(ctx, ctx.Func);
  1889. auto args = ctx.Func->arg_begin();
  1890. auto main = BasicBlock::Create(context, "main", ctx.Func);
  1891. ctx.Ctx = &*args;
  1892. ctx.Ctx->addAttr(Attribute::NonNull);
  1893. const auto get = gen->CreateGetValue(ctx, main);
  1894. ReturnInst::Create(context, get, main);
  1895. return ctx.Func;
  1896. }
  1897. #if __clang__ && (__clang_major__ < 16)
  1898. TSrcLocation TSrcLocation::current() {
  1899. return {};
  1900. }
  1901. const char* TSrcLocation::file_name() const {
  1902. return __FILE__;
  1903. }
  1904. size_t TSrcLocation::line() const {
  1905. return __LINE__;
  1906. }
  1907. size_t TSrcLocation::column() const {
  1908. return 0;
  1909. }
  1910. #endif
  1911. DISubprogramAnnotator::DISubprogramAnnotator(TCodegenContext& ctx, Function* subprogramFunc, const TSrcLocation& location)
  1912. : Ctx(ctx)
  1913. , DebugBuilder(std::make_unique<DIBuilder>(ctx.Codegen.GetModule()))
  1914. , Subprogram(MakeDISubprogram(subprogramFunc->getName(), location))
  1915. , Func(subprogramFunc)
  1916. {
  1917. subprogramFunc->setSubprogram(Subprogram);
  1918. Ctx.Annotator = this;
  1919. }
  1920. DISubprogramAnnotator::~DISubprogramAnnotator() {
  1921. Ctx.Annotator = nullptr;
  1922. { // necessary stub annotation of "CallInst"s
  1923. DIScopeAnnotator stubAnnotate(this);
  1924. for (BasicBlock& block : *Func) {
  1925. for (Instruction& inst : block) {
  1926. if (CallInst* callInst = dyn_cast_or_null<CallInst>(&inst)) {
  1927. const auto& debugLoc = callInst->getDebugLoc();
  1928. if (!debugLoc) {
  1929. stubAnnotate(callInst);
  1930. }
  1931. }
  1932. }
  1933. }
  1934. }
  1935. DebugBuilder->finalizeSubprogram(Subprogram);
  1936. }
  1937. DIFile* DISubprogramAnnotator::MakeDIFile(const TSrcLocation& location) {
  1938. TFsPath path = TString(location.file_name());
  1939. return DebugBuilder->createFile(path.GetName().c_str(), path.Parent().GetPath().c_str());
  1940. }
  1941. DISubprogram* DISubprogramAnnotator::MakeDISubprogram(const StringRef& name, const TSrcLocation& location) {
  1942. const auto file = MakeDIFile(location);
  1943. const auto unit = DebugBuilder->createCompileUnit(llvm::dwarf::DW_LANG_C_plus_plus, file, "MKQL", false, "", 0);
  1944. const auto subroutineType = DebugBuilder->createSubroutineType(DebugBuilder->getOrCreateTypeArray({}));
  1945. return DebugBuilder->createFunction(
  1946. unit,
  1947. name,
  1948. llvm::StringRef(),
  1949. file, 0,
  1950. subroutineType, 0, llvm::DINode::FlagPrototyped, llvm::DISubprogram::SPFlagDefinition
  1951. );
  1952. }
  1953. DIScopeAnnotator::DIScopeAnnotator(DISubprogramAnnotator* subprogramAnnotator, const TSrcLocation& location)
  1954. : SubprogramAnnotator(nullptr)
  1955. , Scope(nullptr)
  1956. {
  1957. Y_ENSURE(subprogramAnnotator != nullptr);
  1958. SubprogramAnnotator = subprogramAnnotator;
  1959. Scope = SubprogramAnnotator->DebugBuilder->createLexicalBlock(SubprogramAnnotator->Subprogram, SubprogramAnnotator->MakeDIFile(location), location.line(), location.column());
  1960. }
  1961. Instruction* DIScopeAnnotator::operator()(Instruction* inst, const TSrcLocation& location) const {
  1962. inst->setDebugLoc(DILocation::get(SubprogramAnnotator->Ctx.Codegen.GetContext(), location.line(), location.column(), Scope));
  1963. return inst;
  1964. }
  1965. }
  1966. }
  1967. #endif