2015-11-08 33 views
17

Đây là mã có thêm hai gấp ba của Words không có hộp bọc đại diện cho một số 192 bit thành một triple mới của Words không có hộp bọc, và cũng có thể trả về bất kỳ tràn:Bắt GHC để sản xuất "Thêm Với Carry (ADC)" hướng dẫn

{-# LANGUAGE MagicHash #-} 
{-# LANGUAGE UnboxedTuples #-} 

import GHC.Prim(plusWord2#, Word#, or#) 

longAdd :: 
    (# Word#, Word#, Word# #) -> 
    (# Word#, Word#, Word# #) -> 
    (# Word#, (# Word#, Word#, Word# #) #) 

longAdd (# xl, xm, xh #) (# yl, ym, yh #) =  
    let 
    plusWord3 x y c = 
     let 
     (# c1, r1 #) = plusWord2# x y 
     (# c2, r2 #) = plusWord2# r1 c 
     in 
     (# plusWord# c1 c2, r2 #) 
    (# cl, rl #) = plusWord2# xl yl 
    (# cm, rm #) = plusWord3 xm ym cl 
    (# ch, rh #) = plusWord3 xh yh cm  
    in 
    (# ch, (# rl, rm, rh #) #) 

Vấn đề là định nghĩa "plusWord3". Lý tưởng nhất, điều này cũng giống như một chức năng "ADC", trong đó có hai từ và các bit thực hiện và trả về kết quả và một carry mới, vì vậy việc lắp ráp kết quả là như sau:

add x1 y1 
adc x2 y2 
adc x3 y3 

Thật không may GHC, cho dù mẹ đẻ hoặc thông qua LLVM, tạo mã lắp ráp xấu xí có liên quan đến việc lưu bit mang vào sổ đăng ký và sau đó đọc nó qua một phần bổ sung riêng biệt, thay vì chỉ sử dụng adc. Tôi không muốn gọi một hàm C bên ngoài để đạt được điều này, khi một khi bạn thêm phí gọi, nó có thể không đáng, tôi muốn ở lại Haskell để mã có thể được inline nếu có thể. Nhưng tôi cũng muốn để có thể dỗ các trình biên dịch vào sản xuất các hướng dẫn adc một cách thích hợp. Có anyway tôi có thể đạt được điều đó?

+1

192 bit từ (và nhiều từ khác) có sẵn trong ['Dữ liệu.DoubleWord'] (https://hackage.haskell.org/package/data-dword-0.3/docs/Data-DoubleWord.html). Tôi tự hỏi nếu nó được tối ưu hóa để tạo ra mã hiệu quả, vì vậy nó có thể là một nguồn kiến ​​thức làm thế nào để làm điều đó, hoặc một nơi để đóng góp, một khi bạn tìm thấy câu trả lời. –

Trả lời

8

Tôi không quen với lập trình cấp thấp, nhưng sau khi đặt câu hỏi trên kênh #ghc của Freenode, tôi có một con trỏ tới số addIntC# primop, có liên quan đến số llvm.sadd.with.overflow. của LLVM. Tôi không chắc chắn những gì llvm biên dịch mà vào.


Gen mã gốc của GHC dường như biết về adc hướng dẫn: X86/CodeGen.hs. Nhưng khi bình luận nói:

chúng tôi xử lý thêm, nhưng khá nặng


Edit: bạn làm việc với các từ. Dường như LLVM backend không biên dịch MO_Add2 (đó là một tên khác cho plusWord2) để llvm.uadd.with.overflow trong https://github.com/ghc/ghc/blob/2b7d9c2b96eb9da3cce7826df4a91c3426095528/compiler/llvmGen/LlvmCodeGen/CodeGen.hs#L737, vé liên quan: https://ghc.haskell.org/trac/ghc/ticket/9430

11

cách đáng tin cậy và hiệu quả nhất sẽ được gọi một primop trực tiếp trong chương trình của bạn.

Sử dụng cuộc gọi FFI là cách dễ nhất nhưng vì bạn cũng lưu ý nó sẽ không phải là cách hiệu quả nhất, vì chi phí FFI.

Thậm chí nếu trình biên dịch sẽ hỗ trợ lệnh bạn muốn và sử dụng nó trong một số chương trình, nó sẽ là mong manh. Một số thay đổi có vẻ vô tội trong chương trình của bạn có thể kết thúc với các assembly được tạo khác mà không sử dụng lệnh bạn muốn.

Vì vậy, đề nghị của tôi là:

  1. Thêm hướng dẫn bạn cần để mã X86 máy phát điện phụ trợ, nếu nó không phải là có rồi.
  2. Thêm bản gốc dịch trực tiếp đến lệnh bạn muốn chạy. Trước tiên hãy chắc chắn rằng không có primop như vậy tồn tại. Sau đó, hãy làm theo các bước sau: https://ghc.haskell.org/trac/ghc/wiki/AddingNewPrimitiveOperations
  3. Bạn có thể nhìn thấy lớp lót trong GHC.Prim (http://hackage.haskell.org/package/ghc-prim/docs/GHC-Prim.html), sử dụng nó trong chương trình của bạn.
  4. Thêm kiểm tra, gửi bản vá của bạn :)
Các vấn đề liên quan