หากต้องการ x = x*10 + 1
อย่างมีประสิทธิภาพ อาจเหมาะสมที่สุดที่จะใช้
lea eax, [rax + rax*4] ; x*=5
lea eax, [1 + rax*2] ; x = x*2 + 1
LEA แบบ 3 องค์ประกอบมีเวลาแฝงที่สูงกว่า บน CPU รุ่นใหม่ของ Intel เช่น 3 รอบต่อ 1 บนตระกูล Sandybridge ดังนั้น disp32 + index*2
จึงเร็วกว่า disp8 + base + index*1
บนตระกูล SnB กล่าวคือ CPU x86 กระแสหลักส่วนใหญ่ที่เราใส่ใจในการเพิ่มประสิทธิภาพ (ซึ่งส่วนใหญ่ใช้กับ LEA เท่านั้น ไม่ใช่ โหลด/จัดเก็บ เนื่องจาก LEA ทำงานบนหน่วยประมวลผล ALU ไม่ใช่ AGU ใน CPU x86 ที่ทันสมัยที่สุด) CPU ของ AMD มี LEA ที่ช้ากว่าโดยมี 3 องค์ประกอบหรือ scale > 1
(http://agner.org/optimize/)
แต่ NASM และ YASM จะปรับให้เหมาะสมสำหรับขนาดโค้ดโดยใช้ [1 + rax + rax*1]
สำหรับ LEA ลำดับที่ 2 ซึ่งต้องการเพียง disp8 แทนที่จะเป็น disp32 (โหมดการกำหนดแอดเดรสจะมีรีจิสเตอร์พื้นฐานหรือ disp32 เสมอ)
นั่นคือพวกเขาจะแบ่ง reg*2
เป็น base+index
เสมอ เพราะนั่นไม่เคยเลวร้ายไปกว่าขนาดโค้ด
ฉันสามารถบังคับให้ใช้ disp32 ด้วย lea eax, [dword 1 + rax*2]
ได้ แต่นั่นไม่ได้หยุด NASM หรือ YASM จากการแยกโหมดการกำหนดแอดเดรส ดูเหมือนว่าคู่มือของ NASM จะไม่บันทึกวิธีการใช้คำหลัก strict
บนตัวประกอบสเกล และ [1 + strict rax*2]
ไม่ได้ประกอบ มีวิธีใช้ strict
หรือไวยากรณ์อื่นๆ เพื่อบังคับให้มีการเข้ารหัสที่ต้องการของโหมดการกำหนดที่อยู่หรือไม่
nasm -O0
เพื่อปิดใช้งานการเพิ่มประสิทธิภาพไม่ทำงาน เห็นได้ชัดว่ามีเพียงการควบคุมการปรับการแทนที่สาขาแบบหลายรอบเท่านั้น ไม่ใช่การปรับให้เหมาะสม ทั้งหมด ที่ NASM ทำ แน่นอนว่าคุณคงไม่อยากทำเช่นนั้นตั้งแต่แรกสำหรับไฟล์ต้นฉบับทั้งหมด แม้ว่ามันจะได้ผลก็ตาม ฉันยังคงได้รับ
8d 84 00 01 00 00 00 lea eax,[rax+rax*1+0x1]
วิธีแก้ปัญหาเดียวที่ฉันคิดได้คือเข้ารหัสด้วยตนเองด้วย db
นี่ค่อนข้างไม่สะดวก สำหรับบันทึก การเข้ารหัสด้วยตนเองคือ:
db 0x8d, 0x04, 0x45 ; opcode, modrm, SIB for lea eax, [disp32 + rax*2]
dd 1 ; disp32
สเกลแฟคเตอร์ถูกเข้ารหัสด้วยไบต์ SIB สูง 2 บิต ฉันประกอบ lea eax, [dword 1 + rax*4]
เพื่อรับรหัสเครื่องสำหรับรีจิสเตอร์ที่ถูกต้อง เนื่องจากการเพิ่มประสิทธิภาพของ NASM ใช้งานได้กับ *2
เท่านั้น SIB คือ 0x85
และการลดค่าฟิลด์ 2 บิตที่ด้านบนของไบต์จะลดค่าสเกลแฟคเตอร์จาก 4 เป็น 2
แต่คำถามคือ: จะเขียนมันในลักษณะที่อ่านง่ายได้อย่างไร ซึ่งทำให้ง่ายต่อการเปลี่ยนรีจิสเตอร์ และให้ NASM เข้ารหัสโหมดการกำหนดแอดเดรสให้คุณ (ฉันคิดว่ามาโครขนาดยักษ์สามารถทำได้ด้วย การประมวลผลข้อความและการเข้ารหัส db
ด้วยตนเอง แต่นั่นไม่ใช่คำตอบที่ฉันกำลังมองหาจริงๆ ฉันไม่ต้องการสิ่งนี้เพื่ออะไรตอนนี้ ฉันอยากจะรู้ว่า NASM หรือ YASM มีไวยากรณ์เพื่อบังคับสิ่งนี้เป็นส่วนใหญ่)
การเพิ่มประสิทธิภาพอื่น ๆ ที่ฉันทราบเช่น mov rax, 1
การประกอบเป็น 5 ไบต์ mov eax,1
เป็นชัยชนะอย่างแท้จริงบน CPU ทั้งหมด เว้นแต่คุณต้องการคำแนะนำที่ยาวขึ้นเพื่อรับการเติมโดยไม่มี NOP และสามารถปิดใช้งานได้ด้วย mov rax, strict dword 1
เพื่อรับการเข้ารหัสแบบขยายสัญญาณ 7 ไบต์ หรือ strict qword
สำหรับ 10 ไบต์ imm64
แก๊สไม่ได้ทำสิ่งนี้หรือการเพิ่มประสิทธิภาพอื่น ๆ ส่วนใหญ่ (เฉพาะขนาดของการแทนที่ทันทีและการกระจัดสาขา): lea 1(,%rax,2), %eax
ประกอบเป็น8d 04 45 01 00 00 00 lea eax,[rax*2+0x1]
และเหมือนกันสำหรับเวอร์ชัน .intel_syntax noprefix
คำตอบสำหรับ MASM หรือผู้ประกอบรายอื่นก็น่าสนใจเช่นกัน