- 博客(1270)
- 资源 (1)
- 收藏
- 关注
原创 LLVM系列第二十八章:写一个JIT Hello World
JIT(Just In Time)也是一个程序,它在运行时,创建并执行了一些新的代码,而这些新代码并不是属于JIT程序本身的。Legacy JIT (LLVM 1.0 - 3.5),引入了ExecutionEngine、延迟编译(lazy compilation),在当前进程中运行(in-process only),在 LLVM 3.5之后被移除了。本章我们就来写一个简单的Hello World,初步感受一下LLVM的ORC JIT引擎是什么样子的。
2024-09-21 11:08:02
146
原创 LLVM系列第二十七章:理解IRBuilder
如果未指定,则默认使用IRBuilderDefaultInserter,这个Hook指定了“每次插入的位置总是当前最新的插入点”,即没有做位置上的偏移或跳跃。由以上可以看出,IRBuilder就是一个工具,它提供了一套统一的API,以便用户用来创建IR指令(Instruction),并插入到代码块中。如果要使用其它未集成的API,可以在创建好指令之后,直接对指令进行操作,比如直接调用LoadInst::setVolatile()等各种Instruction的成员函数。
2024-09-21 11:06:42
145
原创 LLVM系列第二十六章:理解LLVMContext
再举个例子,有这样一个多线程的程序,其中一个线程运行图像处理库(Graphics Library),另一个线程运行音频处理库(Audio Library),而这两个库都调用了LLVM。在很久以前,也就是LLVM的老版本中,这些状态数据都是全局数据。我们可以把它理解为一个黑盒,它包含(并管理)了LLVM中基础的、核心的“全局”数据,如类型(Type)、标准化的常量表等。通常来说,LLVM的用户也许不需要知道context是什么,但编程语言的开发者(即编译器的开发者)是需要清楚地知道context是什么的。
2024-09-21 11:05:41
355
原创 LLVM系列第二十五章:简单统计一下LLVM源码行数
关于如何下载LLVM源码,请参考第一章 《LLVM系列第一章:编译LLVM源码》。注意这里使用的是LLVM 12的源码。可以看到,llvm-project的C++代码已经接近600万行,大约是中大型规模的软件(库)。我们可以用一个名为"scc"的工具来统计LLVM的源码。可以看到,LLVM的C++代码已经超过了200万行,大约是中小型规模的软件(库)。LLVM系列第二十二章:写一个简单的编译时函数调用统计器(Pass)LLVM系列第二十三章:写一个简单的运行时函数调用统计器(Pass)
2024-09-21 11:04:49
357
原创 LLVM系列第二十四章:用Xcode编译调试LLVM源码
注意,在配置之前,须确保选中了opt作为编译目标,即我们编辑的是opt程序的Scheme。生成的Xcode项目文件在目录build-xcode中,我们进入该目录并用Xcode打开项目文件LLVM.xcodeproj即可。我们在第一章中编译LLVM源码时,使用的工具是Ninja,本章用的工具是Xcode。我们利用Xcode编译了LLVM的源代码,并用opt作为例子,简单地调试了一下与LLVM Pass相关的代码。开发环境的配置请参考第一章 《LLVM系列第一章:编译LLVM源码》。
2024-09-21 11:02:23
355
原创 LLVM系列第二十二章:写一个简单的编译时函数调用统计器(Pass)
所以,我们要做的是,遍历模块中的每一个函数、函数中的每一个代码块、代码块中的每一条指令。如上所述,CompileTimeFunctionCallCounter将会遍历模块中的每一个函数、函数中的每一个代码块、代码块中的每一条指令,统计每个函数的调用次数并打印出来。我们用LLVM提供的C++ API,写了一个简单的Pass,用来统计每个函数在编译时的调用次数,并且做了测试。CompileTimeFunctionCallCounter,一个简单的Pass模块,用来统计每个函数在编译时的调用次数。
2024-09-21 11:01:37
245
原创 LLVM系列第二十一章:写一个简单的Loop Pass
Loop Pass执行的顺序是由内而外的,即内层的循环先执行,外层的循环后执行。如果我们是在第一章的编译LLVM完成之后,再编译此项目,则仅仅需要编译SimpleLoopPass项目即可。注意,我们需要把SimpleLoopPass项目加入到LLVM Transforms父项目中,即指示CMake在编译LLVM源码的同时,也要编译SimpleLoopPass项目。我们用LLVM提供的C++ API,创建了一个简单的Loop Pass,并且编译运行成功。
2024-09-21 11:00:35
228
原创 LLVM系列第二十章:写一个简单的Function Pass
Function Pass,顾名思义,是在程序中的每个函数(function)上执行的。具体地说,Function Pass不能添加或删除当前模块的函数或全局变量,也不能分析或修改当前正在被处理的函数之外的其它函数。注意,我们需要把SimpleFunctionPass项目加入到LLVM Transforms父项目中,即指示CMake在编译LLVM源码的同时,也要编译SimpleFunctionPass项目。我们用LLVM提供的C++ API,创建了一个简单的Function Pass,并且编译运行成功。
2024-09-21 10:59:25
203
原创 LLVM系列第十九章:写一个简单的Module Pass
如果我们是在第一章的编译LLVM完成之后,再编译此项目,则仅仅需要编译SimpleModulePass项目即可。注意,我们需要把SimpleModulePass项目加入到LLVM Transforms父项目中,即指示CMake在编译LLVM源码的同时,也要编译SimpleModulePass项目。我们用LLVM提供的C++ API,创建了一个简单的Module Pass,并且编译运行成功。在此记录下用LLVM创建一个简单的Module Pass的过程,以备查阅。
2024-09-21 10:58:03
214
原创 LLVM系列第十八章:写一个简单的IR处理流程Pass
Pass是LLVM中很重要的部分。LLVM Pass可以处理的对象有模块(Module)、函数(Function)、循环(Loop),甚至函数调用栈(Function Call Graph)等等。注意,我们需要把MyPass项目加入到LLVM Transforms父项目中,即指示CMake在编译LLVM源码的同时,也要编译MyPass项目。我们用LLVM提供的C++ API,创建了一个简单的Pass,并且编译运行成功。在此记录下用LLVM创建一个简单的IR处理流程(Pass)的过程,以备查阅。
2024-09-21 10:56:34
576
原创 LLVM系列第十五章:写一个简单的中间代码生成器IR Generator
Module中可以包含函数定义及实现,而函数中则包含了基本代码块BasicBlock,而BasicBlock则包含了一行行的代码,比如变量赋值、数学运算表达式、函数调用、函数返回等等。IRGenerator.h和IRGenerator.cpp,中间代码(Intermediate Representation,即IR)生成器的定义及实现代码。注意到,与前几章相比,我在这里调用了比较多的LLVM API。Lexer.h和Lexer.cpp,SimpleLang语言的词法分析器(Lexer)的定义及实现代码。
2024-09-20 20:38:32
221
原创 LLVM系列第十四章:写一个简单的语义分析器Semantic Analyzer
这个示例中,语义分析其实就是遍历AST的节点,并检查每个节点上的变量申明是否符合SimpleLang语言的规则。与词法分析(Lexical Analysis)及语法分析(Syntax Analysis)相关的文章,请参看《LLVM系列第三章:写一个简单的词法分析器Lexer》和《LLVM系列第四章:写一个简单的语法分析器Parser》。我们参考编译器设计中常用的数据结构定义及算法,基于LLVM提供的API,用C++写了一个很简单的词法分析器,并且编译运行成功。其中,变量a被声明了两次,变量b缺少了申明。
2024-09-20 20:35:26
221
原创 LLVM系列第十三章:写一个简单的语法分析器Parser
可以看到,我们的SimpleParser工具把SimpleLang程序代码切分成了一系列的Token,用这些Token构建出了一颗抽象语法树(AST),最后把AST打印了出来。我们参考编译器设计中常用的数据结构定义及算法,基于LLVM提供的API,用C++写了一个很简单的代码语法分析器,并且编译运行成功。src/Parser.h,src/Parser.cpp,包含了语法分析器(Parser)的定义及实现代码。在此记录下,基于LLVM写一个简单的语法分析器(Simple Parser)的过程,以备查阅。
2024-09-20 20:30:44
189
原创 LLVM系列第十二章:写一个简单的词法分析器Lexer
源文件Lexer.h和Lexer.cpp,包含了SimpleLang语言的词法分析器(Lexer)的定义及实现代码。代码生成器(Code Generator,简称 CodeGen),从 AST 生成用中间表达语言(Intermediate Representation,简称IR)组成的程序代码。我们参考编译器设计的经典词法分析算法,基于LLVM提供的API,用C++写了一个很简单的词法分析器,并且编译运行成功。在此记录下,基于LLVM写一个简单的词法分析器(Simple Lexer)的过程,以备查阅。
2024-09-20 20:29:08
189
原创 LLVM系列第十一章:写一个Hello World
simplelang将会调用simplelangBasic中的函数,并把结果打印出来。我们参考LLVM的项目组织结构,基于LLVM提供的API,用C++写了一个Hello World,并且编译运行成功。原文链接:https://blog.csdn.net/Zhanglin_Wu/article/details/124963173。注意/path/to/llvm-project代表的是llvm-project的源代码路径。开发环境的配置请参考第一章 《LLVM系列第一章:编译LLVM源码》。
2024-09-20 20:27:53
170
原创 LLVM系列第十章:控制流语句if-else-phi
第一个参数表示的是phi指令的返回值类型,如在以上示例中为i32。接下来的每一个参数都是一个数组,代表了每一个分支及其对应的返回值。C函数跟上一章用到的是一样的,只不过我们这次在IR代码中用到了phi指令而已。我们用LLVM提供的C++ API,创建了简单的if-else控制流语句,并打印出了其带有phi指令的IR代码。在很多情况下,控制流只是为了给某一个变量赋值,而phi 指令,则可以根据控制流来选择合适的值。不过,这一次我们用一个特殊的指令来生成IR代码,即phi指令。
2024-09-20 20:26:19
193
原创 LLVM系列第九章:控制流语句if-else
LLVM IR提供了一个指令,可以让我们在栈上申明变量,即 alloca 指令。注意用alloca 指令申明的变量,其实得到是变量的地址。我们用LLVM提供的C++ API,创建了简单的if-else控制流语句,并打印出了它的IR代码。LLVM系列第二十二章:写一个简单的编译时函数调用统计器(Pass)LLVM系列第二十三章:写一个简单的运行时函数调用统计器(Pass)LLVM系列第二十九章:写一个简单的常量加法“消除”工具(Pass)LLVM系列第二十章:写一个简单的Function Pass。
2024-09-20 20:25:10
185
原创 LLVM系列第八章:算术运算语句Arithmetic Statement
在LLVM中,一个简单的算术运算操作需要用到操作符和操作数。所以,要创建一条乘法运算指令,我们首先要得到两个操作数,它们可以来自于函数的参数、数值变量、数值常量等等。为简单起见,我们在这里可以把一个简单的算术运算语句理解为一条指令。我们用LLVM提供的C++ API,创建了一个算术运算语句(Arithmetic Statement),并打印出了它的IR代码。LLVM系列第二十二章:写一个简单的编译时函数调用统计器(Pass)LLVM系列第二十三章:写一个简单的运行时函数调用统计器(Pass)
2024-09-20 20:22:18
133
原创 LLVM系列第七章:函数参数Function Arguments
我们用LLVM提供的C++ API,创建了一个带有参数(Arguments)的函数(Function),并打印出了它的IR代码。本章,我们就来创建一个带有参数的函数。开发环境的配置请参考第一章 《LLVM系列第一章:编译LLVM源码》。LLVM系列第二十二章:写一个简单的编译时函数调用统计器(Pass)LLVM系列第二十三章:写一个简单的运行时函数调用统计器(Pass)LLVM系列第二十九章:写一个简单的常量加法“消除”工具(Pass)LLVM系列第二十章:写一个简单的Function Pass。
2024-09-20 20:20:52
147
原创 LLVM系列第六章:函数返回值Return
我们用LLVM提供的C++ API,创建了一个带有返回值(Return)的函数,并打印出了它的IR代码。我们知道,一个函数运行结束后可以返回一个结果,这就是函数的返回值。LLVM系列第二十二章:写一个简单的编译时函数调用统计器(Pass)LLVM系列第二十三章:写一个简单的运行时函数调用统计器(Pass)LLVM系列第二十九章:写一个简单的常量加法“消除”工具(Pass)LLVM系列第二十章:写一个简单的Function Pass。LLVM系列第十三章:写一个简单的语法分析器Parser。
2024-09-20 20:20:10
119
原创 LLVM系列第五章:全局变量Global Variable
全局变量在链接的时候,到底是指向同一个全局变量,还是多个不同的全局变量,是由链接类型决定的。这里说的“多个不同的全局变量”,意思是其名称相同,但是有多个“分身”( 可以简单地理解为Copy、Instance、实例等等),“分身”之间互不影响。我们用LLVM提供的C++ API,创建了一个全局变量(Global Variable),并打印出了它的IR代码。全局变量(Global Variable)是在一个模块(Module)之内全局可见的变量,也就是说模块内所有的函数都能用它。
2024-09-20 20:19:27
209
原创 LLVM系列第四章:逻辑代码块Block
代码块的起点是一个标签,它是整个代码块的标签。LLVM中的BasicBlock类,就是用来创建、使用、处理代码块的。当然,我们还可以使用LLVM提供的IR代码创建工具(类)IRBuilder,它能让我们更方便快捷的创建出代码块。我们用LLVM提供的C++ API,创建了一个最简单的基本逻辑代码块(BasicBlock),并打印出了它的IR代码。LLVM系列第二十二章:写一个简单的编译时函数调用统计器(Pass)在这一章中,我们就用LLVM提供的这些工具来创建一个最简单的代码块。
2024-09-20 20:16:43
333
原创 LLVM系列第三章:函数Function
当然,如果要创建一个函数,我们还需要用到其它工具,比如llvm::Function、llvm::FunctionType等。我们知道,函数也是有类型的,而llvm::FunctionType就是用来创建函数类型的。注意到这里用了llvm::verifyFunction, 它的作用是检查我们创建的函数是否正确,确保它是符合编程语言规范的。我们用LLVM提供的C++ API,创建了一个最简单的函数(Function),并打印出了它的IR代码。LLVM系列第二十二章:写一个简单的编译时函数调用统计器(Pass)
2024-09-20 20:14:15
124
原创 LLVM系列第二章:模块Module
简单来说,LLVM中的模块(Module),代表了一块代码。它是一个比较完整独立的代码块,是一个最小的编译单元。而LLVM中的模块(Module),我们可以把它初步理解为一个编译单元。在LLVM IR的基本概念(构件)中,模块是一个组合,它包含了其它更小的基本构件。我们用LLVM提供的C++ API,创建了一个最简单的模块(Module),并打印出了它的IR代码。LLVM系列第二十二章:写一个简单的编译时函数调用统计器(Pass)在这一章,我们就用LLVM的API来创建一个最简单的模块。
2024-09-20 20:13:27
202
原创 LLVM系列第一章:编译LLVM源码
我们利用Git下载了LLVM的源代码,用CMake和Ninja工具编译并安装了LLVM,最后还简单地试用了一下LLVM工具库中的llc工具。LLVM是一个著名的开源编译器项目、库、工具,在此记录下编译LLVM源码的过程,以备查阅。LLVM系列第二十二章:写一个简单的编译时函数调用统计器(Pass)LLVM系列第二十三章:写一个简单的运行时函数调用统计器(Pass)LLVM系列第二十九章:写一个简单的常量加法“消除”工具(Pass)LLVM系列第二十章:写一个简单的Function Pass。
2024-09-20 20:12:41
896
原创 最新CTR预测服务的GPU优化实践
因此,我们设计了一个Batch分桶策略,生成N个固定Batch的优化模型,在实际请求到来时找到Batch距离最近的一个Bucket,将请求向上Padding到对应的Batch计算,从而提高了GPU的利用效率。算子层面:目前主流的深度学习框架,如TensorFlow和PyTorch,可以说是深度学习第二代框架,它们首先要解决第一代框架Caffe的问题,Caffe有一个明显问题就是Layer的粒度过粗,导致那个时代的算法开发者都必须有“自己写自定义层”的能力。在最终方案实现上,我们参考了TF-TRT的设计。
2024-09-08 19:38:03
723
原创 终于有人将机器学习中的重点做成了动画
深度学习是机器学习的一个子领域,深度学习通过神经网络模拟人脑神经元的连接来进行复杂数据的学习与预测。其中,卷积神经网络(CNN)主要用于计算机视觉任务;循环神经网络(RNN)则适用于处理序列数据。今天介绍CV和NLP领域一些重要模型。[RNN] 手书动画 ✍️输入序列X:[3,4,5,6]参数矩阵:参数矩阵是通过训练得到的,图中虽然列了4个节点,但其实是同一个节点按照时间步展开的,这也是RNN经常被误解的地方。
2024-08-19 20:53:32
710
原创 【深度学习必读】从YOLOv1到YOLOv10了解基于CNN的目标检测发展历程
采用逆时间顺序分析,本研究考察了YOLO算法引入的进步,从YOLOv10开始,到YOLOv9、YOLOv8和后续版本,探索每个版本在提高实时目标检测的速度、准确性和计算效率方面的贡献。YOLOv10 提供了多种模型变体,如 YOLOv10-N(Nano)、YOLOv10-S(Small)、YOLOv10-M(Medium)、YOLOv10-B(Balanced)、YOLOv10-L(Large)和 YOLOv10-X(Extra Large),以适应不同的计算约束和操作需求。
2024-08-19 20:49:42
1069
原创 【图像复原与重构】椒盐、高斯、周期噪声、均值、中值、自适应、陷波滤波器、逆滤波、维纳滤波 C++
/输入图像,输出图像,均值,方差,系数。//定义输入图像,灰度图像,输出图像,add(image_gray, noise, image_output, Mat(), -1);//randn(a,b,c)产生高斯噪声,其中a为输出矩阵,b为均值,c为方差。原文链接:https://blog.csdn.net/qq_44785013/article/details/123853483。
2024-08-13 21:42:53
264
原创 【特征提取】SIFT、SURF、ORB、FAST
LBP具体在生成的过程中,先将图像划分为若干个子区域,子区域窗口可根据原图像的尺寸进行调整,而不一定非得为3×3的正方形窗口。②BRIEF特征描述: BRIEF描述子主要是通过随机选取兴趣点周围区域的若干点来组成小兴趣区域,将这些小兴趣区域的灰度二值化并解析成二进制码串,将串特征作为该特征点的描述子,BRIEF描述子选取关键点附近的区域并对每一位比较其强度大小,然后根据图像块中两个二进制点来判断当前关键点编码是0还是1.因为BRIEF描述子的所有编码都是二进制数的,这样就节省了计算机存储空间。
2024-08-13 21:36:41
585
原创 提取图像特征方法总结 是那种很传统的方法~
LBP具体在生成的过程中,先将图像划分为若干个子区域,子区域窗口可根据原图像的尺寸进行调整,而不一定非得为3×3的正方形窗口。②BRIEF特征描述: BRIEF描述子主要是通过随机选取兴趣点周围区域的若干点来组成小兴趣区域,将这些小兴趣区域的灰度二值化并解析成二进制码串,将串特征作为该特征点的描述子,BRIEF描述子选取关键点附近的区域并对每一位比较其强度大小,然后根据图像块中两个二进制点来判断当前关键点编码是0还是1.因为BRIEF描述子的所有编码都是二进制数的,这样就节省了计算机存储空间。
2024-08-13 11:29:22
721
原创 【图像模式分类】图像处理中的模板匹配c++实现
显然,当和具有完全相同的方向(平行) 时,,从而式(11-4) 取得其最大值,这就意味着当图像的局部区域类似于子图像模式时,相关运算产生最大的响应。然而,式(11-4) 最终的取值还与向量、自身的模有关,这将导致按照式(11-4) 计算的相关响应存在着对f和w 的灰度幅值比较敏感的缺陷。我们完全可以将子图像w视为一个按行或按列存储的向量,将计算过程中被w覆盖的图像区域视为另一个按照同样的方式存储的向量.这样一来,相关计算就- 成了向量之间的点积运算。// 模板图像第m行,第n个象素的灰度值。
2024-08-13 11:28:29
147
原创 【图像模式分类】模式识别 - 贝叶斯分类器的C++实现
将人的身高(height)和体重(weight)作为分类特征,分为两组类别,男性(male)和女性(female),现在给你一组男性的身高和体重的数据和女性的身高体重数据作为训练数据集训练出一个贝叶斯分类器。我们的问题是”给定特征判断这个特征所对应的类别”,一个容易想到的思路是算出这个特征属于每个类别的概率,然后取最大的那个类别作为最终的分类。,函数的返回值就是对应特征所属的类别,所有的分类器的目的都是去寻找一个比较好的函数能更好的描述特征与类别之间的关系。
2024-08-13 11:27:29
142
原创 C++手撸车道线检测(附代码)
由于高斯平滑是线性离散滤波,因此离散形式的高斯滤波器为 H i , j = 1 2 π σ 2 e ( i − k − 1 ) 2 + ( j − k − 1 ) 2 2 σ 2 H_{i,j} = \frac{1}{2\pi\sigma^2}e^{\frac{(i - k -1)^2 + (j - k - 1)^2}{2\sigma^2}}H。将图像空间中的直线映射到参数空间的一个点,然后对参数空间中的点进行累计投票,进而得到参数空间中的峰值点,该峰值点就对应空间坐标系中的真实存在的直线参数。
2024-08-12 22:03:49
156
原创 【图像分割】点、线和边缘检测,边缘连接,全局阈值检测,Otsu最值阈值检测,区域生长图像分割 C++
此外第二个点(xj,yj)在参数空间也有一条与之相关联的直线,除非他们是平行的,否则这条直线会与和(xi,yi)相关联的直线相交于点(a1,b1),其中a1为斜率,b1为包含xy平面中点(xi,yi)和点(xj,yj)的直线的截距。理想情况下,边缘检测应该进产生位于边缘上的像素级和,实际上,由于噪声、不均匀照明引起的边缘间断,以及其他引入灰度值虚假的不连续的影响,这些像素并不能完全描述边缘特性,因此问哦们在边缘检测后紧跟着连接算法,所设计的算法将边缘像素组合成有意义的变韵或区域边界。令【0,1,2,3…
2024-08-12 22:03:15
151
原创 等待下一篇文章
代码解读:上段代码中,我们需要注意的函数是cv2.dilate(函数),opecv包中的膨胀函数,包含三个参数,同上面一样,第一个为需要膨胀的原始图像,第二个为膨胀框的大小,第三个为迭代次数,这里设置为1 ,粉丝们可以自行设置哦。图像的膨胀操作也是属于图像形态学处理技术的一种,膨胀与腐蚀其实刚好是一对相反的操作,膨胀会将自身中出现的小黑点变换为白色区域(白多黑少),当图像中出现小黑点不好去除时,一般采用膨胀的方式。如上图所示,我们可以看到,原始图片中黑色区域变少了,白色区域相对增加了(黑少而白多)。
2024-08-12 21:59:26
814
原创 c++ opencv数字图像处理:频率域滤波--同态滤波
文章目录前言一、同态滤波原理1.处理原理二、同态滤波器模板及MATLAB代码1.同态滤波器2.代码前言数字图像处理c++ opencv(VS2019 opencv4.53)持续更新一、同态滤波原理1.处理原理(1)认为图像f(x,y)由两部分组成:照射分量i(x,y),反射分量r(x,y):f ( x , y ) = i ( x , y ) ∗ r ( x , y ) f(x,y)=i(x,y)*r(x,y)f(x,y)=i(x,y)∗r(x,y)(2)但上式不能直接用于对两个分量在
2024-08-12 21:32:34
272
原创 c++ opencv数字图像处理:频率域滤波--拉普拉斯滤波(锐化)
原文链接:https://blog.csdn.net/qq_44785013/article/details/121637167。
2024-08-12 21:30:46
208
原创 c++ opencv数字图像处理:频率域滤波--高通滤波--理想高通滤波
原文链接:https://blog.csdn.net/qq_44785013/article/details/121636545。
2024-08-12 21:29:37
196
原创 c++ opencv数字图像处理:频率域滤波--高通滤波--高斯高通滤波
/3.从多个单通道数组中创建一个多通道数组:transform_image。原文链接:https://blog.csdn.net/qq_44785013/article/details/121636239。
2024-08-12 21:28:29
278
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人
RSS订阅