openGauss之LLVM代码走读 一. 前言openGauss的LLVM是指动态使用LLVM的库来构建动态代码和编译成字节码加速频繁调用的代码块的执行时间主要用在向量引擎中读取数据和join计算等场景下的计算加速被视为一个重要的性能优化方向。openGauss中通过将enable_codegen设置成true和codegen_cost_threshold设置为0强制开启此特性。本文主要简单的sqlselect col_bool is true from test1 了解openGauss是如何通过LLVM 动态生成col_bool is true的计算代码的。二. ExecInitCStoreScan 根据node生成动态代码ExecInitCStoreScan 的时候将expr的实现修改成动态代码的方式实现if (consider_codegen plan_stat-ps_ProjInfo-pi_targetlist) { jitted_vectarget dorado::VecExprCodeGen::TargetListCodeGen(plan_stat-ps_ProjInfo-pi_targetlist, (PlanState*)scan_stat); // 如下声明动态生成的函数为 bool JittedVecTargetList(ExprContext* econtext, VectorBatch* pBatch) GsCodeGen::FnPrototype fn_prototype(llvmCodeGen, JittedVecTargetList, boolType); fn_prototype.addArgument(GsCodeGen::NamedVariable(econtext, ExprContextPtrType)); fn_prototype.addArgument(GsCodeGen::NamedVariable(pBatch, VectorBatchPtrType)); jitted_vectarget fn_prototype.generatePrototype(builder, llvmargs[0]); // 生成ecxt_batch WrapGetVectorBatch(econtext) ecxt_batch WrapGetVectorBatchCodeGen(builder, econtext); // 生成 int m_rows pBatch-m_rows nsize builder.CreateLoad(int32Type, val, m_rows); // 生成for (int64 i 0; i nsize, i) builder.SetInsertPoint(for_body); Phi_idx builder.CreatePHI(int64Type, 2); idx_next builder.CreateAdd(Phi_idx, Datum_1); Phi_idx-addIncoming(Datum_0, entry); Phi_idx-addIncoming(idx_next, bb_end); // 依次生成每列的计算代码块,比如 // pBatch-m_arr[0]-m_vals[i] xx; // pBatch-m_arr[1]-m_vals[i] xx; // pBatch-m_arr[2]-m_vals[i] xx; foreach (cell, targetlist) { // 生成计算表达式的代码块比如对于is ture的判断生成一个JittedBooleanTest的动态代码实现原理和本代码段基本一样 res CodeGen(args); // 当前为第几列 AttrNumber resind tle-resno - 1; // 生成pBatch-m_arr[resind]-m_vals[i] res比如 // pBatch-m_arr[0]-m_vals[i] res Vals[0] colind; Vals[1] m_valsoffset; argVec builder.CreateInBoundsGEP(argArr, Vals); argVec builder.CreateLoad(int64PtrType, argVec, m_vals); argVal builder.CreateInBoundsGEP(argVec, loop_index); // 生成pBatch-m_arr[resind]-m_flag[i] tmpNull比如 // pBatch-m_arr[0]-m_flag[i] tmpNull Vals[1] m_flagoffset; argFlag builder.CreateInBoundsGEP(argArr, Vals); argFlag builder.CreateLoad(int8PtrType, argFlag, m_flag); llvm::Value* tmpFlag builder.CreateInBoundsGEP(argFlag, loop_index); llvm::Value* tmpNull isNull; tmpNull builder.CreateLoad(int8Type, tmpNull); builder.CreateStore(tmpNull, tmpFlag); } // pBatch-m_rows nsize foreach (cell, targetlist) { GenericExprState* gstate (GenericExprState*)lfirst(cell); TargetEntry* tle (TargetEntry*)gstate-xprstate.expr; AttrNumber resind tle-resno - 1; DEFINE_CGVAR_INT32(colind, resind); Vals[0] colind; Vals[1] int32_0; val1 builder.CreateInBoundsGEP(argArr, Vals); builder.CreateStore(nsize, val1); // argArr[resind].m_rows nsize; } // 存到hashMap中待后续生成机器码保存到plan_stat-ps_ProjInfo-jitted_vectarget中 if (jitted_vectarget ! NULL) llvm_code_gen-addFunctionToMCJit( jitted_vectarget, reinterpret_castvoid**((plan_stat-ps_ProjInfo-jitted_vectarget))); }综上所示上述的代码会生成一个类似如下的动态代码段bool JittedVecTargetList(ExprContext* econtext, VectorBatch* pBatch) { VectorBatch* ecxt_batch LLVMWrapGetVecBatch(econtext); int m_rows ecxt_batch-m_rows; for (int64 i 0; i m_rows; i) { // 同样用动态的方式生成列表达式的计算代码 res CodeGen(args); pBatch-m_arr[0]-m_vals[i] res; pBatch-m_arr[0]-m_flag[i] isNull; res CodeGen(args); pBatch-m_arr[1]-m_vals[i] res; pBatch-m_arr[1]-m_flag[i] isNull; res CodeGen(args); pBatch-m_arr[2]-m_vals[i] res; pBatch-m_arr[2]-m_flag[i] isNull; ..... } pBatch-m_arr[0].m_rows nsize; pBatch-m_arr[1].m_rows nsize; pBatch-m_arr[2].m_rows nsize; .... }三. standard_ExecutorRun中编译函数生成字节码步骤二生成的代码块仍然只是动态代码块需要编译成二进制字节码才可被执行。standard_ExecutorRun if (CodeGenThreadObjectReady()) { CodeGenThreadRuntimeCodeGenerate(); ((dorado::GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj)-enableOptimizations(true); //对代码段使用o3优化 ((dorado::GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj)-compileCurrentModule(false); GsCodeGen::compileCurrentModule llvm::Function* func map-key; // 步骤二生成的函数 void* jittedFunction exectorEngine-getPointerToFunction(func); // 编译成机器码 *map-value jittedFunction; // 编译后的字节码赋值给plan_stat-ps_ProjInfo-jitted_vectarget }四. 调用执行LLVM的动态代码在执行算子时判断如果plan_stat-ps_ProjInfo-jitted_vectarget有动态生成的机器码那么使用动态生成的机器码否则使用原来的流程。ExecVecProject if (projInfo-pi_targetlist) { if (projInfo-jitted_vectarget) { // 有动态生成的字节码 projInfo-jitted_vectarget(econtext, pProjBatch); JittedVecTargetList // 调用生成的函数 } }

相关新闻

最新新闻

A2牛奶技术解密:基因分型与蛋白定量全链路指南

A2牛奶技术解密:基因分型与蛋白定量全链路指南

如果你以为 A2 牛奶是“无乳糖牛奶”或者“喝了不胀肚的神奶”,那你可能被市场文案带偏了。A2 牛奶真正的价值,不在乳糖,而在蛋白质:它指向的是牛奶中 β-酪蛋白的一种遗传变异体差异。这个差异很小,小到只是 200 多个…

2026/8/30 1:27:42
乐视2017暑期实习生笔试题详解:Java/C/Linux核心考点与答题策略

乐视2017暑期实习生笔试题详解:Java/C/Linux核心考点与答题策略

乐视2017暑期实习生笔试题(一),这份卷子我刷了两遍,第一遍掐着时间做,第二遍逐题分析出题意图。说实话,乐视的实习笔试题在当年属于“看着不难、做对不易”的典型代表,尤其是Java和C语言基础部分…

2026/8/30 1:27:42
基于CMake重构RTKLIB:跨平台构建GNSS高精度定位软件实践

基于CMake重构RTKLIB:跨平台构建GNSS高精度定位软件实践

简介:本资源是面向GNSS导航定位开发者与科研人员的跨平台RTKLIB构建工程,解决传统Makefile或IDE手动配置导致的多系统适配难、依赖管理繁琐等问题。项目基于CMake重构RTKLIB核心工具链,一键生成Linux/Windows/macOS原生构建环境,显…

2026/8/30 1:27:42
ST官网搜STM32应用笔记总重复?快速定位AN4899正确版本

ST官网搜STM32应用笔记总重复?快速定位AN4899正确版本

1. 这个搜索问题是什么,为什么会遇到在 ST 官网(st.com)搜芯片相关的应用笔记时,结果一次翻出好几个看起来一模一样的标题,这种情况我相信很多嵌入式工程师都撞见过。前阵子我的项目里要用到一份 AN4899 文档&#xff…

2026/8/30 1:27:42
AI人类模拟器:从对话玩具到行为系统的架构拆解与开源实践

AI人类模拟器:从对话玩具到行为系统的架构拆解与开源实践

AI人类模拟器,价值130亿:从“对话玩具”到“行为系统”的技术拆解 如果你用过 ChatGPT、Kimi 或者豆包,大概率会有一种感觉:它很聪明,但不像一个“人”。它不会因为你说“我分手了”而沉默几秒,也不会因为连…

2026/8/30 1:27:42
爬虫零基础入门:Requests、BeautifulSoup与数据提取全流程

爬虫零基础入门:Requests、BeautifulSoup与数据提取全流程

动手写爬虫的第一天,很多人会卡在同一个位置:照着文档把requests.get写出来了,网页内容也打印出来了,然后呢?看到一屏密密麻麻的 HTML,不知道下一步该做什么。另一部分人更早放弃,他们想抓的页面…

2026/8/30 1:22:42