2012-03-04 41 views
6

Tôi đang viết trình biên dịch và tôi phải xuất mã cho các điều kiện phân nhánh trên các giá trị float. Ví dụ: để biên dịch loại mã này:Cách tốt nhất để thực hiện phân nhánh bằng cách sử dụng Intel SSE là gì?

if(a <= b){ 
    //1. DO something 
} else { 
    //2. Do something else 
} 

Khi a và b là biến nổi. Tôi chỉ cần nhảy tới 2 nếu điều kiện không đúng, khác rơi xuống 1. Tôi đang xem xét tối ưu hóa ở mức trình biên dịch xem xét những gì trong 1 và 2.

Tôi cần một cái gì đó phù hợp với tất cả các toán tử so sánh >,> =, <, < =, == và! =

Cách tôi tìm thấy để so sánh là sử dụng CMPLTSD (và các hướng dẫn tương đương khác cho các toán tử quan hệ khác). Nhưng với điều đó, tôi phải sử dụng thanh ghi SSE đặc biệt cho kết quả và sau đó tôi phải di chuyển giá trị của nó trên thanh ghi đa năng (ví dụ: eax) và cuối cùng so sánh giá trị với 0.

Tôi cũng thấy rằng Hướng dẫn UCOMISD nên đặt cờ chính xác, nhưng dường như nó không hoạt động theo cách tôi nghĩ.

Vì vậy, cách tốt nhất để xử lý mã như thế là gì? Có hướng dẫn nào tốt hơn giải pháp đầu tiên tôi có không?

Tốt nhất, ý tôi là, giải pháp chung cho vấn đề này. Nếu có thể, tôi muốn có mã hoạt động giống như khi so sánh các số nguyên (cmp a, b; jge label). Tất nhiên, tôi thích hướng dẫn nhanh nhất để đạt được điều đó.

+2

Cách tốt nhất để làm điều đó * phụ thuộc vào những gì bạn đang làm *. Như trong, cái gì nằm trong khối '// DO something'? "Cách tốt nhất" thường phụ thuộc vào việc xem toàn bộ hình ảnh, không cố gắng dịch dòng mã của bạn theo dòng. – jalf

+0

Tôi đã thêm chi tiết vào bài đăng để trả lời hai câu hỏi của bạn. –

+1

Nếu bạn thực sự muốn chi nhánh, UCOMISD (thực sự là SSE2) có vẻ là câu trả lời, có vấn đề gì với nó? Kết quả không theo thứ tự? – harold

Trả lời

7

Mã điều kiện cho ucomisd không tương ứng với mã so sánh nguyên đã ký, nhưng không khớp với mã số chưa được ký (có "không có thứ tự" trong cờ chẵn lẻ). Đó là một chút lạ, tôi thừa nhận, nhưng tất cả các tài liệu rõ ràng. Mã này nếu bạn thực sự muốn chi nhánh có thể là một cái gì đó như thế này cho <=:

ucomisd a,b 
    ja else  ; greater 
    jp else  ; unordered 
    ; code for //1 goes here 
    jmp end 
else: 
    ; code for //2 goes here 
end: 

Đối <:

jae else ; greater or equal 
jp else ; unordered 

tôi có thể liệt kê tất cả chúng nếu bạn thực sự muốn nhưng bạn chỉ có thể nhìn vào mã điều kiện cho ucomisd và khớp chúng với những gì bạn cần.

+0

Điều này thực sự lạ ... Nhưng tôi nghĩ rằng tôi sẽ có nó với các tài liệu hướng dẫn. Cảm ơn rất nhiều. –

1

quan trọng: @ trả lời harold là gần như chính xác đúng, nhưng có một khía cạnh sai tinh tế mà có thể lái xe bạn điên trong một trường hợp cạnh rất quan trọng sau này - điều trị NaN là ngược từ hầu hết các ngôn ngữ (như C++).

Khi @harold nói chính xác, kết quả so sánh không có thứ tự được lưu trữ trong cờ chẵn lẻ.

Tuy nhiên, so sánh không theo thứ tự là đúng khi bất kỳ toán hạng nào là NaN như được mô tả chi tiết trong this stack overflow post. Điều đó có nghĩa là NaN sẽ nhỏ hơn, bằng và lớn hơn hoàn toàn mỗi số bao gồmNaN.

Vì vậy, nếu bạn muốn ngôn ngữ của bạn để phù hợp với C++ 's hành vi của nơi bất cứ so sánh với NaN trả về false, bạn muốn:

Đối <=:

ucomisd xmm0, xmm1 
jbe else_label 

Đối <:

ucomisd xmm0, xmm1 
jb else_label 

Đã xác nhận trong lần tháo gỡ gcc sau, trong đó tôi return a >= b:

144e:  66 0f 2e c8    ucomisd %xmm0,%xmm1 
1452:  0f 93 c0    setae %al 

Ở đây nó sử dụng setae là số đăng ký sửa đổi tương đương với jae. Sau đó nó ngay lập tức trả về mà không kiểm tra cờ chẵn lẻ.

Vì lý do tại sao số ja và không jg, câu trả lời @ harold vẫn là giải thích rõ ràng và chính xác.

Và tất nhiên, bạn không cần phải sử dụng lệnh so sánh, bạn có thể sử dụng không có thứ tự so sánh như thể hiện trong các câu trả lời trước nếu bạn muốn hoàn toàn tất cả các số được ít hơn, lớn hơn, bằng NaN trong chương trình/ngôn ngữ của bạn (nơi thậm chí NaN < NaN là sự thật!). Và tất nhiên, như bạn có thể thấy, nó có thể chậm hơn một chút vì nó yêu cầu kiểm tra bổ sung.

Các vấn đề liên quan