android-ndk 설치 - Android / ARM 타겟에서 Delphi XEx 코드 생성에 영향을 미치는 방법은 무엇입니까?




안드로이드 크로스 (2)

우리는이 문제를 조사하고 있습니다. 간단히 말해 포인터에 의해 참조 된 Integer의 잘못된 정렬 (32 경계까지)에 따라 다릅니다. 모든 답변을 얻는 데 더 많은 시간이 필요하며이를 해결할 계획이 필요합니다.

Marco Cantù, Delphi 개발자 토론자

또한 참고 자료 Delphi zlib 및 zip 라이브러리가 64 비트에서 왜 느린 이유는 무엇입니까? Win64 라이브러리는 최적화없이 구축 된 상태로 출하됩니다.

QP 보고서 : RSP-9922 , Marco는 다음 설명을 추가했습니다.

여기에 여러 가지 문제가 있습니다.

  • 표시된 바와 같이 최적화 설정은 개별 기능이 아닌 전체 단위 파일에만 적용됩니다. 간단히 말해, 같은 파일에서 최적화를 켜고 끄면 아무런 효과가 없습니다.
  • 또한 단순히 "디버그 정보"를 사용하도록 설정하면 최적화가 해제됩니다. 따라서 디버깅 할 때 명시 적으로 최적화 기능을 켜면 아무 효과가 없습니다. 따라서 IDE의 CPU 뷰는 최적화 된 코드의 디스 어셈블 된 뷰를 표시 할 수 없습니다.
  • 셋째, 정렬되지 않은 64 비트 데이터를로드하는 것은 안전하지 않으며 오류가 발생하므로 주어진 시나리오에서 별도의 4 바이트 작업이 필요합니다.

업데이트 2017-05-17. 이 질문의 출처가 된 회사에서 더 이상 일하지 않으며 Delphi XEx에 액세스 할 수 없습니다. 내가 거기있는 동안, 차이점을 만든 루틴에 대해 NEON 내장 함수가있는 혼합 FPC + GCC (Pascal + C)로 마이그레이션하면 문제가 해결되었습니다. (Fgr + GCC는 표준 도구, 특히 Valgrind를 사용할 수 있기 때문에 적극 추천합니다.) 누군가가 신뢰할 수있는 예제를 통해 실제로 델파이 XEx에서 최적화 된 ARM 코드를 생성하는 방법을 보여줄 수 있다면 기꺼이 답변을 수락합니다. .

Embarcadero의 Delphi 컴파일러는 LLVM 백엔드를 사용하여 Android 디바이스 용 기본 ARM 코드를 생성합니다. 필자는 안드로이드 애플리케이션으로 컴파일해야하는 파스칼 코드를 대량으로 가지고 있으며 Delphi에서보다 효율적인 코드를 생성하는 방법을 알고 싶습니다. 지금 당장은 자동 SIMD 최적화와 같은 고급 기능에 대해 이야기하는 것이 아니라 합리적인 코드를 작성하는 것입니다. 확실하게 LLVM 측에 매개 변수를 전달하거나 결과에 어떤 영향을 미칠 수있는 방법이 있어야합니까? 일반적으로 모든 컴파일러에는 코드 컴파일 및 최적화에 영향을 미치는 많은 옵션이 있지만 델파이의 ARM 타겟은 단지 "최적화 켜기 / 끄기"로만 보이며 그게 전부입니다.

LLVM은 비교적 타이트하고 합리적인 코드를 생성 할 수 있지만 Delphi는 그 기능을 기묘한 방식으로 사용하고있는 것으로 보입니다. Delphi는 스택을 매우 많이 사용하기를 원하며 일반적으로 프로세서의 레지스터 r0 ~ r3을 임시 변수로만 사용합니다. 아마도 가장 미친 점은 일반 32 비트 정수를 4 개의 1 바이트로드 연산으로로드하는 것 같습니다. Delphi가 더 나은 ARM 코드를 생성하는 방법, 그리고 안드로이드를위한 byte-by-byte 번거 로움없이?

처음에는 big-endian에서 바이트 순서를 바꿔 넣기위한 byte-by-byte 로딩이 있다고 생각했지만 실제로 그렇지 않았습니다. 단지 4 바이트의 단일 바이트로드로 32 비트 숫자를로드하는 것입니다. *로드하는 것일 수도 있습니다. 정렬되지 않은 워드 크기 메모리로드를 수행하지 않고 전체 32 비트를 처리합니다. (그것은 다른 것을 피하는 것이 좋든, 컴파일러 버그가된다는 것을 암시 할 것입니다.) *

이 간단한 함수를 살펴 보겠습니다.

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

최적화가 설정된 상태에서 XE6뿐 아니라 업데이트 팩 1이 설치된 Delphi XE7에서도 해당 함수에 대해 다음과 같은 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}

델파이가 필요로하는 명령어와 메모리 접근 횟수를 세면됩니다. 그리고 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의 경우 델파이는 포인터와 var 매개 변수 버전에 대해 동일한 코드를 생성하며 Android 변수 매개 변수 버전과 거의 동일하지는 않습니다. 편집 : 분명히하기 위해 바이트 단위로드는 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

다음 명령으로 emulator.bat를 작성하여 에뮬레이터를 시작할 수 있습니다. 더 빨리 시작할 것입니다.

emulator.exe -cpu-delay 0 -no-boot-anim @<avd name>

Unix (Mac 또는 Linux) :

emulator -cpu-delay 0 -no-boot-anim @<avd name>




android delphi android-ndk arm llvm