Güncelleme 2017-05-17. Artık bu sorunun ortaya çıktığı şirket için çalışmıyorum ve Delphi XEx'e erişimim yok. Ben oradayken, sorun karışık FPC + GCC'ye (Pascal + C) geçerek, fark yarattığı bazı rutinler için NEON intrinsics ile çözüldü. (FPC + GCC ayrıca standart araçların, özellikle Valgrind'in kullanılmasını sağladığı için şiddetle tavsiye edilir.) Birisi güvenilir örneklerle, Delphi XEx'ten nasıl optimize edilmiş ARM kodu üretebildiklerini gösterebilirse, cevabı kabul etmekten mutluluk duyuyorum .
Embarcadero'nun Delphi derleyicileri, Android cihazlar için yerel ARM kodu üretmek için LLVM arka ucu kullanır. Android uygulamalarına derlemem gereken çok miktarda Pascal kodum var ve Delphi'nin daha verimli kod üretmesini nasıl yapacağımı bilmek istiyorum. Şu anda, otomatik SIMD optimizasyonları gibi gelişmiş özelliklerden bile bahsetmiyorum, sadece makul kod üretmekle ilgili. Elbette, parametreleri LLVM tarafına geçirmenin veya bir şekilde sonucu etkilemenin bir yolu olmalı? Genellikle, herhangi bir derleyici kod derleme ve optimizasyonu etkilemek için birçok seçeneğe sahip olacaktır, ancak Delphi'nin ARM hedefleri sadece "optimizasyon açık / kapalı" gibi görünüyor ve hepsi bu.
LLVM'nin makul derecede sıkı ve mantıklı kod üretebileceği düşünülüyor, ancak Delphi'nin tesislerini garip bir şekilde kullanıyor gibi görünüyor. Delphi, yığını çok yoğun bir şekilde kullanmak istiyor ve genellikle işlemcinin r0-r3 kayıtlarını geçici değişkenler olarak kullanıyor. Belki de en çılgını, dört adet 1 baytlık yükleme işlemi olarak normal 32 bit tamsayıları yüklemek gibi görünüyor. Delphi daha iyi ARM kodu üretmek nasıl yapılır ve byte by-byte güçlük olmadan Android için yapıyor?
İlk başta bayt byte bayt yüklemesinin byte sırasını big-endian'dan değiştirmek olduğunu düşündüm, ancak durum böyle değildi, gerçekten sadece 4 bit baytlık yükler ile 32 bitlik bir sayı yüklemek. * hizasız bir kelime boyutlu bellek yükü yapmadan 32 bitin tamamı. (bundan kaçınması gerekip gerekmediği başka bir şeydir, bu da her şeyin bir derleyici hatası olmasını ima eder) *
Bu basit işleve bakalım:
function ReadInteger(APInteger : PInteger) : Integer;
begin
Result := APInteger^;
end;
Optimizasyonlar açık olsa bile, güncelleme paketi 1'e sahip Delphi XE7 ve XE6, bu işlev için aşağıdaki ARM montaj kodunu üretir:
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}
Sadece Delphi'nin ihtiyaç duyduğu talimatları ve bellek erişimlerini sayın. Ve 4 tek baytlık yüklerden 32 bit tam sayı oluşturmak ... İşlevi biraz değiştirir ve işaretçi yerine var parametresi kullanırsam, biraz daha az kıvrımlıdır:
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}
Sökme işlemini buraya dahil etmeyeceğim, ancak iOS için Delphi, işaretçi ve var parametre sürümleri için aynı kodu üretir ve neredeyse ancak Android var parametre sürümü ile tam olarak aynı değildir. Düzenleme: açıklığa kavuşturmak için, bayt bayt yüklemesi yalnızca Android'de yapılır. Ve sadece Android'de, işaretçi ve var parametre sürümleri birbirinden farklıdır. İOS'ta her iki sürüm de tam olarak aynı kodu oluşturur.
Karşılaştırma için, FPC 2.7.1 (Mart 2014'ten itibaren SVN trunk versiyonu) -O2 optimizasyon seviyesi ile işlevi düşünüyor. İşaretçi ve var parametre sürümleri tamamen aynıdır.
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
Ayrıca Android NDK ile birlikte gelen C derleyicisi ile eşdeğer bir C fonksiyonunu test ettim.
int ReadInteger(int *APInteger)
{
return *APInteger;
}
Ve bu aslında FPC'nin yaptığı aynı şeyi derler:
Disassembly of section .text._Z11ReadIntegerPi:
00000000 <_Z11ReadIntegerPi>:
0: 6800 ldr r0, [r0, #0]
2: 4770 bx lr
armeabi-v7a
bunun yerine hedefleme oluşturduğunuzdan armeabi
emin olun (bu derleyicide bu tür seçeneklerin olup olmadığından emin olun armeabi
). (Gösterilen demontaj, büyük bir değer okuyor gibi görünmüyor, sadece bir kerede bir bayt değeri okuyor.)