从DCT简单了解一种线性汇编优化方法

来源:本站
导读:目前正在解读《从DCT简单了解一种线性汇编优化方法》的相关信息,《从DCT简单了解一种线性汇编优化方法》是由用户自行发布的知识型内容!下面请观看由(电工技术网 - www.9ddd.net)用户发布《从DCT简单了解一种线性汇编优化方法》的详细说明。
简介:从DCT简单了解一种线性汇编优化方法

一直在看这方面的东西,自己也写过代码,但是始终都没有掌握其中的真谛。其实现在也是半懂不懂,然而还是感觉有些灵感了,写起代码也不那么慢了。今天下午就调试了四个代码,前提是这四个函数前几天是看过的:dct4x4dc,idct4x4dc,quant4x4dciquant4x4dc。效果dct变换还是很好的,基本提高了一半的效率,而iquant就没甚么改进,而且quant还不如以前了,原因估计是代码太长,以后还要进一步优化。

今天调的这么快,主要是把2x2的都做好了,那么简单将进行四个循环就可以了,而最后把循环展开,反正c64是有那么多寄存器的,一下就做完这16个,效果当然要比循环四次好的多(而且从水平和垂直两个方面就是八次循环了)。

今天想写下的心得不是对于dct变换本身的,虽然这部分也是很关键的,但今天就说一下优化dct2x2dc的过程。

void

dct2x2dc_c(int16_t* data)

{

int16_t s[4];

s[0] = data[0];

s[1] = data[1];

s[2] = data[2];

s[3] = data[3];

data[0] = s[0] + s[2] + s[1] + s[3];

data[1] = s[0] + s[2] - s[1] - s[3];

data[2] = s[0] - s[2] + s[1] - s[3];

data[3] = s[0] - s[2] - s[1] + s[3];

}

这是T264中的dct2x2dcc代码,其实很简单,dct变换就是矩阵变换,最适合做优化了。单独测试这部分代码的c函数,两个主要参考:总周期2157data cache misses50次。

简单的改为汇编,只要取数做运算就可以了。

.global _dct2x2dc_sa

_dct2x2dc_sa:.cproc data

.no_mdep

.reg data0,data1,data2,data3,data02,data13,data20,data31

.reg s0,s1,s2,s3

LDH *data,s0

LDH *+data[1],s1

LDH *+data[2],s2

LDH *+data[3],s3;分四次把data取出

ADD s0,s2,data02

ADD s1,s3,data13

ADD data02,data13,data0

SUB data02,data13,data1

SUB s0,s2,data20

SUB s1,s3,data31

ADD data20,data31,data2

SUB data20,data31,data3;把公式综合起来进行运算

STH data0,*data

STH data1,*+data[1]

STH data2,*+data[2]

STH data3,*+data[3];存数

.endproc

这样的实现很简单,相关的注释在后面,剖析结果:周期2109data cache misses46次。

改进非常小。这是个中间阶段,测试数据是正确的,就可以进行进一步优化了。很明显,汇编中最费时的就是loadstore。以前就看到数据打包的概念,这次终于理解了。首先,我们知道(主函数中)data的数据是16bit的,而c64的寄存器都是32位,那么我们就可以把每两个数放在一个寄存器中,然后再利用其他相关的操作来进行运算(很明显c64这样的设计就是要我们这样用的)。说起来很不明确,具体的讲就很清楚了。首先,一个LDW在一个地址取一个字,那么就是32bit,就是取了两个dataLDW *data,data10。同时再来一个:LDW *+data[1],data32。很明显就取出了所有的四个datadata0data1分别位于寄存器data10的低16位和高16位,同样data2data3data32中。如果画图就很明白了,这个文字说明:

data10: data1(H)data0(L)

data32: data3(H)data2(L)

而且我们知道c64有两条指令:ADD2SUB2(具体可以参看相关资料),分别是将两个操作数的高16位相加、相减放在dst的高16位,同时低16位相加相减放在低16位。也就是说,如果我们使用这样两条语句:ADD2 data10,data32,data0213SUB2 data10,data32,data2031,那么在data0213data2031中存储为:

data0213: 1+3(H)0+2(H)

data2131: 1-3(H)0-2(H)相当整齐。

之后我们再看c代码,得到的data0data3正是data0213data2031高低共四个元素1+30+21-30-2的组合。当然首先要把他们分离,还没发现c64有指令可以高低位计算的,把这两个寄存器右移16得到了13的两个运算,原始的(data0213data2031)就是02的运算。这样的计算好像是不对的,因为使用的02运算的高16位并不是单纯的,而使用的13运算的高16也是与计算没关系的。这个不用担心,我们的结果就是16位,最后只要考虑低16位就可以了,而且我们最后还有pack的操作,就会把高16位冲掉了。我们计算一个data2作为说明。

观察c代码,data2(0-2)+(1-3),先把0-2移出来:SHR data2031,16,data31;然后再相加即可:ADD data2013,data31,data2。搞定。其他的也是类似了。关于PACK2的运算可以看整个代码就明确了。

LDW *data,data10

LDW *+data[1],data32;整字取数据,这里注意不要因为是按字取就加2,同样LDDW是也是加1

ADD2 data10,data32,data0213

SUB2 data10,data32,data2031;得到四个元素

SHR data0213,16,data13

SHR data2031,16,data31;分离13的运算

ADD data0213,data13,data0

ADD data2031,data31,data2 ;计算data0data2

SUB data0213,data13,data1

SUB data2031,data31,data3 ;计算data1data3

PACK2 data1,data0,data10

PACK2 data3,data2,data32;打包一个是冲掉高16位,一个也是为STW做准备

STW data10,*data

STW data32,*+data[1];按字再存数据,也是提升性能的主要部分。

为简明起见,去掉了线性汇编的头尾以及定义寄存器。最后的剖析结果:周期1955data cache misses42次。再进一步想,如果使用双字取数和存,是不是更会提升呢?

LDDW *data,data32:data10

;中间代码与LDW一致

STDW data32:data10,*data最后的剖析结果:周期1877data cache misses40次。

2x2的情况还看不那么明显,按照这样的方法改了dct4x4dc_c,二者的剖析结果为:

c:4591108

sa:240552(都是上面一样的指标)。

可见,提升了近一半的性能。

其他函数的优化也是相类似的。

目前的理解就这么多了,其他的更深刻慢慢就会知道了。

提醒:《从DCT简单了解一种线性汇编优化方法》最后刷新时间 2024-03-14 01:04:59,本站为公益型个人网站,仅供个人学习和记录信息,不进行任何商业性质的盈利。如果内容、图片资源失效或内容涉及侵权,请反馈至,我们会及时处理。本站只保证内容的可读性,无法保证真实性,《从DCT简单了解一种线性汇编优化方法》该内容的真实性请自行鉴别。