컴파일러는이를 여러 레지스터에 저장하고 필요한 경우 여러 명령어를 사용하여 해당 값을 산술합니다. 대부분의 ISA에는 x86 과 같은 캐리 추가 기능이 있습니다.adc
이있어 확장 정밀도 정수 추가 / 서브를 수행하는 것이 상당히 효율적입니다.
예를 들어, 주어진
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 호출 규칙은 RDX : RAX에서 128 비트 정수를 반환합니다. 그러나 이것은 main
반환 값을 전혀 반환하지는 않습니다. 모든 중복 복사는 순전히 최적화 비활성화에서 비롯되며 Rust는 실제로 디버그 오버플로를 검사합니다. 양식.)
비교를 위해 다음은 x86-64의 Rust 64 비트 정수에 대한 asm입니다. 여기에는 캐리 추가 기능이 필요하지 않으며 각 값에 대해 단일 레지스터 또는 스택 슬롯 만 있습니다.
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 / 테스트는 여전히 완전히 중복됩니다. jc
됩니다 (CF = 1이면 점프).
최적화가 활성화되면 Rust 컴파일러는 오버플로를 확인하지 않으므로 다음 +
과 같이 작동합니다 .wrapping_add()
.