【问题标题】:Using FPC .o files in Delphi 2010在 Delphi 2010 中使用 FPC .o 文件
【发布时间】:2018-02-09 21:22:28
【问题描述】:

我为 Delphi 和 FPC 编写了相当大的矩阵运算库。 现在有一个用于英特尔 AVX 扩展的库的扩展,但是 我只能设法在 FPC 中编译。我的想法是创造 FPC 中的 .o 文件,其中包含 AVX 汇编代码并包括这些 Delphi 中的文件。我试图在这里关注这个问题: Linking FPC .o files into Delphi

但没有成功。我能够转储函数名称并尝试导入 这些在 Delphi 单元中。问题是我总是得到一个错误说 .o 文件格式错误。

我使用 CodeTyphoon 进行编译,内部使用 FPC 3.1.1 和 Delphi2010 作为第一次尝试。

代码在 FPC 中编译一次,在 Delphi 中使用适当的 ifdefs。

我的基本代码如下所示(只是摘录):

// ###################################################################
// #### This file is part of the mathematics library project, and is
// #### offered under the licence agreement described on
// #### http://www.mrsoft.org/
// ####
// #### Copyright:(c) 2011, Michael R. . All rights reserved.
// ####
// #### Unless required by applicable law or agreed to in writing, software
// #### distributed under the License is distributed on an "AS IS" BASIS,
// #### WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// #### See the License for the specific language governing permissions and
// #### limitations under the License.
// ###################################################################


unit AVXMatrixMultOperations;

interface

{$IFDEF CPUX64}
{$DEFINE x64}
{$ENDIF}
{$IFDEF cpux86_64}
{$DEFINE x64}
{$ENDIF}
{$IFNDEF x64}

uses MatrixConst;

{$IFNDEF FPC}
// this fails -> wrong object format
{$L '.\AVXPrecompiled\win32\AVXMatrixMultOperations.o'}
{$ENDIF}

// full matrix operations
procedure AVXMatrixMultAligned(dest : PDouble; const destLineWidth : TASMNativeInt; mt1, mt2 : PDouble; width1, height1, width2, height2 : TASMNativeInt; const LineWidth1, LineWidth2 : TASMNativeInt);
{$IFNDEF FPC} external '' name 'AVXMATRIXMULTOPERATIONS_$$_AVXMATRIXMULTALIGNED$crc2A67AB04'; {$ENDIF}

{$ENDIF}

implementation

{$IFDEF FPC} {$ASMMODE intel} {$ENDIF}

{$IFNDEF x64}

{$IFDEF FPC}

procedure AVXMatrixMultAligned(dest : PDouble; const destLineWidth : TASMNativeInt; mt1, mt2 : PDouble; width1, height1, width2, height2 : TASMNativeInt; const LineWidth1, LineWidth2 : TASMNativeInt);
var bytesWidth2, destOffset : TASMNativeInt;
    iter : TASMNativeInt;
{$IFDEF FPC}
begin
{$ENDIF}
asm
   // prolog - simulate stack
   push ebx;
   push edi;
   push esi;

   mov ecx, dest;

   mov edi, width1;
   imul edi, -8;
   mov iter, edi;

   sub mt1, edi;

   //destOffset := destLineWidth - Width2*sizeof(double);
   mov ebx, Width2;
   shl ebx, 3;
   mov eax, destLineWidth;
   sub eax, ebx;
   mov destOffset, eax;

   //bytesWidth2 := width2*sizeof(double);
   mov bytesWidth2, ebx;

   // for y := 0 to height1 - 1 do
   @@foryloop:

      // r12 -> counter to width2
      mov esi, width2;
      sub esi, 2;
      jl @LastXColumn;

      @@forxloop:
      // for x := 0 to width2 div 2 - 1
          // esi: mt1 - width1*sizeof(double)
          // mt2: mt2
          mov edx, mt1;
          mov ebx, mt2;
          mov eax, iter;
          mov edi, LineWidth2;

          vxorpd ymm0, ymm0, ymm0;
          vxorpd ymm1, ymm1, ymm1;

          cmp eax, -32;
          jg @@Innerloop2Begin;

          // for z := 0 to width1 - 1do
          // AVX part:
          @@InnerLoop1:
             // 4x4 block
             vmovapd xmm2, [ebx];
             add ebx, edi;
             vmovapd xmm4, xmm2;

             vmovapd xmm3, [ebx];
             add ebx, edi;

             // shuffle so we can multiply

             // swap such that we can immediately multiply
             vmovlhps xmm2, xmm2, xmm3;
             vmovhlps xmm3, xmm3, xmm4;

             // next 4 elements
             vmovapd xmm4, [ebx];
             add ebx, edi;
             vmovapd xmm6, xmm4;

             vmovapd xmm5, [ebx];
             add ebx, edi;

             vmovapd ymm7, [edx + eax]

             vmovlhps xmm4, xmm4, xmm5;
             vmovhlps xmm5, xmm5, xmm6;

             vinsertf128 ymm2, ymm2, xmm4, 1;
             vinsertf128 ymm3, ymm3, xmm5, 1;

             // now multiply and add
             vmulpd ymm2, ymm2, ymm7;
             vmulpd ymm3, ymm3, ymm7;

             vaddpd ymm0, ymm0, ymm2;
             vaddpd ymm1, ymm1, ymm3;
          add eax, 32;
          jl @@InnerLoop1;

          vextractf128 xmm2, ymm0, 1;
          vextractf128 xmm3, ymm1, 1;

          vhaddpd xmm0, xmm0, xmm2;
          vhaddpd xmm1, xmm1, xmm3;

          test eax, eax;
          jz @@InnerLoopEnd2;

          @@Innerloop2Begin:

          // rest in single elements
          @@InnerLoop2:
             vmovapd xmm2, [ebx];
             add ebx, edi;

             vmovddup xmm3, [edx + eax];

             vmulpd xmm2, xmm2, xmm3;
             vmovhlps xmm4, xmm4, xmm2;

             vaddsd xmm0, xmm0, xmm2;
             vaddsd xmm1, xmm1, xmm4;
          add eax, 8;
          jnz @@InnerLoop2;

          @@InnerLoopEnd2:

          // finall horizontal addition
          vhaddpd xmm0, xmm0, xmm1;

          vmovapd [ecx], xmm0;

          // increment the pointers
          // inc(mt2), inc(dest);
          //add dword ptr [mt2], 8;
          add mt2, 16;
          add ecx, 16;

      // end for x := 0 to width2 div 2 - 1
      sub esi, 2;
      jge @@forxloop;

      @LastXColumn:

      cmp esi, -1;
      jne @NextLine;

      // last column of mt2
      mov eax, iter;
      mov ebx, mt2;

      vxorpd xmm0, xmm0, xmm0;

      @InnerLoop2:
         vmovsd xmm1, [edx + eax];
         vmovsd xmm2, [ebx];

         vmulsd xmm1, xmm1, xmm2;
         vaddsd xmm0, xmm0, xmm1;

         add ebx, edi;
      add eax, 8;
      jnz @InnerLoop2;

      vmovsd [ecx], xmm0;
      add ecx, 8;
      add mt2, 8;

      @NextLine:
      // dec(mt2, Width2);
      // inc(PByte(mt1), LineWidth1);
      // inc(PByte(dest), destOffset);
      //mov ebx, bytesWidth2;
      //sub dword ptr [mt2], ebx;
      mov eax, bytesWidth2;
      sub mt2, eax;
      mov eax, LineWidth1;
      add mt1, eax;
      add ecx, destOffset;

   // end for y := 0 to height1 - 1
   //dec eax;
   dec height1;
   jnz @@foryloop;

   // epilog
   vzeroupper;

   pop esi;
   pop edi;
   pop ebx;
end;
{$IFDEF FPC}
end;
{$ENDIF}

{$ENDIF}

{$ENDIF}

end.

【问题讨论】:

  • 编译成 DLL 并使用它。我不认为delphi可以处理对象格式。
  • AFAIK,FPC 可以生成 COFF 和 ELF 文件(也许更多)。我猜你应该设置选项 (-Acoff) 以使 FPC 生成 COFF 文件。 AFAIK,Delphi 不会链接到 ELF 文件。请注意,可能这两种格式都可以具有 .o 扩展名。 freepascal.org/docs-html/user/usersu15.html
  • 嗯……你的 FPC 会生成 64 位代码而不是 32 位代码吗?
  • win32/64 版本的 FPC 应该产生 coff,但是 FPC 目标当然应该匹配 delphi 目标,32/64 位。也就是说,它可能链接到的 RTL 标识符,包括与单元初始化相关的内容可能是不同的。如果您没有得到准确的信息,这无济于事。尝试先链接一个空文件?顺便说一句,*nix/Cygwin 的“文件”命令对于快速检查文件的真正类型很有用。避免调试信息,它肯定是不同的。如果需要,请剥离。
  • 我坚信静态包含目标文件以在 delphi 中获取整体 bpl 或 exe 文件的想法 - 所以我将尝试在 fpc 设置中显式创建 COFF 文件并完全删除调试设置.

标签: delphi delphi-2010 freepascal


【解决方案1】:

由于这里涉及单个函数,恕我直言,最简单的方法是直接转换 FPC AVXMatrixMultOperations.o 文件。

使用出色的 Object file converter 工具。

您可以尝试将一种二进制格式转换为 Delphi 接受的另一种二进制格式。

但我想最干净的方法是将其转换为 asm:

objconv -fasm AVXMatrixMultOperations.o

它将创建一个AVXMatrixMultOperations.asm 文件,该文件可用于用简单的db ..,..,..,.. 字节替换未知的AVX 指令。通常,生成的.asm 文件的左侧是汇编程序,右侧是原始的十六进制字节。

这就是我在我的库中处理旧的 Delphi 编译器的方式,例如:

function crc32csse42(crc: cardinal; buf: PAnsiChar; len: cardinal): cardinal;
asm // eax=crc, edx=buf, ecx=len
        not     eax
        test    ecx, ecx
        jz      @0
        test    edx, edx
        jz      @0
@3:     test    edx, 3
        jz      @8 // align to 4 bytes boundary
        {$ifdef ISDELPHI2010}
        crc32   eax, byte ptr[edx]
        {$else}
        db      $F2, $0F, $38, $F0, $02
        {$endif}
        inc     edx
        ....

所以在你的情况下,像

{$ifdef FPC}
vinsertf128 ymm2, ymm2, xmm4, 1;
vinsertf128 ymm3, ymm3, xmm5, 1;
{$else}
db $xx,$yy,$zz
db $xx,$yy,$zz
{$endif}

【讨论】:

  • 那么新的会做 AVX(2) 吗?我的西雅图没有,我只是用我的 Delphi 应用程序打包 FPC dll。
  • 正如我所解释的,您可以使用 ObjConvert 工具生成的 .asm 将 AVX(2) 转换为 db $xx,$xx,$xx。它比使用外部 dll 干净得多。
  • 对我来说不是。部署并不是真正的问题,而且数据库的东西在恕我直言更脏。不过,对于特殊情况,我会牢记这一点。
  • 抱歉迟到的评论......感谢您的意见。这实际上是我的第一个想法。问题是大约有 50k 的代码带有 AVX 指令。第一个只是一个例子。我实际上想尝试 fpc 对象链接的事情,因为如果有变化,这也更容易处理。
  • 由于 Delphi 肯定无法识别 FPC coff 目标文件,我想我除了 dll 方法之外的最后手段是编写某种自动 AVX 到 dx$xx,$yy,$zz 转换器基于asm 文件。敬请期待...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-11-10
  • 2012-05-16
  • 2011-09-10
  • 2011-04-03
  • 1970-01-01
  • 1970-01-01
  • 2010-12-04
相关资源
最近更新 更多