리더 보드-JIT 컴파일 (낮을수록 좋음)
- es1024-81.2 점 (작동중인 컴파일러 포함)
- 키 에트 랜달-116 포인트
- 엘-121 포인트
리더 보드-해석 됨 (낮을수록 좋음)
- Martin Büttner-706654 점 (약 2 시간 정도).
- criptych-30379 포인트 (97 초)
당신의 임무는 당신이 그것을 받아들이도록 선택한다면 가능한 가장 작은 바이트 코드 인터프리터 / VM을 작성하는 것입니다. VM / 인터프리터는 아래에 지정된 언어로 작은 CISC 아키텍처 (작업 크기가 다를 수 있음)를 사용합니다. 완료되면 3 개의 CPU 레지스터 값을 인쇄하여 올바른 출력이 인쇄되었음을 증명해야합니다 (3,126,900,366).
컴파일러
자체 테스트를 원한다면 컴파일러가 아래에 게시되어 있습니다. 답을 가지고 테스트를 게시하십시오.
"VM"사양
VM에는 3 개의 32 비트 부호없는 정수 레지스터 R0, R1, R2가 있습니다. 16 진수로 0x00, 0x01 및 0x02로 표시됩니다.
다음 작업이 지원되어야합니다.
형식은 [이름] [... 피연산자 ...], [16 진수 연산 코드] [... 피연산자 반복 ...]입니다.
- LOAD [레지스터] [4 바이트 값], 0x00 [레지스터] [4 바이트 값]
- PUSH [등록], 0x02 [등록]
- POP [등록], 0x03 [등록]
- ADD [레지스터, 1 바이트] [레지스터, 1 바이트], 0x04 [레지스터] [레지스터]
- SUB [레지스터, 1 바이트] [레지스터, 1 바이트], 0x05 [레지스터] [레지스터]
- MUL [레지스터, 1 바이트] [레지스터, 1 바이트], 0x06 [레지스터] [레지스터]
- DIV [register, 1 byte] [register, 1 byte], 0x07 [register] [register]
- JMP [코드 라인, 4 바이트], 0x08 [4 바이트 코드 라인 번호]
- CMP [레지스터, 1 바이트] [레지스터, 1 바이트], 0x09 [레지스터] [레지스터]
- BRANCHLT [코드 라인, 4 바이트], 0x0a [4 바이트 코드 라인 번호]
몇 가지 참고 사항 :
- 위의 수학 연산은 2 개의 레지스터 값을 더하여 출력을 첫 번째 레지스터에 배치합니다.
- 비교 연산자 인 CMP는 2 개의 레지스터 값을 비교하고 나중에 분기 명령어에서 사용할 수 있도록 일부 내부 플래그 (구현에 따라 다를 수 있음)에 출력을 저장해야합니다.
- CRAN 전에 BRANCH를 호출 한 경우 BRANCHEQ를 호출하지 않으면 "VM"은 분기되지 않아야합니다.
- PUSH / POP는 당연히 스택에서 숫자를 푸시하거나 팝합니다.
- 점프 및 분기 연산자는 이진 주소가 아닌 특정 작업 (코드 라인)으로 이동합니다.
- 지점 작업은 비교를 수행하지 않습니다. 오히려 마지막 비교에서 출력을 가져와 실행합니다.
- 분기 및 점프 연산자는 0부터 시작하는 라인 번호 인덱싱 시스템을 사용합니다. (예 : JMP 0이 첫 번째 줄로 이동)
- 모든 연산은 0으로 오버 플로우되고 정수 오버 플로우에서 예외를 발생시키지 않는 부호없는 숫자에 대해 수행됩니다.
- 0으로 나누는 것은 허용되지 않으므로 프로그램의 동작은 정의되지 않습니다. 예를 들면 다음과 같습니다.
- 프로그램을 중단하십시오.
- VM의 실행을 종료하고 현재 상태를 반환합니다.
- "ERR : Division by 0"메시지를 표시하십시오.
- 프로그램 종료는 명령 포인터가 프로그램 끝에 도달 할 때와 같이 정의됩니다 (비 비어있는 프로그램을 가정 할 수 있음).
출력 출력은 정확히이 값이어야합니다 (줄 바꾸기 포함).
R0 3126900366
R1 0
R2 10000
포인트
포인트는 다음 공식을 기반으로 계산됩니다.Number Of Characters * (Seconds Needed To Run / 2)
다른 시간을 유발하는 하드웨어 차이를 피하기 위해 각 테스트는 우분투 서버 또는 Windows 8의 내 컴퓨터 (i5-4210u, 8GB 램)에서 실행되므로 Dual G5에서만 컴파일되는 미친 이국적인 런타임을 사용하지 마십시오 정확히 762.66MB의 사용 가능한 RAM이있는 Mac Pro.
특수한 런타임 / 언어를 사용하는 경우 링크를 게시하십시오.
- 관심있는 사람들을 위해 테스트 코드 (C #으로 작성)를 게시했습니다 : http://pastebin.com/WYCG5Uqu
테스트 프로그램
아이디어는 여기 에서 왔 으므로 약간 수정 된 버전의 프로그램을 사용합니다.
프로그램의 올바른 출력은 다음과 같습니다. 3,126,900,366
C에서 :
int s, i, j;
for (s = 0, i = 0; i < 10000; i++) {
for (j = 0; j < 10000; j++)
s += (i * j) / 3;
}
코드에서 : [R0은 s, j의 R1, i의 R2를 나타냄]
LOAD R0 0
LOAD R2 0 <--outer loop value
LOAD R1 0 <--inner loop value
--Begin inner loop--
PUSH R1 <--push inner loop value to the stack
MUL R1 R2 <--(i*j)
PUSH R2
LOAD R2 3
DIV R1 R2 <-- / 3
POP R2
ADD R0 R1 <-- s+=
POP R1
PUSH R2
LOAD R2 1
ADD R1 R2 <--j++
POP R2
PUSH R2
LOAD R2 10000
CMP R1 R2 <-- j < 10000
POP R2
BRANCHLT 3 <--Go back to beginning inner loop
--Drop To outer loop--
LOAD R1 1
ADD R2 R1 <--i++
LOAD R1 10000
CMP R2 R1 <-- i < 10000
LOAD R1 0 <--Reset inner loop
BRANCHLT 2
이진 / 육각으로 :
0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x02 0x00 0x00 0x00 0x00
0x00 0x01 0x00 0x00 0x00 0x00
0x02 0x01
0x06 0x01 0x02
0x02 0x02
0x00 0x02 0x00 0x00 0x00 0x03
0x07 0x01 0x02
0x03 0x02
0x04 0x00 0x01
0x03 0x01
0x02 0x02
0x00 0x02 0x00 0x00 0x00 0x01
0x04 0x01 0x02
0x03 0x02
0x02 0x02
0x00 0x02 0x00 0x00 0x27 0x10
0x09 0x01 0x02
0x03 0x02
0x0a 0x00 0x00 0x00 0x03
0x00 0x01 0x00 0x00 0x00 0x01
0x04 0x02 0x01
0x00 0x01 0x00 0x00 0x27 0x10
0x09 0x02 0x01
0x00 0x01 0x00 0x00 0x00 0x00
0x0a 0x00 0x00 0x00 0x02
보너스 포인트 (효과는 곱셈으로 적용됨) 예를 들어 세 가지 모두에 해당되는 경우 ((문자 * 0.50) * 0.75) * 0.90
- 인터프리터가 실제로 JIT 컴파일러 인 경우 50 % 감소
- 루프 언 롤링 / 의미있는 최적화를 적용하면 25 % 감소합니다.
- VM을 확장하면 10 % 감소
- BRANCHEQ [코드 라인, 4 바이트] (동일한 지점-opcode 0x0b)
- BRANCHGT [코드 라인, 4 바이트] (분기보다 큰 경우-opcode 0x0c)
- BRANCHNE [코드 라인, 4 바이트] (동일하지 않은 지점-opcode 0x0d)
- RLOAD [레지스터 1] [레지스터 2] (레지스터 2의 값을 이동하여 레지스터 1-opcode 0x01).
허용되지 않음
- 테스트 케이스를 프로그램에 사전 컴파일하는 것은 금지되어 있습니다. STDIN 또는 파일에서 바이트 코드를 승인해야합니다 (어떤 것이 든 상관 없습니다).
- 프로그램을 실행하지 않고 출력을 반환합니다.
- VM 요구 사항을 속이려는 다른 방법.
CMP
작거나 같은지 확인 합니까 ? 결과는 어떻게됩니까?
MUL
그리고 DIV
또한 underspecified된다. 서명 또는 서명이 없습니까? 곱셈 오버플로는 어떻게됩니까?