Nếu bạn nhân hai giá trị mà bạn không biết trước, không thể đánh bại lệnh nhân trong bộ ghép x86.
Nếu bạn biết trước giá trị của một trong các toán hạng, bạn có thể đánh bại lệnh nhân bằng cách sử dụng một số lượng nhỏ số lần thêm. Điều này làm việc đặc biệt tốt khi toán hạng đã biết là nhỏ, và chỉ có một vài bit trong biểu diễn nhị phân của nó. Để nhân giá trị không xác định x với giá trị đã biết bao gồm 2^p + 2^q + ... 2^r bạn chỉ cần thêm x * 2^p + x * 2^q + .. x * 2 * r nếu bit p, q , ... và r được đặt. Đây có thể dễ dàng thực hiện trong lắp ráp bởi trái chuyển và nói thêm:
; x in EDX
; product to EAX
xor eax,eax
shl edx,r ; x*2^r
add eax,edx
shl edx,q-r ; x*2^q
add eax,edx
shl edx,p-q ; x*2^p
add eax,edx
Vấn đề chính với điều này là phải mất ít nhất 4 đồng hồ để làm điều này, giả sử một CPU superscalar hạn chế bởi phụ thuộc đăng ký.Nhân thường mất 10 hoặc ít hơn đồng hồ trên CPU hiện đại và nếu chuỗi này dài hơn thời gian , bạn cũng có thể nhân lên.
Để nhân với 9:
mov eax,edx ; same effect as xor eax,eax/shl edx 1/add eax,edx
shl edx,3 ; x*2^3
add eax,edx
này nhịp đập nhân; chỉ nên lấy 2 đồng hồ.
Điều ít nổi tiếng hơn là sử dụng lệnh LEA (địa chỉ hiệu quả tải), để thực hiện nhanh chóng theo từng hằng số nhỏ. LEA chỉ mất một đồng hồ duy nhất trong trường hợp xấu nhất thời gian thực thi của nó thường có thể là bằng cách chồng chéo với các hướng dẫn khác bằng CPU siêu cứng.
LEA về cơ bản là "thêm hai giá trị có số nhân không đổi nhỏ". Nó tính t = 2^k * x + y cho k = 1,2,3 (xem sách hướng dẫn tham chiếu của Intel) cho t, x và y là bất kỳ thanh ghi nào. Nếu x == y, bạn có thể nhận được 1,2,3,4,5,8,9 lần x, nhưng sử dụng x và y làm sổ đăng ký riêng cho phép kết quả trung gian được kết hợp và được chuyển sang thanh ghi khác ví dụ, để t), và điều này hóa ra là rất tiện dụng. Sử dụng nó, bạn có thể hoàn thành một nhân với 9 sử dụng một chỉ dẫn duy nhất:
lea eax,[edx*8+edx] ; takes 1 clock
Sử dụng LEA một cách cẩn thận, bạn có thể nhân bởi một loạt các hằng số đặc biệt trong một số ít các chu kỳ:
lea eax,[edx*4+edx] ; 5 * edx
lea eax,[eax*2+edx] ; 11 * edx
lea eax,[eax*4] ; 44 * edx
Để thực hiện điều này, bạn phải phân tách hệ số không đổi của bạn thành nhiều yếu tố/số tiền khác nhau liên quan đến 1,2,3,4,5,8 và 9. Điều đáng chú ý là bạn có thể thực hiện bao nhiêu hằng số nhỏ và vẫn sử dụng 3-4 hướng dẫn.
Nếu bạn cho phép sử dụng các hướng dẫn đơn đồng hồ thông thường khác (ví dụ: SHL/SUB/NEG/MOV) bạn có thể nhân với một số giá trị không đổi mà LEA tinh khiết không thể tự làm. Để nhân với 31:
lea eax,[4*edx]
lea eax,[8*eax] ; 32*edx
sub eax,edx; 31*edx ; 3 clocks
Chuỗi LEA tương ứng dài:
lea eax,[edx*4+edx]
lea eax,[edx*2+eax] ; eax*7
lea eax,[eax*2+edx] ; eax*15
lea eax,[eax*2+edx] ; eax*31 ; 4 clocks
Tìm ra những trình tự này là một chút khó khăn, nhưng bạn có thể thiết lập một cuộc tấn công có tổ chức.
Vì LEA, SHL, SUB, NEG, MOV là tất cả các lệnh đồng hồ đơn nhất và đồng hồ không nếu chúng không phụ thuộc vào các hướng dẫn khác, bạn có thể tính toán chi phí exeuction của bất kỳ trình tự như vậy. Điều này có nghĩa là bạn có thể thực hiện một thuật toán lập trình động để tạo chuỗi tốt nhất có thể có của các hướng dẫn như vậy. Điều này chỉ hữu ích nếu số lượng đồng hồ nhỏ hơn số nguyên nhân cho CPU cụ thể của bạn (Tôi sử dụng 5 đồng hồ làm quy tắc chung), và nó không sử dụng hết tất cả các thanh ghi hoặc ít nhất nó không không sử dụng đăng ký đã được bận rộn (tránh bất kỳ sự cố tràn).
Tôi đã thực sự xây dựng bộ biên dịch này vào trình biên dịch PARLANSE và rất hiệu quả để tính toán các mảng cấu trúc A [i], trong đó kích thước của phần tử cấu trúc trong A là hằng số đã biết.Một người thông minh có thể nhớ cache câu trả lời để nó không phải là phải được tính toán lại mỗi lần nhân cùng một hằng số xảy ra; Tôi đã không thực sự làm điều đó bởi vì thời gian để tạo ra các chuỗi như vậy là ít hơn bạn mong đợi.
Điều thú vị là in ra các chuỗi các lệnh cần thiết để nhân với tất cả các hằng số từ 1 đến 10000. Hầu hết trong số đó có thể được thực hiện trong trường hợp xấu nhất 5-6. Kết quả là, trình biên dịch PARLANSE hầu như không bao giờ sử dụng một số nhân thực tế khi lập chỉ mục ngay cả các mảng cấu trúc lồng nhau tối thiểu .
lý do tại sao ubuntu trong thẻ? –
@ x2 -Bởi vì tôi phải thêm ít nhất năm thẻ để đăng câu hỏi của mình, xin lỗi. – Pavitar
cái gì? không bạn không. –