เท่าที่ฉันรู้การอ้างอิงนามแฝงตัวชี้ / สามารถขัดขวางความสามารถของคอมไพเลอร์ในการสร้างรหัสที่ดีที่สุดเพราะพวกเขาจะต้องตรวจสอบให้แน่ใจว่าการสร้างไบนารีทำงานอย่างถูกต้องในกรณีที่ทั้งสองอ้างอิง / พอยน์เตอร์นามแฝงแน่นอน ตัวอย่างเช่นในรหัส C ต่อไปนี้
void adds(int *a, int *b) {
*a += *b;
*a += *b;
}
เมื่อคอมไพล์clang version 6.0.0-1ubuntu2 (tags/RELEASE_600/final)
ด้วย-O3
แฟล็ก
0000000000000000 <adds>:
0: 8b 07 mov (%rdi),%eax
2: 03 06 add (%rsi),%eax
4: 89 07 mov %eax,(%rdi) # The first time
6: 03 06 add (%rsi),%eax
8: 89 07 mov %eax,(%rdi) # The second time
a: c3 retq
ที่นี่รหัสเก็บกลับไป(%rdi)
สองครั้งในกรณีint *a
และint *b
นามแฝง
เมื่อเราบอกคอมไพเลอร์อย่างชัดเจนว่าตัวชี้ทั้งสองนี้ไม่สามารถใช้นามแฝงกับrestrict
คำหลักได้:
void adds(int * restrict a, int * restrict b) {
*a += *b;
*a += *b;
}
จากนั้นเสียงดังกราวจะเปล่งรหัสไบนารี่เวอร์ชั่นที่ดีที่สุด
0000000000000000 <adds>:
0: 8b 06 mov (%rsi),%eax
2: 01 c0 add %eax,%eax
4: 01 07 add %eax,(%rdi)
6: c3 retq
เนื่องจากสนิมทำให้แน่ใจ (ยกเว้นในรหัสที่ไม่ปลอดภัย) ว่าการอ้างอิงที่ไม่แน่นอนทั้งสองไม่สามารถใช้นามแฝงได้ฉันจึงคิดว่าคอมไพเลอร์ควรจะปล่อยโค้ดที่ได้รับการปรับให้เหมาะสมที่สุด
เมื่อผมทดสอบด้วยโค้ดด้านล่างและเรียบเรียงด้วยrustc 1.35.0
กับ-C opt-level=3 --emit obj
,
#![crate_type = "staticlib"]
#[no_mangle]
fn adds(a: &mut i32, b: &mut i32) {
*a += *b;
*a += *b;
}
มันสร้าง:
0000000000000000 <adds>:
0: 8b 07 mov (%rdi),%eax
2: 03 06 add (%rsi),%eax
4: 89 07 mov %eax,(%rdi)
6: 03 06 add (%rsi),%eax
8: 89 07 mov %eax,(%rdi)
a: c3 retq
สิ่งนี้ไม่ได้ใช้ประโยชน์จากการรับประกันa
และb
ไม่สามารถใช้นามแฝงได้
นี่เป็นเพราะคอมไพเลอร์ปัจจุบันยังอยู่ในระหว่างการพัฒนาและยังไม่ได้รวมการวิเคราะห์นามแฝงเพื่อเพิ่มประสิทธิภาพ
นี่เป็นเพราะยังมีโอกาสa
และb
นามแฝงแม้ใน Rust ที่ปลอดภัยหรือไม่
unsafe
รหัสการอ้างอิงนามแฝงที่ไม่แน่นอนไม่ได้รับอนุญาตและทำให้เกิดพฤติกรรมที่ไม่ได้กำหนด คุณสามารถใช้นามแฝงตัวชี้แบบ raw ได้ แต่unsafe
รหัสไม่อนุญาตให้คุณละเว้นกฎมาตรฐานของสนิม เป็นเพียงความเข้าใจผิดที่พบบ่อยและคุ้มค่าที่จะชี้ให้เห็น
+=
ปฏิบัติการทั้งสองในร่างกายของadds
สามารถตีความได้ว่าเป็น*a = *a + *b + *b
อย่างไร หากตัวชี้ไม่นามแฝงพวกเขาสามารถคุณยังสามารถมองเห็นสิ่งที่จำนวนเงินb* + *b
ใน asm 2: 01 c0 add %eax,%eax
สองรายการ: แต่ถ้าพวกเขาทำนามแฝงพวกเขาไม่สามารถทำได้เพราะเมื่อคุณเพิ่ม*b
เป็นครั้งที่สองมันจะมีค่าที่แตกต่างจากครั้งแรกที่อยู่รอบ ๆ (อันที่คุณเก็บไว้ใน4:
รายการแรกของ asm)