页首横幅-已通过JIT编译(越低越好)
- es1024-81.2分(包括有效的编译器!)
- 基思·兰德尔-116点
- 病-121点
页首横幅-解读(越低越好)
- 马丁·布特纳(MartinBüttner)-706654点(大约2个小时左右)。
- ip割-30379点(97秒)
您的任务(如果您选择接受)是编写尽可能小的字节码解释器/ VM。VM /解释器使用以下指定的语言使用小型CISC架构(操作大小可能有所不同)。完成后,必须打印3个CPU寄存器的值,以证明打印了正确的输出(3,126,900,366)。
编译器
如果您想进行自己的测试,请在下面发布编译器。随时发布答案。
“ VM”规格
VM具有3个32位无符号整数寄存器:R0,R1,R2。它们以十六进制表示为0x00、0x01和0x02。
必须支持以下操作:
格式为[名称] [...操作数...],[十六进制操作码] [...操作数重复...]
- LOAD [寄存器] [4字节值],0x00 [寄存器] [4字节值]
- PUSH [寄存器],0x02 [寄存器]
- POP [寄存器],0x03 [寄存器]
- ADD [寄存器,1字节] [寄存器,1字节],0x04 [寄存器] [寄存器]
- SUB [寄存器,1字节] [寄存器,1字节],0x05 [寄存器] [寄存器]
- MUL [寄存器,1个字节] [寄存器,1个字节],0x06 [寄存器] [寄存器]
- DIV [寄存器,1个字节] [寄存器,1个字节],0x07 [寄存器] [寄存器]
- JMP [代码行,4字节],0x08 [4字节代码行号]
- CMP [寄存器,1个字节] [寄存器,1个字节],0x09 [寄存器] [寄存器]
- BRANCHLT [代码行,4字节],0x0a [4字节代码行号]
一些注意事项:
- 上面的数学运算将2个寄存器的值加在一起,将输出放在第一个寄存器中。
- CMP是比较运算符,应比较2个寄存器的值,并将输出存储在一些内部标志中(这可以是特定于实现的),以备将来在分支指令上使用。
- 如果在CMP之前调用了BRANCH,则除非调用了BRANCHEQ,否则“ VM”不应分支。
- PUSH / POP毫不奇怪地从堆栈中推入或弹出数字。
- 跳转和跳转运算符跳转到特定的操作(代码行),而不是二进制地址。
- 分支操作不进行比较。相反,他们从上一次比较中获取输出以执行。
- 分支和跳转运算符使用基于零的行号索引系统。(例如,JMP 0跳到第一行)
- 所有操作都将对无符号数字执行,该数字将溢出为零,并且在整数溢出时不会引发异常。
- 不允许除以零,因此,该程序的行为未定义。您可以(例如)...
- 使程序崩溃。
- 结束VM的执行并返回其当前状态。
- 显示“ ERR:被0除”的消息。
- 程序的终止定义为指令指针到达程序末尾(可以假定为非空程序)。
输出 输出必须与此完全相同(包括换行符)
R0 3126900366
R1 0
R2 10000
积分
积分是根据以下公式计算的:Number Of Characters * (Seconds Needed To Run / 2)
为避免硬件差异导致时间不同,每项测试都将在ubuntu服务器或Windows 8的计算机(i5-4210u,8GB内存)上运行,因此请不要使用仅在Dual G5上编译的疯狂异国运行时Mac Pro具有762.66 mb的可用RAM。
如果您使用的是专门的运行时/语言,请发布链接。
- 对于感兴趣的各方,我在此处发布了测试代码(用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字节](如果相等则为分支-操作码0x0b)
- BRANCHGT [代码行,4个字节](如果大于则为分支-操作码0x0c)
- BRANCHNE [代码行,4字节](如果不相等则为分支-操作码0x0d)
- RLOAD [寄存器1] [寄存器2](将寄存器2的值移动到寄存器1-操作码0x01)。
不允许的
- 禁止将测试用例预编译到程序中。您必须从STDIN或从文件接受字节码(无关紧要)。
- 不运行程序就返回输出。
- 您可以想到其他任何方法来欺骗VM需求。
CMP
检查小于或等于?结果如何?
MUL
并且DIV
也未指定。应该签名还是未签名?乘法溢出会发生什么?