Assembly 如何阅读ISA反汇编?还有GPU流水线和等待状态
我试图理解OpenCL编译器为了优化它而产生的机器代码。因此,我使用工具m2s opencl kc(来自multi2sim)离线编译我的*.cl文件,并将中间文件(开关:-a)保留为*.isa文件。这个*.isa包含一个“反汇编”部分,这似乎是我正在寻找的 注意:我的装配知识有点“旧”。我为像奔腾386/486这样的老CPU制作了汇编。所以我在阅读向量指令时遇到了问题,虽然我有一些关于向量指令的理论知识Assembly 如何阅读ISA反汇编?还有GPU流水线和等待状态,assembly,gpu,instruction-set,pipelining,cpu-cycles,Assembly,Gpu,Instruction Set,Pipelining,Cpu Cycles,我试图理解OpenCL编译器为了优化它而产生的机器代码。因此,我使用工具m2s opencl kc(来自multi2sim)离线编译我的*.cl文件,并将中间文件(开关:-a)保留为*.isa文件。这个*.isa包含一个“反汇编”部分,这似乎是我正在寻找的 注意:我的装配知识有点“旧”。我为像奔腾386/486这样的老CPU制作了汇编。所以我在阅读向量指令时遇到了问题,虽然我有一些关于向量指令的理论知识 [... OTHER STUFF ... ] ; -------- Disassembly
[... OTHER STUFF ... ]
; -------- Disassembly --------------------
00 ALU_PUSH_BEFORE: ADDR(32) CNT(6) KCACHE0(CB2:0-15) KCACHE1(CB0:0-15)
0 x: MOV R2.x, 0.0f
z: SETGT_INT R0.z, 1, KC0[0].y
t: MULLO_INT ____, R1.x, KC1[1].x
1 w: ADD_INT ____, R0.x, PS0
2 y: ADD_INT R2.y, PV1.w, KC1[6].x
3 x: PREDE_INT ____, R0.z, 0.0f UPDATE_EXEC_MASK UPDATE_PRED
01 JUMP POP_CNT(1) ADDR(9)
02 ALU: ADDR(38) CNT(5) KCACHE0(CB1:0-15)
4 x: MOV R2.x, 0.0f
y: MOV R3.y, 0.0f
w: LSHL ____, R2.y, 2
5 z: ADD_INT R2.z, KC0[0].x, PV4.w
03 LOOP_DX10 i0 FAIL_JUMP_ADDR(8)
04 ALU: ADDR(43) CNT(11) KCACHE0(CB2:0-15)
6 y: ADD_INT R3.y, R3.y, 1
w: LSHL ____, R3.y, 2
7 x: SETGT_INT R3.x, KC0[0].y, PV6.y
z: ADD_INT ____, R2.z, PV6.w
w: ADD_INT ____, PV6.w, 8
8 x: ASHR R0.x, PV7.w, 4
y: LSHR R0.y, PV7.z, 2
z: BFE_UINT R0.z, PV7.w, 0x00000002, 0x00000002
[... some more ... ]
我想知道的是命令前面的数字和字符的含义。据我所知,编译器生成了一些“复杂”指令,如:
00 ALU_PUSH_BEFORE: ADDR(32) CNT(6) KCACHE0(CB2:0-15) KCACHE1(CB0:0-15)
0 x: MOV R2.x, 0.0f
z: SETGT_INT R0.z, 1, KC0[0].y
t: MULLO_INT ____, R1.x, KC1[1].x
1 w: ADD_INT ____, R0.x, PS0
2 y: ADD_INT R2.y, PV1.w, KC1[6].x
3 x: PREDE_INT ____, R0.z, 0.0f UPDATE_EXEC_MASK UPDATE_PRED
(问题:这是所谓的“超长指令词”吗?)
此“复杂”指令由多个“简单”指令组成,如下所示:
00 ALU_PUSH_BEFORE: ADDR(32) CNT(6) KCACHE0(CB2:0-15) KCACHE1(CB0:0-15)
0 x: MOV R2.x, 0.0f
z: SETGT_INT R0.z, 1, KC0[0].y
t: MULLO_INT ____, R1.x, KC1[1].x
1 w: ADD_INT ____, R0.x, PS0
2 y: ADD_INT R2.y, PV1.w, KC1[6].x
3 x: PREDE_INT ____, R0.z, 0.0f UPDATE_EXEC_MASK UPDATE_PRED
这些“简单”指令似乎是每个向量单元的指令。这四个矢量单位由x、y、z和w引用。但什么是“t”?这是另一个向量单位吗?我为“Cypress”GPU编译了它
现在关于数字。。。这些只是“行号”吗?
前导零:复杂指令序列号。。。?
无前导零:简单指令序列号
我假设所有具有相同串行的“简单”指令都可以在一个周期内“逻辑”执行,前提是我们假设内存访问没有等待状态。例如,(上述复杂指令的)以下指令在周期0中“执行”:
0 x: MOV R2.x, 0.0f
z: SETGT_INT R0.z, 1, KC0[0].y
t: MULLO_INT ____, R1.x, KC1[1].x
我所说的“执行”是指我们有某种(例如4周期)的流水线。这意味着上述指令应该在第0周期开始执行,并且应该在第3周期之后完成
关于管道的问题
如果下一条指令(例如“1”)将读取寄存器R2.x,会发生什么情况?它会读取R2.x的旧值(在指令“0”之前)还是指令“1”会被延迟,直到指令“0”结束?或者这可能是一种“不关心”的情况(产生未定义的结果),编译器必须注意这一点,而这永远不会发生
关于内存访问的问题
我假设可以在数据获取周期中执行对寄存器的访问,而无需等待。内存访问将需要一些额外的周期,具体取决于访问的内存类型:
- “_private”内存应该主要映射到寄存器李>
- __本地内存(在同一组的工作项之间共享高达64KB):在当前GPU中,我需要多少额外的周期
- __全局内存:这应该是256MB到x GB的外部DRAM。在这里我需要额外的循环次数是多少?据我所知,此内存不会缓存到GPU设备
- __常量内存应该类似于_全局内存,但使用_本地内存进行缓存
4 x: MOV R2.x, 0.0f
y: MOV R3.y, 0.0f
w: LSHL ____, R2.y, 2
这是一条使用三个可用ALU的指令,即“x”、“y”和“w”。它还可以使用构成最大并行指令的“z”和“t”,如:
4 x: MOV R2.x, 0.0f
y: MOV R3.y, 0.0f
z: MOV R3.z, 0.0f
w: LSHL ____, R2.y, 2
t: LSHL ____, R2.z, 4
尽管如此,这是一条单独的VLIW指令,它“馈送”着色器核心的所有五个ALU“通道”,然后在一个步骤中并行执行这五个操作
但什么是“t”?这是另一个向量单位吗
是的,“t”是第五个标量单位,称为“超越”,可以用来执行计算,如sin(x)
或cos(x)
。除此之外,它还可以执行普通的标量操作,但它的局限性在于,并非在“x”到“w”中可能执行的所有标量操作也可以在“t”中执行。因此,理想情况下,每个核心可以在一个步骤中执行五个标量操作。值得注意的是,与CPU上的SSE指令不同,这五个单元独立工作:每个单元在每个步骤中都可以执行自己的操作,而在SSE单元中,只有一个操作可以并行应用于多个数据。这基本上构成了SSE和VLIW架构之间的差异
那些
指令显然是特殊的指令,实际上并不在ALU上执行操作,比如从(片外)内存中获取数据,或者控制流指令
要获得内存延迟的估计值,请查看中的附录D-设备参数
\uu常量
内存与\uu本地
内存不同:它在芯片上有自己的内存空间,所有工作项的内存空间都是相同的,根据文档,它的访问速度大约是\uu本地
内存的两倍,因为工作项之间不需要一致逻辑
互联网上的一些来源指出,(AMD)GPU没有缓存,LDS内存应该用于显式模拟缓存。但在某些文档中,有对L1和L2缓存的引用
不管是哪种方式,请注意,当一个线程暂停等待数据时,GPU通过极快地切换执行“上下文”,在“隐藏”内存延迟方面非常出色。如果有足够多的并行任务可供选择,GPU可能总会找到一个准备好执行的任务,可以将其替换为需要等待的任务。您在这里询问的是哪种GPU体系结构?ISA文件适用于AMD“Cypress”GPU。上述代码/所选GPU只是一个示例。请不要试图解释太“柏树”-具体。。。我需要以更一般的方式来理解这些事情。如果事情变得太复杂,无法在一篇简单的帖子中解释,那么一个链接到一个好的解释(例如教程、howto paper)也可以。Cypress,是的,我想我认识到了VLIW结构。您可以在这里下载关于Evergreen ISA的手册:您所询问的整个指令集和体系结构已经完全过时两次。我想说的是