Я проверил integer-gmp исходный код, чтобы понять, как иностранные примитивы могут быть реализованы с точки зрения cmm, как описано на Страница GHC Primops. Я знаю о методах их реализации, используя llvm hack или fvia-C/gcc - это больше для изучения, чтобы понять этот третий подход, который interger-gmp библиотека использует.
Итак, я просмотрел учебник CMM на странице MSFT (pdf-ссылка), прошел страницу GHC CMM, и все еще есть некоторые неотвеченные вопросы (трудно держать все эти концепции в голове, не копаясь в CMM, что я и делаю сейчас). Этот фрагмент кода существует из файла cmm integer-bmp:
integer_cmm_int2Integerzh (W_ val)
{
W_ s, p; /* to avoid aliasing */
ALLOC_PRIM_N (SIZEOF_StgArrWords + WDS(1), integer_cmm_int2Integerzh, val);
p = Hp - SIZEOF_StgArrWords;
SET_HDR(p, stg_ARR_WORDS_info, CCCS);
StgArrWords_bytes(p) = SIZEOF_W;
/* mpz_set_si is inlined here, makes things simpler */
if (%lt(val,0)) {
s = -1;
Hp(0) = -val;
} else {
if (%gt(val,0)) {
s = 1;
Hp(0) = val;
} else {
s = 0;
}
}
/* returns (# size :: Int#,
data :: ByteArray#
#)
*/
return (s,p);
}
Как определено в ghc cmm header:
W_ is alias for word.
ALLOC_PRIM_N is a function for allocating memory on the heap for primitive object.
Sp(n) and Hp(n) are defined as below (comments are mine):
#define WDS(n) ((n)*SIZEOF_W) //WDS(n) calculates n*sizeof(Word)
#define Sp(n) W_[Sp + WDS(n)]//Sp(n) points to Stackpointer + n word offset?
#define Hp(n) W_[Hp + WDS(n)]//Hp(n) points to Heap pointer + n word offset?
Я не понимаю строки 5-9 (строка 1 - это начало, если у вас есть путаница 1/0). Более конкретно:
- Почему формат вызова функции ALLOC_PRIM_N (bytes, fun, arg) таким образом?
- Почему p управляется таким образом?
Функция, как я ее понимаю (от поиска сигнатуры функции в Prim.hs) принимает int и возвращает массив (int, byte) (хранится в s
, p
соответственно в коде).
Для тех, кто интересуется встроенным вызовом в if block
, это реализация cmm gmp mpz_init_si. Я предполагаю, что если вы вызываете функцию, определенную в объектном файле через ccall, она не может быть встроена (что имеет смысл, поскольку это объектный код, а не промежуточный код). Подход LLVM более подходит для встраивания через LLVM IR). Таким образом, оптимизация заключалась в том, чтобы определить cmm-представление функции, которая должна быть встроена. Пожалуйста, исправьте меня, если это предположение неверно.
Пояснение строк 5-9 будет очень оценено. У меня больше вопросов о других макросах, определенных в файле integer-gmp, но в одном сообщении может быть слишком много вопросов. Если вы можете ответить на вопрос с помощью вики-страницы Haskell или блога (вы можете опубликовать ссылку в качестве ответа), это было бы высоко оценено (и если вы это сделаете, я также хотел бы пошаговое прохождение целого числа -gmp cmm, например GMP_TAKE2_RET1
).