我们正在为高级编译语言编写字节码,经过一些分析和优化,很明显,当前最大的性能开销是我们用于跳转到字节码情况的switch语句。
我们研究了提取每个case标签的地址并将其存储在字节码本身的流中,而不是我们通常打开的指令ID。如果我们这样做,我们可以跳过跳转表,直接跳转到当前执行指令的代码位置。这在GCC中非常有效,但是MSVC似乎不支持这样的特性。
我们尝试使用内联汇编来获取标签的地址(并跳转到它们),它可以工作,但是,使用内联汇编会导致整个函数被MSVC优化器避免。
有没有一种方法可以让优化器仍然在代码上运行?不幸的是,我们不能将内联汇编提取到另一个函数中,而不是在其中创建标签的函数中,因为即使在内联汇编中也没有办法为另一个函数引用标签。有什么想法吗?非常感谢您的输入,谢谢!
4条答案
按热度按时间slwdgvem1#
在MSVC中实现这一点的唯一方法是使用内联汇编(这基本上会让你对x64产生错误):
如果你打算做这样的事情,那么最好的方法是在汇编中编写整个解释器,然后通过链接器将其链接到主二进制文件(这就是LuaJIT所做的,这也是VM如此快速的主要原因,当它不运行艾德代码时)。
LuaJIT is open-source,所以如果你走这条路,你可能会从中得到一些提示。或者,你可能想看看forth的源代码(它的创建者开发了你正在尝试使用的the principle),如果有一个MSVC构建,你可以看到他们是如何完成的,否则你会被GCC卡住(这不是一件坏事,它可以在所有主要平台上工作)。
eni9jsuy2#
看看Erlang在Windows上的构建。他们使用MSVC进行大部分构建,然后使用GCC进行一个文件,以利用标签作为值的扩展。然后对所得到的目标代码进行黑客攻击,使其与MSVC链接器兼容。
http://www.erlang.org/doc/installation_guide/INSTALL-WIN32.html
laawzig23#
看起来你可以把实际的代码移到函数上,而不是case标签上。然后字节码可以简单地转换成直接调用。例如,字节码1将转换为
CALL BC1
。由于您生成的是直接调用,因此没有函数指针的开销。大多数CPU的流水线可以遵循这样的无条件直接分支。结果,每个字节码的实际实现被优化,并且从字节码到机器码的转换是平凡的1:1转换。由于每个
CALL
是5个字节(假设是x86-32),所以代码扩展了一些,但这不太可能是一个大问题。3htmauhk4#
我发现的最好的方法是使用switch子句,然后为switch子句的每个元素编写后藤调用。
手动工作,但不使用汇编,看起来与MSVC兼容性良好。