我正在学习汇编程序很长一段时间,我正在尝试重写一些简单的过程\函数来查看性能优势(如果有的话).我的主要开发工具是Delphi 2007,第一个例子将使用该语言,但它们也可以很容易地翻译成其他语言.
问题表明:
我们给出了一个无符号字节值,其中八位中的每一位代表一行屏幕中的一个像素.每个单个像素可以是实心(1)或透明(0).换句话说,我们在一个字节值中包含8个像素.我想将这些像素解压缩成一个8字节的数组,就像最年轻的像素(位)将落在数组的最低索引之下一样,依此类推.这是一个例子:
One byte value -----------> eight byte array
10011011 -----------------> [1][1][0][1][1][0][0][1]
Array index number -------> 0 1 2 3 4 5 6 7
Run Code Online (Sandbox Code Playgroud)
下面我介绍解决问题的五种方法.接下来,我将展示他们的时间比较以及我如何衡量这些时间.
我的问题包括两部分:
我问您详细的有关方法的答案DecodePixels4a和DecodePixels4b.为什么方法4b有点慢4a?
例如,如果我的代码没有正确对齐,它会慢一些,那么告诉我给定方法中哪些指令可以更好地对齐,以及如何做到这一点不破坏方法.
我想看看这个理论背后的真实例子.请记住,我正在学习汇编,我想从你的答案中获得知识,这使我将来能够编写更好的优化代码.
你能写更快的常规DecodePixels4a吗?如果是,请提供并描述您已采取的优化步骤.通过更快的例程,我的意思是在测试环境中在最短的时间段内运行的例程,在此处提供的所有例程中.
允许使用所有Intel系列处理器以及与之兼容的处理器.
您将在下面找到我编写的例程:
procedure DecodePixels1(EncPixels: Byte; var DecPixels: TDecodedPixels);
var
i3: Integer;
begin
DecPixels[0] := EncPixels and $01;
for i3 := 1 to 7 do
begin
EncPixels := EncPixels shr 1;
DecPixels[i3] := …Run Code Online (Sandbox Code Playgroud) 在汇编代码中编写Delphi过程或函数时,必须保存哪些寄存器并在过程结束时将其恢复为原始值?
从(内联)汇编代码调用另一个Delphi过程或函数时,我还能期望其他函数与寄存器有什么关系?哪些寄存器将恢复为原始值,哪些可能不会?
(显然,同样的答案适用于这两个问题)
我假设Delphi 的默认调用约定.我知道这EAX用于32位返回值.而看着SysUtils.pas的汇编代码,似乎EBX,ESI并EDI推而恢复,但有些则没有.但是,我找不到任何关于此的文档.
根据"在Delphi中使用汇编程序",eax将包含Self.但是,eax如图所示,内容为0.我想知道出了什么问题?
procedure TForm1.FormCreate(Sender: TObject);
var
X, Y: Pointer;
begin
asm
mov X, eax
mov Y, edx
end;
ShowMessage(IntToStr(NativeInt(X)) + ' ; ' + IntToStr(NativeInt(Y)));
end;
Run Code Online (Sandbox Code Playgroud) 有时我会编写很短的汇编函数
function SeniorBit(Value: LongWord): Integer;
asm
OR EAX,EAX
JZ @@Done
BSR EAX,EAX
INC EAX
@@Done:
end;
Run Code Online (Sandbox Code Playgroud)
这似乎是内联的最佳候选人:
function SeniorBit(Value: LongWord): Integer; inline;
Run Code Online (Sandbox Code Playgroud)
但是Delphi编译器不允许它.为什么?
更新:
感谢ldsandon,有一份关于QC的一份有着5.5年历史的公开报告.该报告包含一些提议(如扩展asm指令)以简化编译器的asm内联.我更倾向于在过程/函数级别上引入"裸"指令,该指令向编译器说它不必为过程创建堆栈帧,并且可选地应保留哪些寄存器(在eax,edx和ecx中).
如果使用BASM代码进行高效内联过程的一般任务很困难(并且可能是不必要的),那么一个好主意是为最重要的案例启用内联(如明确声明的寄存器使用的裸函数).
我有这个过程交换Word变量的字节(低/高)(它做与System.Swap函数相同的东西).当编译器优化为OFF时,该过程有效,但当它处于ON状态时,该过程无效.任何人都可以帮我吗?
procedure SwapWord(VAR TwoBytes: word);
asm
Mov EBX, TwoBytes
Mov AX, [EBX]
XCHG AL,AH
Mov [EBX], AX
end;
Run Code Online (Sandbox Code Playgroud) 我正在使用Delphi 2010.是否可以告诉Delphi不为函数生成序言?我正在写一些像这样的纯汇编函数:
procedure SomeAssembly; stdcall;
begin
asm
...
end;
end;
Run Code Online (Sandbox Code Playgroud)
我想告诉Delphi不要为这个函数生成一个序言和结语,比如C++的__declspec(naked)特性.
所以没有人浪费他们的时间,我不需要帮助让这些功能与序幕一起工作; 我已经可以做到了.这只是一个很大的不便,将使维护成为一个巨大的麻烦.我将不得不手动检查编译器生成的序言以查看它们的长度,如果更改,我的程序将崩溃.
我也知道我可以将函数编写为字节数组中的一系列字节,但这比查找Delphi序言的长度更糟糕.
如果我这样做
var
a,b,c:cardinal;
begin
a:=$80000000;
b:=$80000000;
c:=a+b;
end;
Run Code Online (Sandbox Code Playgroud)
c将等于0,因为加法溢出.捕获这个溢出的布尔值的最佳方法是什么?(a+b<a) or (a+b<b)?一个非常好的方法是使用内联汇编程序,但我不是那么多的汇编程序(虽然我猜它会包含类似的内容JO)
题
有没有资源学习如何在Delphi中使用汇编?
背景资料
我已经找到并阅读了一些通用程序集和指令集引用(x86,MMX,SSE等).但我发现很难在Delphi中应用这些信息.一般的事情,如如何获得类属性的价值等.
我希望在优化代码时可以选择使用汇编.
我明白:
我有兴趣学习如何在Delphi中使用汇编,因为:
如何使用Delphi 2007检查盒子是否支持AVX.
我的问题仅限于查询CPU中的支持(假设操作系统正常/带有SP1的Windows 7).
由Chris Lomont 撰写的题为"英特尔®高级矢量扩展简介 "的PDF文档解释了如何执行此操作,并提供了一个示例代码实现,但在c ++中.
它也可以在这个页面上找到.
我试图运行以下,
type
Vector = array [1..4] of Single;
{$CODEALIGN 16}
function add4(const a, b: Vector): Vector; register; assembler;
asm
movaps xmm0, [a]
movaps xmm1, [b]
addps xmm0, xmm1
movaps [@result], xmm0
end;
Run Code Online (Sandbox Code Playgroud)
它提供了对movaps的访问冲突,据我所知,如果内存位置为16对齐,则可以信任movaps.如果movups(不需要对齐),它没有问题.
所以我的问题是,在Delphi XE3中,{$ CODEALIGN}在这种情况下似乎不起作用.
编辑
很奇怪......我尝试了以下几点.
program Project3;
{$APPTYPE CONSOLE}
uses
windows; // if not using windows, no errors at all
type
Vector = array [1..4] of Single;
function add4(const a, b: Vector): Vector;
asm
movaps xmm0, [a]
movaps xmm1, [b]
addps …Run Code Online (Sandbox Code Playgroud)