คอมไพลเลอร์จะจัดเก็บสิ่งเหล่านี้ไว้ในรีจิสเตอร์หลายรายการและใช้คำสั่งหลายคำสั่งเพื่อคำนวณค่าเหล่านั้นหากจำเป็น ISAs ส่วนใหญ่มีคำสั่งเสริมพร้อมพกพาเช่นx86adc
ซึ่งทำให้การเพิ่ม / ย่อยจำนวนเต็มความแม่นยำสูงมีประสิทธิภาพพอสมควร
ตัวอย่างเช่นให้
fn main() {
let a = 42u128;
let b = a + 1337;
}
คอมไพเลอร์สร้างสิ่งต่อไปนี้เมื่อคอมไพล์สำหรับ x86-64 โดยไม่มีการปรับให้เหมาะสม:
(ความคิดเห็นที่เพิ่มโดย @PeterCordes)
playground::main:
sub rsp, 56
mov qword ptr [rsp + 32], 0
mov qword ptr [rsp + 24], 42 # store 128-bit 0:42 on the stack
# little-endian = low half at lower address
mov rax, qword ptr [rsp + 24]
mov rcx, qword ptr [rsp + 32] # reload it to registers
add rax, 1337 # add 1337 to the low half
adc rcx, 0 # propagate carry to the high half. 1337u128 >> 64 = 0
setb dl # save carry-out (setb is an alias for setc)
mov rsi, rax
test dl, 1 # check carry-out (to detect overflow)
mov qword ptr [rsp + 16], rax # store the low half result
mov qword ptr [rsp + 8], rsi # store another copy of the low half
mov qword ptr [rsp], rcx # store the high half
# These are temporary copies of the halves; probably the high half at lower address isn't intentional
jne .LBB8_2 # jump if 128-bit add overflowed (to another not-shown block of code after the ret, I think)
mov rax, qword ptr [rsp + 16]
mov qword ptr [rsp + 40], rax # copy low half to RSP+40
mov rcx, qword ptr [rsp]
mov qword ptr [rsp + 48], rcx # copy high half to RSP+48
# This is the actual b, in normal little-endian order, forming a u128 at RSP+40
add rsp, 56
ret # with retval in EAX/RAX = low half result
ซึ่งคุณจะเห็นว่าค่า42
ถูกเก็บไว้ในrax
และrcx
และ
(หมายเหตุของบรรณาธิการ: ข้อตกลงการโทร x86-64 C ส่งคืนจำนวนเต็ม 128 บิตใน RDX: RAX แต่นี่ main
ไม่ส่งคืนค่าเลยการคัดลอกซ้ำซ้อนทั้งหมดมาจากการปิดใช้งานการเพิ่มประสิทธิภาพเท่านั้นและ Rust จะตรวจสอบการล้นในการดีบัก โหมด.)
สำหรับการเปรียบเทียบนี่คือ asm สำหรับ Rust 64-bit จำนวนเต็มบน x86-64 ซึ่งไม่จำเป็นต้องใช้ add-with-carry มีเพียง register เดียวหรือ stack-slot สำหรับแต่ละค่า
playground::main:
sub rsp, 24
mov qword ptr [rsp + 8], 42 # store
mov rax, qword ptr [rsp + 8] # reload
add rax, 1337 # add
setb cl
test cl, 1 # check for carry-out (overflow)
mov qword ptr [rsp], rax # store the result
jne .LBB8_2 # branch on non-zero carry-out
mov rax, qword ptr [rsp] # reload the result
mov qword ptr [rsp + 16], rax # and copy it (to b)
add rsp, 24
ret
.LBB8_2:
call panic function because of integer overflow
setb / test ยังคงซ้ำซ้อนโดยสิ้นเชิง: jc
(กระโดดถ้า CF = 1) จะทำงานได้ดี
ด้วยการเพิ่มประสิทธิภาพการเปิดใช้คอมไพเลอร์สนิมไม่ได้ตรวจสอบสำหรับล้นเพื่อให้การทำงานเช่น+
.wrapping_add()