Tại sao XOR lại chiến thắng SUB trong việc xóa thanh ghi?
Trong lập trình Assembly, lệnh `xor eax, eax` là phương pháp phổ biến nhất để đặt thanh ghi về 0. Mặc dù `sub eax, eax` có những ưu điểm kỹ thuật tương đương hoặc thậm chí tốt hơn về cờ trạng thái, nhưng XOR đã trở thành tiêu chuẩn nhờ hiệu ứng đám đông và thói quen của các trình biên dịch ban đầu.

Matt Godbolt, người nổi tiếng nhất với tư cách là chủ sở hữu của Compiler Explorer, đã viết một bài viết ngắn giải thích lý do tại sao các trình biên dịch x86 lại yêu thích lệnh xor eax, eax.
Câu trả lời nằm ở chỗ đây là cách ngắn gọn nhất để đặt một thanh ghi về 0 trên kiến trúc x86. Cụ thể, nó ngắn hơn vài byte so với cách viết rõ ràng là mov eax, 0 vì nó tránh được việc phải mã hóa hằng số bốn byte. Kiến trúc x86 không có thanh ghi zero chuyên dụng, vì vậy nếu bạn cần xóa một thanh ghi, bạn phải thực hiện việc này từ đầu.
Tuy nhiên, Matt không giải thích tại sao mọi người lại chọn xor thay vì một phép toán toán học khác đảm bảo kết quả bằng 0? Đặc biệt, vấn đề gì với sub eax, eax? Nó được mã hóa với cùng số byte, thực thi trong cùng số chu kỳ. Và hành vi của nó đối với các cờ (flags) thậm chí còn tốt hơn:
xor eax, eaxđể lại cờ AF (Auxiliary Flag) ở trạng thái không xác định.sub eax, eaxlại xóa cờ AF này.
Về mặt kỹ thuật thuần túy, sub có vẻ hợp lý hơn một chút. Nhưng tôi không biết tại sao xor lại thắng cuộc này, nhưng tôi nghi ngờ đó chỉ là một trường hợp của hiệu ứng đám đông (swarming).
Trong lịch sử giả định của tôi, xor và sub ban đầu có độ phổ biến tương đương nhau, nhưng xor đã chiếm lĩnh thế dẫn trước nhỏ do một sự ngẫu nhiên nào đó, có thể vì nó trông "thông minh" hơn.
Khi các trình biên dịch sớm sử dụng xor để xóa thanh ghi, điều này đã khởi động hiệu ứng quả cầu tuyết, vì mọi người sẽ thấy trình biên dịch tạo ra xor và nghĩ: "Chà, những người viết trình biên dịch này rất thông minh, họ hẳn biết điều tôi không biết. Vì tôi đang phân vân giữa xor và sub, thì dữ liệu nhỏ này đủ để đẩy tôi về phía xor."
Sự phổ biến của các thành ngữ này như một cách để xóa thanh ghi đã dẫn đến việc Intel thêm tính năng phát hiện đặc biệt cho cả xor r, r và sub r, r ở bộ giải mã lệnh phía trước và đổi tên đích đến thành một thanh ghi zero nội bộ, bỏ qua việc thực thi lệnh hoàn toàn. Bạn có thể hình dung rằng lệnh, theo một nghĩa nào đó, "mất không chu kỳ để thực thi". Việc phát hiện phía trước cũng phá vỡ các chuỗi phụ thuộc: Thông thường, đầu ra của xor hoặc sub phụ thuộc vào đầu vào của nó, nhưng trong trường hợp đặc biệt này, chúng ta biết đầu ra là 0, độc lập với đầu vào.
Mặc dù Intel đã thêm hỗ trợ cho cả việc phát hiện xor và sub, nhưng cộng đồng trên Stack Overflow lo ngại rằng các nhà sản xuất CPU khác có thể đã xử lý đặc biệt cho xor nhưng không phải sub, điều đó khiến xor trở thành người chiến thắng trong cuộc chiến vô nghĩa này.
Khi một lệnh có lợi thế, ngay cả khi chỉ cực kỳ nhỏ, điều đó đủ để làm nghiêng cán cân và quy tụ mọi người về phía đó.
Một câu chuyện nhỏ thêm: Một trong những đồng nghiệp cũ của tôi thích dùng sub r, r để xóa thanh ghi, và khi tôi đọc mã assembly, tôi có thể nhận ra anh ấy là tác giả nhờ việc sử dụng sub để xóa thanh ghi thay vì xor phổ biến hơn.
Một điều thú vị nữa: Mẹo xor không hoạt động trên Itanium vì các phép toán toán học không đặt lại bit NaT. May mắn thay, Itanium cũng có một thanh ghi zero chuyên dụng, vì vậy bạn không cần mẹo này. Bạn chỉ cần di chuyển giá trị 0 vào đích mong muốn của mình.
Bài viết liên quan

Công nghệ
Nhân viên Meta phẫn nộ trước phần mềm bắt buộc theo dõi hoạt động để huấn luyện AI
22 tháng 4, 2026

Công nghệ
Khi một Vùng Cloud Bị Tê Liệt: Tái Định Nghĩa High Availability Trong Bối Cảnh Địa Chính Trị Bất Ổn
22 tháng 4, 2026

Công nghệ
Công cụ phát hiện AI mới cho thấy các bài đăng của Giáo hoàng có thể do AI viết
22 tháng 4, 2026
