我一直在查看整型gmp源代码,以了解如何以cmm的方式实现GHC Primops页面上所记录的外国原始业务。我知道使用llvm攻击或fvia-C/gcc来实现它们的技术--这是我理解interger-gmp库使用的第三种方法的一种学习经验。
因此,我在MSFT页面(pdf连结)上查阅了CMM教程,浏览了GHC CMM页面,仍然有一些未回答的问题(很难在不深入CMM的情况下保留所有这些概念,这就是我现在正在做的)。有一个来自整型bmp cmm文件的代码片段
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报头中所定义的
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混淆)。更具体而言:
据我理解,这个函数(通过查看Prim.hs中的函数签名)接受一个int,并返回一个(int,字节数组)(分别存储在代码中的s和p中)。
对于任何想知道在if block中内联调用的人来说,这是si函数的cmm实现。我的猜测是,如果您通过ccall调用对象文件中定义的函数,它就不能内联(这是有意义的,因为它是对象代码,而不是中间代码- LLVM方法似乎更适合通过LLVM IR进行内联)。因此,优化是定义要内联的函数的cmm表示。如果这个猜测是错误的,请纠正我。
我们将非常感谢对第5-9行的解释。关于整数-gmp文件中定义的其他宏,我有更多的问题,但在一篇文章中可能要求太多了。如果您可以使用Haskell wiki页面或博客来回答这个问题(您可以将链接作为答案发布),这将是非常感谢的(如果您这样做了,我也会感谢一个整数-gmp的cmm宏(如GMP_TAKE2_RET1)的逐步遍历)。
发布于 2014-09-22 14:54:39
这些行在Haskell堆上分配了一个新的ByteArray#,因此要了解它们,首先需要了解一下GHC的堆是如何管理的。
Haskell类型的ByteArray#是用堆对象类型ARR_WORDS实现的。ARR_WORDS对象只是由(一个信息指针后面跟着)一个大小(字节)和任意数据(有效载荷)组成。GC不解释有效负载,因此它不能存储指向Haskell堆对象的指针,但可以存储任何其他内容。SIZEOF_StgArrWords是所有ARR_WORDS堆对象共有的头的大小,在这种情况下,有效负载只是一个单词,所以SIZEOF_StgArrWords + WDS(1)是我们需要分配的空间的数量。
ALLOC_PRIM_N (SIZEOF_StgArrWords + WDS(1),integer_cmm_int2Integerzh,val)扩展为
Hp = Hp + (SIZEOF_StgArrWords + WDS(1));
if (Hp > HpLim) {
HpAlloc = SIZEOF_StgArrWords + WDS(1);
goto stg_gc_prim_n(integer_cmm_int2Integerzh, val);
}第一行增加惠普分配的数量。第二行检查堆溢出。第三行记录我们试图分配的金额,这样GC就可以撤销它。第四行调用GC。
第四行是最有趣的。参数告诉GC如何在垃圾回收完成后重新启动线程:它应该使用参数val重新调用integer_cmm_int2Integerzh。_n( stg_gc_prim_n中的"_n“和ALLOC_PRIM_N中的"_N”)意味着val是一个非指针参数(在本例中是Int#)。如果val是指向Haskell堆对象的指针,则GC需要知道它是活动的(因此它不会被收集),并使用对象的新地址重新调用我们的函数。在这种情况下,我们将使用_p变体。还有一些变体,如用于多指针参数的_pp,用于Double#参数的_d等。
在第5行之后,我们成功地分配了一个SIZEOF_StgArrWords + WDS(1)字节块,记住,Hp指向它的最后一个单词。所以,p= Hp - SIZEOF_StgArrWords将p设置为这个块的开头。第8行填充p的info指针,将新创建的堆对象标识为ARR_WORDS。CCCS是当前的成本中心堆栈,仅用于分析。启用分析时,每个堆对象都包含一个额外的字段,该字段基本上标识谁负责其分配。在非分析构建中,没有CCCS,SET_HDR只设置信息指针。最后,第9行填充ByteArray#的size字段。函数的其余部分填充有效负载并返回符号值和ByteArray#对象指针。
因此,这最终更多地是关于GHC堆而不是Cmm语言,但我希望它能有所帮助。
发布于 2014-09-24 06:32:12

所需知识
为了实现运算和逻辑运算,计算机在其CPU (Central )中采用了数字电路,称为ALU (算术逻辑单元)。ALU从输入寄存器加载数据。处理器寄存器是在位于CPU芯片E 220的SRAM(静态随机存取存储器)中实现的L1 cache (数据请求在3 CPU时钟时钟内的数据请求)中的内存存储。一个处理器通常包含几种寄存器的,通常根据它们能容纳的的位数来区分。
数字是用表示的离散位,可以保持有限的数值。数字通常遵循原语类型,由编程语言(在哈斯克尔)公开:
8 bit numbers = 256 unique representable values
16 bit numbers = 65 536 unique representable values
32 bit numbers = 4 294 967 296 unique representable values
64 bit numbers = 18 446 744 073 709 551 616 unique representable values针对这些类型的固定精度算法已经在硬件中实现了.字大小是指计算机的CPU一次可处理的位数。对于x86体系结构,这是32位和x64,这是64位。
IEEE754定义了{16,32,64,128}位数字的浮点数标准,例如32位点数(有4 294 967 296个唯一值),至少可以保持近似值-3.402823e38到3.402823e38,其精度至少<代码>E 2547<代码>E 256浮点数>E 157位数。

此外
缩写GMP指的是GNU多精度算法库,并添加了对软件模拟的任意精度算法的支持。Glasgow Haskell编译器 Integer实现使用此方法。
GMP的目标是在所有操作数的大小上比任何其他大型库都更快。这样做的一些重要因素是:
回答
对于某些人来说,Haskell可能有点难以理解语法,下面是javascript版本
var integer_cmm_int2Integerzh = function(word) {
return WORDSIZE == 32
? goog.math.Integer.fromInt(word))
: goog.math.Integer.fromBits([word.getLowBits(), word.getHighBits()]);
};goog是使用的Google闭包库类位于Math.Integer中。称为职能:
goog.math.Integer.fromInt = function(value) {
if (-128 <= value && value < 128) {
var cachedObj = goog.math.Integer.IntCache_[value];
if (cachedObj) {
return cachedObj;
}
}
var obj = new goog.math.Integer([value | 0], value < 0 ? -1 : 0);
if (-128 <= value && value < 128) {
goog.math.Integer.IntCache_[value] = obj;
}
return obj;
};
goog.math.Integer.fromBits = function(bits) {
var high = bits[bits.length - 1];
return new goog.math.Integer(bits, high & (1 << 31) ? -1 : 0);
};这并不完全正确,因为返回类型应该是return (s,p);
为了修复这个问题,应该创建GMP包装器。这是在Haskell到JavaScript编译器项目(源链接)中完成的。
第5-9行
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;如下所示
https://stackoverflow.com/questions/16067523
复制相似问题