如何影响Android / ARM目标的Delphi XEx代码生成?


266

更新2017-05-17。我不再为产生此问题的公司工作,也无法访问Delphi XEx。在我在那里的时候,通过迁移到混合FPC + GCC(Pascal + C)来解决问题,对于某些例程,NEON内在函数有所作为。(强烈建议使用FPC + GCC,因为它可以使用标准工具,尤其是Valgrind。)如果有人可以通过可靠的示例演示他们实际上如何从Delphi XEx生成优化的ARM代码,我很乐意接受答案。


Embarcadero的Delphi编译器使用LLVM后端为Android设备生成本机ARM代码。我有大量Pascal代码,需要将这些代码编译到Android应用程序中,并且我想知道如何使Delphi生成更有效的代码。现在,我什至没有在谈论诸如自动SIMD优化之类的高级功能,而只是在生成合理的代码。当然必须有一种方法可以将参数传递给LLVM端,否则会影响结果?通常,任何编译器都会有很多选择来影响代码的编译和优化,但是Delphi的ARM目标似乎仅仅是“优化开/关”,仅此而已。

LLVM应该能够生成合理的紧致和明智的代码,但是Delphi似乎在以奇怪的方式使用其功能。Delphi希望非常大量地使用堆栈,并且通常只将处理器的寄存器r0-r3用作临时变量。也许最疯狂的是,它似乎正在将正常的32位整数作为四个1字节的加载操作进行加载。如何使Delphi产生更好的ARM代码,而又没有它为Android带来的逐字节麻烦呢?

起初,我认为逐字节加载是为了交换big-endian的字节顺序,但事实并非如此,它实际上只是加载具有4个单字节加载的32位数字。*可能是加载完整的32位,而不会产生未对齐的字大小的存储器负载。(是否应该避免那是另一回事,这暗示整个事情都是编译器错误)*

让我们看一下这个简单的函数:

function ReadInteger(APInteger : PInteger) : Integer;
begin
  Result := APInteger^;
end;

即使启用了优化,带有更新包1的Delphi XE7以及XE6也会为该功能生成以下ARM汇编代码:

Disassembly of section .text._ZN16Uarmcodetestform11ReadIntegerEPi:

00000000 <_ZN16Uarmcodetestform11ReadIntegerEPi>:
   0:   b580        push    {r7, lr}
   2:   466f        mov r7, sp
   4:   b083        sub sp, #12
   6:   9002        str r0, [sp, #8]
   8:   78c1        ldrb    r1, [r0, #3]
   a:   7882        ldrb    r2, [r0, #2]
   c:   ea42 2101   orr.w   r1, r2, r1, lsl #8
  10:   7842        ldrb    r2, [r0, #1]
  12:   7803        ldrb    r3, [r0, #0]
  14:   ea43 2202   orr.w   r2, r3, r2, lsl #8
  18:   ea42 4101   orr.w   r1, r2, r1, lsl #16
  1c:   9101        str r1, [sp, #4]
  1e:   9000        str r0, [sp, #0]
  20:   4608        mov r0, r1
  22:   b003        add sp, #12
  24:   bd80        pop {r7, pc}

只需计算Delphi为此所需的指令和内存访问数即可。并从4个单字节负载中构造一个32位整数...如果我稍微改变一下函数,并使用var参数代替指针,则它的卷积会稍微减少一些:

Disassembly of section .text._ZN16Uarmcodetestform14ReadIntegerVarERi:

00000000 <_ZN16Uarmcodetestform14ReadIntegerVarERi>:
   0:   b580        push    {r7, lr}
   2:   466f        mov r7, sp
   4:   b083        sub sp, #12
   6:   9002        str r0, [sp, #8]
   8:   6801        ldr r1, [r0, #0]
   a:   9101        str r1, [sp, #4]
   c:   9000        str r0, [sp, #0]
   e:   4608        mov r0, r1
  10:   b003        add sp, #12
  12:   bd80        pop {r7, pc}

我不会在这里包括反汇编,但是对于iOS,Delphi会为指针和var参数版本生成相同的代码,它们几乎但与Android var参数版本完全不同。 编辑:澄清一下,逐字节加载仅在Android上。仅在Android上,指针和var参数的版本彼此不同。在iOS上,两个版本均生成完全相同的代码。

为了进行比较,以下是FPC 2.7.1(2014年3月发布的SVN中继版本)对优化级别为-O2的功能的看法。指针和var参数版本完全相同。

Disassembly of section .text.n_p$armcodetest_$$_readinteger$pinteger$$longint:

00000000 <P$ARMCODETEST_$$_READINTEGER$PINTEGER$$LONGINT>:

   0:   6800        ldr r0, [r0, #0]
   2:   46f7        mov pc, lr

我还使用Android NDK随附的C编译器测试了等效的C函数。

int ReadInteger(int *APInteger)
{
    return *APInteger;
}

并将其编译成与FPC基本上相同的内容:

Disassembly of section .text._Z11ReadIntegerPi:

00000000 <_Z11ReadIntegerPi>:
   0:   6800        ldr r0, [r0, #0]
   2:   4770        bx  lr

14
Google+对此的讨论中,Sam Shaw指出C ++在调试版本中显示了长格式代码,而在发行版本中显示了优化代码。Delphi在这两个地方都做到了。因此,这很可能是发送LLVM的标志中的简单错误,如果是这样,则非常值得提交错误报告,它可能很快就会得到解决。
David

9
哦,好,我读错了。然后,就像Notlikethat所说的那样,听起来好像它假设指针负载将是未对齐的(或不能保证对齐),并且较旧的ARM平台不一定会执行未对齐的负载。确保具有构建目标armeabi-v7a而不是目标目标armeabi(不确定此编译器中是否存在此类选项),因为自ARMv6起,应该支持未对齐的加载(而armeabi假定为ARMv5)。(所示的反汇编看起来好像不是读取bigendian值,而是一次读取一个字节的小endian值。)
mstorsjo 2015年

6
我发现RSP-9922似乎是同一错误。
大卫

6
在embarcadero.public.delphi.platformspecific.ios新闻组中,有人问过XE4和XE5之间的优化被破坏了,“ ARM编译器优化被破坏了吗?” devsuperpage.com/search/…–
S. Fresh

6
@Johan:它是什么可执行文件?我的印象是,它以某种方式嵌入了Delphi的编译器可执行文件中。试试看,让我们知道结果。
Side S. Fresh

Answers:


8

我们正在调查这个问题。简而言之,它取决于指针引用的Integer的潜在未对准(到32边界)。需要更多时间来获得所有答案...以及解决此问题的计划。

MarcoCantù,Delphi开发人员主持人

也参考 为什么Delphi zlib和zip库在64位下如此慢?因为Win64库在出厂时没有进行优化。


在QP报告中: RSP-9922编译器生成的ARM代码错误,$ O指令被忽略?,Marco添加了以下说明:

这里有多个问题:

  • 如图所示,优化设置仅适用于整个单元文件,不适用于单个功能。简而言之,在同一文件中打开和关闭优化将无效。
  • 此外,仅启用“调试信息”即可关闭优化。因此,在调试时,显式打开优化将无效。因此,IDE中的CPU视图将无法显示优化代码的反汇编视图。
  • 第三,加载不对齐的64位数据并不安全,并且会导致错误,因此在给定情况下需要单独的4个1字节操作。

MarcoCantù在2015年1月发布了“我们正在调查此问题”注释,并在2016年1月以“按预期工作”解决了相关的错误报告RSP-9922,并提到了“内部问题已于3月2日关闭” 2015”。我不明白他们的解释。
S. Fresh

1
我在问题解决方案中添加了评论。
MarcoCantù'16
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.