【发布时间】: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