จะมีผลต่อการสร้างรหัส Delphi XEx สำหรับเป้าหมาย Android / ARM อย่างไร


266

อัพเดท 2017-05-17 ฉันไม่ทำงานให้กับ บริษัท ที่มีคำถามนี้มาแล้วและไม่สามารถเข้าถึง Delphi XEx ได้ ในขณะที่ฉันอยู่ที่นั่นปัญหาได้รับการแก้ไขโดยการโยกย้ายไปยัง FPC + GCC (Pascal + C) ผสมกับ NEON อินทรินซินส์สำหรับกิจวัตรบางอย่างที่สร้างความแตกต่าง (แนะนำให้ใช้ FPC + GCC เพราะช่วยให้สามารถใช้เครื่องมือมาตรฐานโดยเฉพาะอย่างยิ่ง Valgrind) หากมีใครสามารถสาธิตด้วยตัวอย่างที่น่าเชื่อถือว่าจริง ๆ แล้วพวกเขาสามารถสร้างรหัส ARM ที่ดีที่สุดจาก Delphi XEx ได้อย่างไรฉันยินดีที่จะตอบ .


คอมไพเลอร์ Delphi ของ Embarcadero ใช้แบ็กเอนด์ LLVM เพื่อสร้างรหัส ARM ดั้งเดิมสำหรับอุปกรณ์ Android ฉันมีรหัส Pascal จำนวนมากที่ฉันต้องรวบรวมในแอปพลิเคชัน Android และฉันต้องการทราบวิธีการทำให้ Delphi สร้างรหัสที่มีประสิทธิภาพมากขึ้น ตอนนี้ฉันไม่ได้พูดถึงคุณสมบัติขั้นสูงเช่นการเพิ่มประสิทธิภาพ SIMD อัตโนมัติเพียงแค่การสร้างรหัสที่สมเหตุสมผล แน่นอนว่าจะต้องมีวิธีการส่งผ่านพารามิเตอร์ไปยังด้าน LLVM หรือส่งผลต่อผลลัพธ์อย่างไร โดยทั่วไปคอมไพเลอร์ใด ๆ จะมีตัวเลือกมากมายที่จะส่งผลกระทบต่อการคอมไพล์และการปรับให้เหมาะสม แต่เป้าหมาย ARM ของ Delphi ดูเหมือนจะเป็นเพียง "การเพิ่มประสิทธิภาพเปิด / ปิด" และนั่นก็คือ

LLVM น่าจะมีความสามารถในการสร้างรหัสที่สมเหตุสมผลและสมเหตุสมผล แต่ดูเหมือนว่า Delphi กำลังใช้สิ่งอำนวยความสะดวกในลักษณะแปลก ๆ Delphi ต้องการใช้สแต็คอย่างหนักมากและโดยทั่วไปจะใช้การลงทะเบียนของโปรเซสเซอร์ r0-r3 เป็นตัวแปรชั่วคราวเท่านั้น บางทีสิ่งที่น่าประหลาดใจที่สุดก็คือดูเหมือนว่าจะโหลดจำนวนเต็ม 32 บิตปกติเป็นการดำเนินการโหลด 1 ไบต์สี่ครั้ง จะทำให้ Delphi ผลิตโค้ด ARM ที่ดีขึ้นได้อย่างไรและโดยไม่ต้องยุ่งยากกับไบต์ต่อไบต์ที่สร้างขึ้นสำหรับ Android

ตอนแรกฉันคิดว่าการโหลดไบต์เป็นไบต์สำหรับการแลกเปลี่ยนไบต์จาก big-endian แต่นั่นไม่ใช่กรณีจริง ๆ เพียงแค่โหลดเลข 32 บิตพร้อมโหลดแบบไบต์เดียว 4 ตัว * อาจเป็นการโหลด เต็ม 32 บิตโดยไม่ต้องโหลดหน่วยความจำขนาดเท่าคำที่ไม่ได้จัดแนว (ไม่ว่าจะเป็นควรหลีกเลี่ยงนั่นเป็นอีกสิ่งหนึ่งซึ่งจะบ่งบอกถึงสิ่งทั้งหมดที่เป็นข้อบกพร่องของคอมไพเลอร์) *

ลองดูฟังก์ชั่นง่าย ๆ นี้:

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

แม้ว่าจะเปิดใช้งานการปรับให้เหมาะสม Delphi XE7 พร้อมด้วยชุดการอัปเดต 1 เช่นเดียวกับ 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 และสร้างจำนวนเต็ม 32 บิตจาก 4 ไบต์เดียวโหลด ... ถ้าฉันเปลี่ยนฟังก์ชั่นเล็กน้อยและใช้พารามิเตอร์ 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 และพวกเขาเกือบจะ แต่ไม่เหมือนกับรุ่นพารามิเตอร์ var Android แก้ไข: เพื่อให้ชัดเจนยิ่งขึ้นการโหลดแบบไบต์ต่อไบต์มีเฉพาะใน Android และสำหรับ Android เท่านั้นเวอร์ชันของตัวชี้และพารามิเตอร์ var แตกต่างจากกัน บน iOS ทั้งสองรุ่นจะสร้างรหัสเดียวกันทั้งหมด

สำหรับการเปรียบเทียบนี่เป็นสิ่งที่ FPC 2.7.1 (เวอร์ชั่น trunk SVN จากมีนาคม 2014) คิดว่าของฟังก์ชั่นที่มีระดับการเพิ่มประสิทธิภาพ -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

ฉันยังทดสอบฟังก์ชั่น C ที่เทียบเท่ากับคอมไพเลอร์ C ที่มาพร้อมกับ Android NDK

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
Btw ในการอภิปราย Google+เกี่ยวกับเรื่องนี้แซมชอว์ตั้งข้อสังเกตว่า C ++ แสดงรหัสแบบยาวในการแก้ไขข้อบกพร่องและรหัสที่ได้รับการปรับปรุง Wheres Delphi ทำได้ทั้งสองอย่าง จากนั้นมันอาจจะเป็นข้อผิดพลาดง่ายๆในการตั้งค่าสถานะที่พวกเขากำลังส่ง LLVM และถ้าเป็นเช่นนั้นรายงานข้อผิดพลาดเป็นมูลค่าการยื่นมันอาจจะได้รับการแก้ไขในไม่ช้า
David

9
โอ้ฉันเข้าใจผิด จากนั้นตามที่ Notlikethat กล่าวว่าดูเหมือนว่าโหลดพอยน์เตอร์จะไม่อยู่ในแนว (หรือไม่สามารถรับประกันการจัดตำแหน่ง) และแพลตฟอร์ม ARM ที่เก่ากว่าไม่สามารถทำการโหลดที่ไม่ได้จัดแนวได้ ตรวจสอบให้แน่ใจว่าคุณได้สร้างการกำหนดเป้าหมายarmeabi-v7aแทนarmeabi(ไม่แน่ใจว่ามีตัวเลือกดังกล่าวในคอมไพเลอร์นี้) ตั้งแต่โหลด unaligned ควรได้รับการสนับสนุนตั้งแต่ ARMv6 (ในขณะที่armeabiถือว่า ARMv5) (ที่แสดงการถอดชิ้นส่วนดูไม่เหมือนมันอ่านค่า bigendian ก็แค่อ่านค่าน้อย endian หนึ่งไบต์ในเวลา.)
mstorsjo

6
ฉันพบRSP-9922ซึ่งดูเหมือนว่าจะเป็นบั๊กเดียวกันนี้
David

6
มีคนถามเกี่ยวกับการปรับให้เหมาะสมระหว่าง XE4 กับ XE5 ในกลุ่มข่าวสาร devsuperpage.com/search/…
Side S. Fresh

6
@ โจฮัน: มันคืออะไรปฏิบัติการ? ฉันรู้สึกว่ามันอบในคอมไพเลอร์ของ Delphi ที่ปฏิบัติการได้ ลองดูและแจ้งให้เราทราบผลลัพธ์
Side S. Fresh

คำตอบ:


8

เรากำลังตรวจสอบปัญหา กล่าวโดยสังเขปมันขึ้นอยู่กับการจัดแนวผิดที่อาจเกิดขึ้น (ถึงขอบเขต 32) ของจำนวนเต็มที่อ้างอิงโดยตัวชี้ ต้องการเวลาเพิ่มอีกนิดเพื่อให้ได้คำตอบทั้งหมด ... และวางแผนที่จะแก้ไขปัญหานี้

Marco Cantùผู้ดูแลเกี่ยวกับDelphi Developers

การอ้างอิงด้วยเหตุใด Delphi zlib และ zip libraries ช้ามากใน 64 บิต? เนื่องจาก Win64 ไลบราลีถูกจัดส่งโดยไม่มีการปรับให้เหมาะสม


ในรายงาน QP: RSP-9922 รหัส ARM ไม่ถูกต้องที่สร้างโดยคอมไพเลอร์, ไม่ใช้คำสั่ง $ O? มาร์โกเพิ่มคำอธิบายต่อไปนี้:

มีหลายปัญหาที่นี่:

  • ตามที่ระบุไว้การตั้งค่าการปรับให้เหมาะสมใช้กับไฟล์หน่วยทั้งหมดเท่านั้น ใส่เพียงแค่เปิดและปิดการเพิ่มประสิทธิภาพในไฟล์เดียวกันจะไม่มีผล
  • นอกจากนี้การเปิดใช้งาน "ข้อมูลการดีบัก" จะเป็นการปิดการเพิ่มประสิทธิภาพ ดังนั้นเมื่อมีการดีบักการเปิดใช้งานการปรับให้เหมาะสมจะไม่มีผลอย่างชัดเจน ดังนั้นมุมมอง CPU ใน IDE จะไม่สามารถแสดงมุมมองที่แยกส่วนของรหัสที่ได้รับการปรับปรุง
  • ประการที่สามการโหลดข้อมูล 64 บิตที่ไม่ได้อยู่ในแนวเดียวกันนั้นไม่ปลอดภัยและทำให้เกิดข้อผิดพลาดดังนั้นการดำเนินการ 4 ไบต์หนึ่งแยกต่างหากที่จำเป็นในสถานการณ์ที่กำหนด

Marco Cantùโพสต์ข้อความว่า "เรากำลังตรวจสอบปัญหา" ในเดือนมกราคม 2015 และรายงานข้อผิดพลาดที่เกี่ยวข้อง RSP-9922 ได้รับการทำเครื่องหมายแก้ไขด้วยความละเอียด "ทำงานตามที่คาดหวัง" ในเดือนมกราคม 2016 และมีการกล่าวถึง "ปัญหาภายในปิดเมื่อ 2 มีนาคม 2015" ฉันไม่เข้าใจคำอธิบายของพวกเขา
Side S. Fresh

1
ฉันเพิ่มความคิดเห็นในการแก้ไขปัญหา
Marco Cantù
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.