Вот код, который добавляет два тройки незанятых слов, представляющих 192-битное число, в новую тройку нерасположенных слов, а также возвращает любое переполнение:
{-# 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 #) #)
Проблема - это определение "plusWord3". В идеале это похоже на функцию adc, которая принимает два слова и бит переноса и возвращает результат и новый перенос, поэтому результирующая сборка выглядит следующим образом:
add x1 y1
adc x2 y2
adc x3 y3
К сожалению, GHC, будь то native или через LLVM, создает уродливый ассемблерный код, который включает сохранение бит переноса в регистр, а затем чтение его с помощью отдельного дополнительного добавления вместо использования adc
. Я не хочу вызывать внешнюю функцию C для достижения этой цели, так как как только вы добавляете накладные расходы на вызов, это, вероятно, не стоит, я бы хотел остаться в Haskell, чтобы код мог быть встроен там, где это возможно. Но я также хочу уговорить компилятор подготовить инструкцию adc
соответствующим образом. В любом случае я могу достичь этого?