외부 primop에 대한 cmm 호출 형식 (integer-gmp 예)
나는 GHC Primops 페이지 에 문서화 된 것처럼 외부 primops이 cmm 측면에서 어떻게 구현 될 수 있는지 이해하기 위해 integer-gmp 소스 코드를 확인했습니다 . llvm hack 또는 fvia-C / gcc를 사용하여 구현하는 기술을 알고 있습니다. 이것은 interger-gmp 라이브러리가 사용하는 세 번째 접근 방식을 이해하는 데 더 많은 학습 경험입니다.
그래서 저는 MSFT 페이지 (pdf 링크) 에서 CMM 튜토리얼을 찾아보고 GHC CMM 페이지를 살펴 봤지만 아직 답이없는 질문이 몇 가지 있습니다 (지금하고있는 CMM을 파헤 치지 않고 모든 개념을 머리 속에 유지하기가 어렵습니다). integer-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/0 혼란이있는 경우 1 행이 시작입니다). 더 구체적으로:
- ALLOC_PRIM_N (bytes, fun, arg)의 함수 호출 형식이 왜 그런가요?
- p가 그렇게 조작되는 이유는 무엇입니까?
I는 (함수 서명보고로부터 이해할으로서의 기능 Prim.hs는 ) int를 가져 와서 (INT, 바이트 어레이) (저장 반환 s
, p
코드를 각각 참조).
인라인 호출에 대해 궁금한 사람을 위해 if block
gmp mpz_init_si 함수 의 cmm 구현입니다 . 내 생각 엔 ccall을 통해 개체 파일에 정의 된 함수를 호출하면 인라인 될 수 없습니다 (중간 코드가 아닌 개체 코드이기 때문에 의미가 있습니다-LLVM 접근 방식은 LLVM IR을 통한 인라인에 더 적합합니다). 따라서 최적화는 인라인 될 함수의 cmm 표현을 정의하는 것입니다. 이 추측이 잘못된 경우 저를 수정하십시오.
Explanation of lines 5-9 will be very much appreciated. I have more questions about other macros defined in integer-gmp file, but it might be too much to ask in one post. If you can answer the question with a Haskell wiki page or a blog (you can post the link as answer), that would be much appreciated (and if you do, I would also appreciate step-by-step walk-through of an integer-gmp cmm macro such as GMP_TAKE2_RET1
).
Those lines allocate a new ByteArray# on the Haskell heap, so to understand them you first need to know a bit about how GHC's heap is managed.
각 기능 (= Haskell 코드를 실행하는 OS 스레드)에는 고유 한 nursery 가 있으며 , 힙 영역은 이와 같이 정상적이고 작은 할당을 수행합니다. 가비지 수집기를 트리거하는 nursery의 나머지 공간을 초과하는 할당을 시도 할 때까지 개체는 낮은 주소에서 높은 주소로이 영역에 순차적으로 할당됩니다.
모든 힙 개체는 단어 크기의 배수로 정렬됩니다. 즉, 32 비트 시스템에서는 4 바이트, 64 비트 시스템에서는 8 바이트입니다.
Cmm 레벨 레지스터 Hp는 nursery에 할당 된 마지막 단어 (시작)를 가리 킵니다. HpLim은 nursery에서 할당 할 수있는 마지막 단어를 가리 킵니다. (HpLim은 GC의 세계를 중지하거나 비동기 예외를 보내기 위해 다른 스레드에서 0으로 설정할 수도 있습니다.)
https://ghc.haskell.org/trac/ghc/wiki/Commentary/Rts/Storage/HeapObjects 에는 개별 힙 개체의 레이아웃에 대한 정보가 있습니다. 특히 각 힙 객체는 (무엇보다도) 어떤 종류의 힙 객체인지 식별 하는 info 포인터로 시작 합니다.
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);
}
첫 번째 줄은 할당 할 양만큼 Hp를 증가시킵니다. 두 번째 줄은 힙 오버플로를 확인합니다. 세 번째 줄에는 할당하려는 금액이 기록되어 있으므로 GC에서 실행 취소 할 수 있습니다. 네 번째 줄은 GC를 호출합니다.
네 번째 줄이 가장 흥미 롭습니다. 인수는 가비지 콜렉션이 완료되면 스레드를 다시 시작하는 방법을 GC에 알려줍니다. val 인수로 integer_cmm_int2Integerzh를 다시 호출해야합니다. 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의 정보 포인터를 채우고 새로 생성 된 힙 개체를 ARR_WORDS로 식별합니다. CCCS는 프로파일 링에만 사용되는 현재 비용 센터 스택입니다. 프로파일 링이 활성화되면 각 힙 개체에는 기본적으로 할당 책임자를 식별하는 추가 필드가 포함됩니다. 비 프로파일 링 빌드에는 CCCS가 없으며 SET_HDR은 정보 포인터 만 설정합니다. 마지막으로 9 행은 ByteArray #의 크기 필드를 채 웁니다. 나머지 함수는 페이로드를 채우고 부호 값과 ByteArray # 개체 포인터를 반환합니다.
따라서 이것은 Cmm 언어보다 GHC 힙에 관한 것이었지만 도움이되기를 바랍니다.
필요한 지식
In order to do arithmetic and logical operations computers have digital circuit called ALU (Arithmetic Logic Unit) in their CPU (Central Processing Unit). An ALU loads data from input registers. Processor register is memory storage in L1 cache (data requests within 3 CPU clock ticks) implemented in SRAM(Static Random-Access Memory) located in CPU chip. A processor often contains several kinds of registers, usually differentiated by the number of bits they can hold.
Numbers are expressed in discrete bits can hold finite number of values. Typically numbers have following primitive types exposed by the programming language (in Haskell):
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
Fixed-precision arithmetic for those types has been implemented in hardware. Word size refers to the number of bits that can be processed by a computer's CPU in one go. For x86 architecture this is 32 bits and x64 this is 64 bits.
IEEE 754 defines floating point numbers standard for {16, 32, 64, 128} bit numbers. For example 32 bit point number (with 4 294 967 296 unique values) can hold approximate values [-3.402823e38 to 3.402823e38] with accuracy of at least 7 floating point digits.
In addition
Acronym GMP means GNU Multiple Precision Arithmetic Library and adds support for software emulated arbitrary-precision arithmetic's. Glasgow Haskell Compiler Integer implementation uses this.
GMP aims to be faster than any other bignum library for all operand sizes. Some important factors in doing this are:
- Using full words as the basic arithmetic type.
- Using different algorithms for different operand sizes; algorithms that are faster for very big numbers are usually slower for small numbers.
- Highly optimized assembly language code for the most important inner loops, specialized for different processors.
Answer
For some Haskell might have slightly hard to comprehend syntax so here is javascript version
var integer_cmm_int2Integerzh = function(word) {
return WORDSIZE == 32
? goog.math.Integer.fromInt(word))
: goog.math.Integer.fromBits([word.getLowBits(), word.getHighBits()]);
};
Where goog is Google Closure library class used is located in Math.Integer. Called functions :
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);
};
That is not totally correct as return type should be return (s,p);
where
- s is value
- p is sign
In order to fix this GMP wrapper should be created. This has been done in Haskell to JavaScript compiler project (source link).
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;
다음과 같습니다
- 새 단어로 공간을 할당
- 그것에 대한 포인터를 생성
- 포인터 값 설정
- 포인터 유형 크기 설정
참고 URL : https://stackoverflow.com/questions/16067523/cmm-call-format-for-foreign-primop-integer-gmp-example
'Program Tip' 카테고리의 다른 글
Jenkins + Play 1.2.4 : cobertura 잠금 파일 / 보고서 관련 문제 (0) | 2020.11.25 |
---|---|
jquery가 메모리를 너무 많이 누수하는 이유는 무엇입니까? (0) | 2020.11.25 |
앱 * 및 * 웹 사이트에 대해 OAuth2로 인증 (0) | 2020.11.25 |
예를 들어 아래에 더 이상 콘텐츠가 없을 때 NestedScrollView & CollapsingToolbarLayout의 스크롤을 비활성화하는 방법은 무엇입니까? (0) | 2020.11.25 |
systemgroup.com.apple.configurationprofiles 경로에 대한 시스템 그룹 컨테이너 (0) | 2020.11.25 |