LLVM Cpu0 新后端6
想好好熟悉一下llvm开发一个新后端都要干什么,于是参考了老师的系列文章:
LLVM 后端实践笔记
代码在这里(还没来得及准备,先用网盘暂存一下):
链接: https://pan.baidu.com/s/1yLAtXs9XwtyEzYSlDCSlqw?pwd=vd6s 提取码: vd6s
之前的章节只实现了 int 和 32 位的 long 类型数据,这一章会新增一些更复杂的数据类型,比如 char, bool, short, long long,还会增加结构体,浮点,和向量类型。这一部分内容相对比较简单,其实这些类型也都是标准语言都支持的类型,所以 LLVM 自身已经实现了很大一部分功能,只要我们的后端不那么奇怪,就很容易填补缺失的内容。
目录
一、修改的文件
1.1 Cpu0ISelDAGToDAG.cpp
1.2 Cpu0ISelLowering.cpp/.h
1.3 Cpu0InstrInfo.td
1.4 Cpu0SEISelDAGToDAG.cpp/.h
1.5 MCTargetDesc/Cpu0InstPrinter.cpp/.h
二、实现结果
2.1 局部指针
2.2 char类型
2.3 bool类型
2.4 short
2.5 long long 类型
2.6 局部数组、结构体
2.7 全局数组、结构体
2.8 向量
2.9 cl指令
一、修改的文件
1.1 Cpu0ISelDAGToDAG.cpp
在SelectAddr接口内增加对于基址+常量偏移这种地址形式的处理,对于全局基址加常量偏移的情况,提取其基址和偏移。。
1.2 Cpu0ISelLowering.cpp/.h
有关于对 bool 类型的处理,这里增加了一些对 i1 类型 Promote 的合法化描述,告诉 LLVM 在遇到对 i1 类型的 extend 时要做 Promote。Promote 是将较小宽度的数据类型扩展成对应的能够支持的更宽的数据宽度类型,在指令选择的类型合法化阶段会起到作用。在 long long 实现中,在 Lowering 的位置还需要增加对 long long 类型的移位操作合法化。
覆盖一个函数 isOffsetFoldingLegal(),直接返回 false,避免带偏移的全局地址展开,Cpu0 和 Mips 一样无法处理这种情况。我们实现的 getAddrNonPIC() 方法中,将全局符号地址展开成一条加法指令,对地址的高低位做加法运算。所以实际上我们会将一条全局地址带偏移的寻址展开成加法运算 base,然后再把结果与 offset 相加的 DAG(在 Cpu0ISelDAGToDAG.cpp 中的 SelectAddr 中提取这种情况的 node Value,此时就已经是两个 add node 了)。
最后,还需要对向量类型的支持做一小部分改动,覆盖 getSetCCResultType() 方法,如果是向量类型,使用 VT.changeVectorElementTypeToInteger() 方法返回 CC 值。
1.3 Cpu0InstrInfo.td
到目前,因为我们添加数据类型的很多实现代码已经在公共 LLVM 代码中实现,所以实际上大多数修改都在 td 文件中。
新增一个 mem_ea 的操作数类型,这是一个 complexpattern,会定义其 encoding 操作和 printinst 等操作,它用来描述指令 pattern 中的地址表示;然后要定义一个 LEA_ADDiu 的模式,这是一个不会输出成指令的模式,它实际上是计算地址+偏移的结果,这和 sparc 处理器中的 LEA_ADDRi 是一样的效果。
新增 i8 和 i16 相关的 extend 类型以及对应的 ld/st,命名为 LB, LBu, SB, LH, LHu, SH。LB, LH 处理有符号的 i8/i16 类型 load,LBu, LHu 处理无符号的 i8/i16 类型 load,SB, SH 处理i8/i16 类型的store。
新增 CountLeading0 和 CountLeading1 的 pattern,用来选择到计算前导 0 和计算前导 1 的指令,llvm 内置了 ctlz 的 node(count leading zero),可以直接把 clz 指令接过去,不过对于 count leading 1 是没有对应的 node 的,不过可以通过先对值取反然后求前导 0 的方式实现前导 1 的计算,即 ctlz (not RC:$rb)。
因为 C 语言没有对求前导 0 和前导 1 的原生语法,所以实际上会使用 builtin 接口来实现,也就是说,在 C 语言描述中,为了实现这种功能,需要调用 __builtin_clz() 函数(ctls 就是先对参数取反再调用 ctlz 的 builtin),因为我们使用了内置的 node,所以这部分是 llvm 帮我们实现了。
1.4 Cpu0SEISelDAGToDAG.cpp/.h
定义了一个 selectAddESubE() 方法,用来处理带进位的加减法运算的指令选择。在 trySelect() 方法中,将对 ISD::SUBE, ISD::ADDE 的情况选择用 selectAddESubE() 来处理。
selectAddESubE() 方法为符合条件的 node 新增了一个操作数节点,该节点会读取状态字中进位是否是 1,并将结果叠加到运算中;在 Cpu032I 处理器中,使用 CMP 指令和 ANDi 指令来获取进位状态,在 Cpu032II 处理器中,则使用 SLT 指令直接判断进位。
另外,还要处理 SMUL_LOHI 和 UMUL_LOHI 节点,这是能够直接返回两个运算结果的节点(高低位)。
1.5 MCTargetDesc/Cpu0InstPrinter.cpp/.h
增加mem_ea 的printinst操作的实现。
二、实现结果
2.1 局部指针
int test_local_pointer() {int b = 3;int *p = &b;return *p;
}
addiu $sp, $sp, -8 # 扩栈addiu $2, $zero, 3 # 将3存到寄存器st $2, 4($sp) # 将其存到栈上addiu $2, $sp, 4 # 读出栈中局部变量的地址st $2, 0($sp) # 将这个地址存到栈上ld $2, 0($sp) # 读出这个地址ld $2, 0($2) # 读出地址里的内容addiu $sp, $sp, 8 # 回栈ret $lr # 返回
2.2 char类型
struct Date
{short year;char month;char day;char hour;char minute;char second;
};unsigned char b[4] = {'a', 'b', 'c', '\0'};int test_char()
{unsigned char a = b[1];char c = (char)b[1];struct Date date1 = {2021, (char)2, (char)27, (char)17, (char)22, (char)10};char m = date1.month;char s = date1.second;return 0;
}
addiu $sp, $sp, -24lui $2, %got_hi(b)addu $2, $2, $gpld $2, %got_lo(b)($2) # 与上边搭配加载全局变量b的首地址lbu $3, 1($2) # 计算b[1]的地址,存到寄存器3sb $3, 20($sp) # 将寄存器3内的地址存到栈上lbu $2, 1($2) # 再次计算b[1]的地址,存到寄存器2sb $2, 16($sp) # 将寄存器2内的地址存到栈上ld $2, %got($__const.test_char.date1)($gp)ori $2, $2, %lo($__const.test_char.date1) # 获取要写入局部变量对象的常量的地址lhu $3, 6($2) # 将偏移6处的内容load到寄存器3中,lhu是i16的,就是load范围是2字节lhu $4, 4($2) # 将偏移4处的内容load到寄存器4中,lhu是i16的,就是load范围是2字节shl $4, $4, 16 or $3, $4, $3 # 这两条是将上述load出来的两个2字节的内容拼成一个4字节的st $3, 12($sp) # 将这4字节存到栈上,也就是存放hour, minute, second到 date1lhu $3, 2($2) # 这里是相同的逻辑lhu $2, 0($2)shl $2, $2, 16or $2, $2, $3st $2, 8($sp) # 将这4字节存到栈上,也就是存放year, month, day到 date1lbu $2, 10($sp) # 从偏移10的位置读出date1.month(我们知道year, month, day在偏移8的位置,year两个字节,因此month在偏移10的位置,这里很正确)sb $2, 4($sp) # 将其存到栈上(m)lbu $2, 14($sp) # 从偏移14的位置读出date1.secondsb $2, 0($sp) # 将其存到栈上(s)addiu $2, $zero, 0addiu $sp, $sp, 24ret $lr
2.3 bool类型
bool test_load_bool()
{int a = 1;if (a < 0)return false;return true;
}
这里涉及到跳转我们当前可能编不过,下一节的内容加上之后我们就可以编过了,我们先提前看一下效果。
_Z14test_load_boolv:
# %bb.0:addiu $sp, $sp, -8addiu $2, $zero, 1st $2, 0($sp)ld $2, 0($sp)addiu $3, $zero, -1slt $2, $3, $2bne $2, $zero, $BB0_2nop
# %bb.1:addiu $2, $zero, 0sb $2, 7($sp) # 使用 sb 将 bool 类型的 0 写入栈jmp $BB0_3
$BB0_2:addiu $2, $zero, 1sb $2, 7($sp) # 使用 sb 将 bool 类型的 1 写入栈
$BB0_3:lbu $2, 7($sp)addiu $sp, $sp, 8ret $lr
2.4 short
int test_signed_char()
{char a = 0x80;int i = (signed int)a;i = i + 2; // i = (-128 + 2) = -126return i;
}int test_unsigned_char()
{unsigned char c = 0x80;unsigned int ui = (unsigned int)c;ui = ui + 2; // ui = (128 + 2) = 130return (int)ui;
}int test_signed_short()
{short a = 0x8000;int i = (signed int)a;i = i + 2; // i = (-32768 + 2) = -32766return i;
}int test_unsigned_short()
{unsigned short c = 0x8000;unsigned int ui = (unsigned int)c;ui = ui + 2; // ui = (32768 + 2) = 32770return (int)ui;
}
st_signed_short
...addiu $sp, $sp, -8ori $2, $zero, 32768sh $2, 4($sp)lh $2, 4($sp)st $2, 0($sp)ld $2, 0($sp)addiu $2, $2, 2st $2, 0($sp)ld $2, 0($sp)addiu $sp, $sp, 8ret $lr
...
test_unsigned_short:
...addiu $sp, $sp, -8ori $2, $zero, 32768sh $2, 4($sp)lhu $2, 4($sp)st $2, 0($sp)ld $2, 0($sp)addiu $2, $2, 2st $2, 0($sp)ld $2, 0($sp)addiu $sp, $sp, 8ret $lr
...
汇编还是很好理解的,这里就不进行详细的分析了。
2.5 long long 类型
long long test_longlong()
{long long a = 0x300000002;long long b = 0x100000001;int a1 = 0x30010000;int b1 = 0x20010000;long long c = a + b; // c = 0x00000004,00000003long long d = a - b; // d = 0x00000002,00000001long long e = a * b; // e = 0x00000005,00000002long long f = (long long)a1 * (long long)b1; // f = 0x00060050,01000000return (c+d+e+f); // (0x0006005b,01000006) = (393307,16777222)
}
addiu $sp, $sp, -56addiu $2, $zero, 2st $2, 52($sp) # a的低位addiu $2, $zero, 3st $2, 48($sp) # a的高位addiu $2, $zero, 1st $2, 44($sp) # b的低位st $2, 40($sp) # b的高位lui $2, 12289st $2, 36($sp) # a1lui $2, 8193st $2, 32($sp) # b1ld $2, 52($sp) # a的低位ld $3, 48($sp) # a的高位ld $4, 44($sp) # b的低位ld $5, 40($sp) # b的高位addu $3, $3, $5 # 高位相加addu $4, $2, $4 # 低位相加sltu $2, $4, $2 # 判断低位加法是否有进位addu $2, $3, $2 # 将进位与高位结果相加st $4, 28($sp) # 下同st $2, 24($sp)ld $2, 48($sp)ld $3, 52($sp)ld $4, 40($sp)ld $5, 44($sp)sltu $6, $3, $5subu $2, $2, $4subu $2, $2, $6subu $3, $3, $5st $3, 20($sp)st $2, 16($sp)ld $2, 48($sp)ld $3, 52($sp)ld $4, 44($sp)ld $5, 40($sp)mul $5, $3, $5multu $3, $4mflo $3mfhi $6addu $5, $6, $5mul $2, $2, $4addu $2, $5, $2st $3, 12($sp)st $2, 8($sp)ld $2, 36($sp)ld $3, 32($sp)mult $2, $3mflo $2mfhi $3st $2, 4($sp)st $3, 0($sp)ld $2, 28($sp)ld $3, 24($sp)ld $4, 20($sp)ld $5, 16($sp)addu $3, $3, $5addu $4, $2, $4sltu $2, $4, $2addu $2, $3, $2ld $3, 8($sp)ld $5, 12($sp)addu $5, $4, $5sltu $4, $5, $4addu $2, $2, $3addu $2, $2, $4ld $3, 4($sp)ld $4, 0($sp)addu $2, $2, $4addu $3, $5, $3sltu $4, $3, $5addu $2, $2, $4addiu $sp, $sp, 56ret $lr
2.6 局部数组、结构体
与2.2中的局部结构体类似。
2.7 全局数组、结构体
struct Date
{int year;int month;int day;
};struct Date date = {2021, 2, 27};
int a[3] = {2021, 2, 27};int test_struct()
{int day = date.day;int i = a[1];return (i+day); // 2 + 27 = 29
}
addiu $sp, $sp, -8lui $2, %got_hi(date)addu $2, $2, $gpld $2, %got_lo(date)($2) # 从got表中取全局变量date的地址ld $2, 8($2) # 从偏移8的地方load出date.day,(year和month各占4字节)st $2, 4($sp) # 存到栈中(day)lui $2, %got_hi(a) # 下同addu $2, $2, $gpld $2, %got_lo(a)($2)ld $2, 4($2)st $2, 0($sp)ld $2, 0($sp)ld $3, 4($sp)addu $2, $2, $3addiu $sp, $sp, 8ret $lr
2.8 向量
typedef long vector8long __attribute__((__vector_size__(32)));
typedef long vector8short __attribute__((__vector_size__(16)));int test_cmplt_short()
{volatile vector8short a0 = {0, 1, 2, 3};volatile vector8short b0 = {2, 2, 2, 2};volatile vector8short c0;c0 = a0 < b0;return (int)(c0[0] + c0[1] + c0[2] + c0[3]);
}int test_cmplt_long()
{volatile vector8long a0 = {2, 2, 2, 2, 1, 1, 1, 1};volatile vector8long b0 = {1, 1, 1, 1, 2, 2, 2, 2};volatile vector8long c0;c0 = a0 < b0;return (c0[0] + c0[1] + c0[2] + c0[3] + c0[4] + c0[5] + c0[6] + c0[7]);
}
下述是test_cmplt_short函数的汇编,我们看个稍微短一点的:
addiu $sp, $sp, -64st $10, 60($sp) # 4-byte Folded Spillst $9, 56($sp) # 4-byte Folded Spilladdiu $2, $zero, 3st $2, 44($sp)addiu $3, $zero, 2st $3, 40($sp)addiu $2, $zero, 1st $2, 36($sp)addiu $2, $zero, 0st $2, 32($sp)st $3, 28($sp)st $3, 24($sp)st $3, 20($sp)st $3, 16($sp)ld $3, 44($sp)ld $4, 40($sp)ld $5, 36($sp)ld $6, 32($sp)ld $7, 28($sp)ld $8, 24($sp)ld $9, 20($sp)ld $10, 16($sp)slt $6, $6, $10subu $6, $2, $6slt $5, $5, $9subu $5, $2, $5slt $4, $4, $8subu $4, $2, $4slt $3, $3, $7subu $2, $2, $3st $2, 12($sp)st $4, 8($sp)st $5, 4($sp)st $6, 0($sp)ld $2, 12($sp)ld $2, 8($sp)ld $2, 4($sp)ld $2, 0($sp)ld $3, 12($sp)ld $3, 8($sp)ld $3, 0($sp)ld $3, 4($sp)addu $2, $2, $3ld $3, 12($sp)ld $3, 4($sp)ld $3, 0($sp)ld $3, 8($sp)addu $2, $2, $3ld $3, 8($sp)ld $3, 4($sp)ld $3, 0($sp)ld $3, 12($sp)addu $2, $2, $3ld $9, 56($sp) # 4-byte Folded Reloadld $10, 60($sp) # 4-byte Folded Reloadaddiu $sp, $sp, 64ret $lr
其实整体逻辑是很简单的。
2.9 cl指令
int countLeadingZero() {int a, b;b = __builtin_clz(a);return b;
}int countLeadingOne() {int a, b;b = __builtin_clz(~a);return b;
}
countLeadingZero:addiu $sp, $sp, -8ld $2, 4($sp)clz $2, $2st $2, 0($sp)ld $2, 0($sp)addiu $sp, $sp, 8ret $lrcountLeadingOne:addiu $sp, $sp, -8ld $2, 4($sp)clo $2, $2st $2, 0($sp)ld $2, 0($sp)addiu $sp, $sp, 8ret $lr
相关文章:
LLVM Cpu0 新后端6
想好好熟悉一下llvm开发一个新后端都要干什么,于是参考了老师的系列文章: LLVM 后端实践笔记 代码在这里(还没来得及准备,先用网盘暂存一下): 链接: https://pan.baidu.com/s/1yLAtXs9XwtyEzYSlDCSlqw?…...

GAT1399协议分析(9)--图像上传
一、官方定义 二、wirechark实例 有前面查询的基础,这个接口相对简单很多。 请求: 文本化: POST /VIID/Images HTTP/1.1 Host: 10.0.201.56:31400 User-Agent: python-requests/2.32.3 Accept-Encoding: gzip, deflate Accept: */* Connection: keep-alive content-type:…...
Spring ApplicationContext的getBean方法
Spring ApplicationContext的getBean方法 在Spring框架的ApplicationContext中,getBean(Class<T> requiredType)方法可以接受一个类类型参数,这个参数可以是接口类也可以是实现类。 使用接口类: 如果requiredType是一个接口,…...
自然语言处理(NLP)—— 自动摘要
自动摘要是一种将长文本信息浓缩为短文本的技术,旨在保留原文的主要信息和意义。 1 自动摘要的第一种方法 它的第一种方法是基于理解的,受认知科学和人工智能的启发。 在这个方法中,我们首先建立文本的语义表示,这可以理解为文本…...
Spring RestClient报错:400 Bad Request : [no body]
我项目采用微服务架构,所以各服务之间通过Spring RestClient远程调用,本来一直工作得好好的,昨天突然发现远程调用一直报错,错误详情如下: org.springframework.web.client.HttpClientErrorException$BadRequest: 400…...

【数据结构】 -- 堆 (堆排序)(TOP-K问题)
引入 要学习堆,首先要先简单的了解一下二叉树,二叉树是一种常见的树形数据结构,每个节点最多有两个子节点,通常称为左子节点和右子节点。它具有以下特点: 根节点(Root):树的顶部节…...
C#面:XML与 HTML 的主要区别是什么
C# XML与HTML有以下几个主要区别: 用途不同:XML(eXtensible Markup Language)是一种用于存储和传输数据的标记语言,它的主要目的是描述数据的结构和内容。HTML(HyperText Markup Language)是一…...
java并发-如何保证线程按照顺序执行?
【readme】 使用只有单个线程的线程池(最简单)Thread.join() 可重入锁 ReentrantLock Condition 条件变量(多个) ; 原理如下: 任务1执行前在锁1上阻塞;执行完成后在锁2上唤醒;任务…...

PyCharm中 Fitten Code插件的使用说明一
一. 简介 Fitten Code插件是是一款由非十大模型驱动的 AI 编程助手,它可以自动生成代码,提升开发效率,帮您调试 Bug,节省您的时间,另外还可以对话聊天,解决您编程碰到的问题。 前一篇文章学习了 PyCharm…...

Polar Web【简单】PHP反序列化初试
Polar Web【简单】PHP反序列化初试 Contents Polar Web【简单】PHP反序列化初试思路EXP手动脚本PythonGo 运行&总结 思路 启动环境,显示下图中的PHP代码,于是展开分析: 首先发现Easy类中有魔术函数 __wakeup() ,实现的是对成员…...

树莓派4B 零起点(二) 树莓派 更换软件源和软件仓库
目录 一、准备工作,查看自己的树莓派版本 二、安装HTTPS支持 三、更换为清华源 1、更换Debian软件源 2,更换Raspberrypi软件仓库 四、进行软件更新 接前章,我们的树莓派已经启动起来了,接下来要干的事那就是更换软件源和软件…...

Pytorch 实现目标检测二(Pytorch 24)
一 实例操作目标检测 下面通过一个具体的例子来说明锚框标签。我们已经为加载图像中的狗和猫定义了真实边界框,其中第一个 元素是类别(0代表狗,1代表猫),其余四个元素是左上角和右下角的(x, y)轴坐标(范围…...
如何使用Python中的列表解析(list comprehension)进行高效列表操作
Python中的列表解析(list comprehension)是一种创建列表的简洁方法,它可以在单行代码中执行复杂的循环和条件逻辑。列表解析提供了一种快速且易于阅读的方式来生成新的列表。 以下是一些使用列表解析进行高效列表操作的示例: 1.…...
java使用websocket遇到的问题
java使用websocket的bug 1 websocket连接正常但是收不到服务端发出的消息java的websocket并发的时候导致连接断开(看着连接是正常的,但是实际上已经断开) 1 websocket连接正常但是收不到服务端发出的消息 java的websocket并发的时候导致连接断…...

[Cloud Networking] Layer 2
文章目录 1. 什么是Mac Address?2. 如何查找MAC地址?3. 二层数据交换4. [Layer 2 Protocol](https://blog.csdn.net/settingsun1225/article/details/139552315) 1. 什么是Mac Address? MAC 地址是计算机的唯一48位硬件编码,嵌入到网卡中。 MAC地址也…...
[240609] qwen2 发布,在 Ollama 已可用 | 采用语言模型构建通用 AGI(2020年8月)
目录 qwen2 发布,在 Ollama 已可用Qwen2 模型概览 (基于 Ollama 网站信息)一、模型介绍二、模型参数三、支持语言 (除英语和中文外)四、模型性能五、许可证六、数据支撑: 采用语言模型构建通用 AGI qwen2 发布,在 Ollama 已可用 Qwen2 模型概览 (基于 O…...
赶紧收藏!2024 年最常见 20道分布式、微服务面试题(五)
上一篇地址:赶紧收藏!2024 年最常见 20道分布式、微服务面试题(四)-CSDN博客 九、在分布式系统中,如何保证数据一致性? 在分布式系统中保证数据一致性是一个复杂的问题,因为分布式系统由多个独…...

为什么Kubernetes(K8S)弃用Docker:深度解析与未来展望
为什么Kubernetes弃用Docker:深度解析与未来展望 🚀 为什么Kubernetes弃用Docker:深度解析与未来展望摘要引言正文内容(详细介绍)什么是 Kubernetes?什么是 Docker?Kubernetes 和 Docker 的关系…...

软件游戏提示msvcp120.dll丢失的解决方法,总结多种靠谱的解决方法
在电脑使用过程中,我们可能会遇到一些错误提示,其中之一就是“找不到msvcp120.dll”。那么,msvcp120.dll是什么?它对电脑有什么影响?有哪些解决方法?本文将从以下几个方面进行探讨。 一,了解msv…...

使用kafka tools工具连接带有用户名密码的kafka
使用kafka tools工具连接带有用户名密码的kafka 创建kafka连接,配置zookeeper 在Security选择Type类型为SASL Plaintext 在Advanced页面添加如下图红框框住的内容 在JAAS_Config加上如下配置 需要加的配置: org.apache.kafka.common.security.plain.Pla…...
【Linux】shell脚本忽略错误继续执行
在 shell 脚本中,可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行,可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令,并忽略错误 rm somefile…...
【Linux】C语言执行shell指令
在C语言中执行Shell指令 在C语言中,有几种方法可以执行Shell指令: 1. 使用system()函数 这是最简单的方法,包含在stdlib.h头文件中: #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...
蓝桥杯 2024 15届国赛 A组 儿童节快乐
P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡,轻快的音乐在耳边持续回荡,小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下,六一来了。 今天是六一儿童节,小蓝老师为了让大家在节…...
JVM垃圾回收机制全解析
Java虚拟机(JVM)中的垃圾收集器(Garbage Collector,简称GC)是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象,从而释放内存空间,避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...

【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)
骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术,它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton):由层级结构的骨头组成,类似于人体骨骼蒙皮 (Mesh Skinning):将模型网格顶点绑定到骨骼上,使骨骼移动…...

多模态大语言模型arxiv论文略读(108)
CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题:CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者:Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...

C# 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...

以光量子为例,详解量子获取方式
光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学(silicon photonics)的光波导(optical waveguide)芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中,光既是波又是粒子。光子本…...
C++.OpenGL (20/64)混合(Blending)
混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...
tomcat入门
1 tomcat 是什么 apache开发的web服务器可以为java web程序提供运行环境tomcat是一款高效,稳定,易于使用的web服务器tomcathttp服务器Servlet服务器 2 tomcat 目录介绍 -bin #存放tomcat的脚本 -conf #存放tomcat的配置文件 ---catalina.policy #to…...