assembly 标签地址(MSVC)

mhd8tkvw  于 2023-05-07  发布在  其他
关注(0)|答案(4)|浏览(182)

我们正在为高级编译语言编写字节码,经过一些分析和优化,很明显,当前最大的性能开销是我们用于跳转到字节码情况的switch语句。
我们研究了提取每个case标签的地址并将其存储在字节码本身的流中,而不是我们通常打开的指令ID。如果我们这样做,我们可以跳过跳转表,直接跳转到当前执行指令的代码位置。这在GCC中非常有效,但是MSVC似乎不支持这样的特性。
我们尝试使用内联汇编来获取标签的地址(并跳转到它们),它可以工作,但是,使用内联汇编会导致整个函数被MSVC优化器避免。
有没有一种方法可以让优化器仍然在代码上运行?不幸的是,我们不能将内联汇编提取到另一个函数中,而不是在其中创建标签的函数中,因为即使在内联汇编中也没有办法为另一个函数引用标签。有什么想法吗?非常感谢您的输入,谢谢!

slwdgvem

slwdgvem1#

在MSVC中实现这一点的唯一方法是使用内联汇编(这基本上会让你对x64产生错误):

int _tmain(int argc, _TCHAR* argv[])
{
case_1:
    void* p;
    __asm{ mov [p],offset case_1 }
    printf("0x%p\n",p);
    return 0;
}

如果你打算做这样的事情,那么最好的方法是在汇编中编写整个解释器,然后通过链接器将其链接到主二进制文件(这就是LuaJIT所做的,这也是VM如此快速的主要原因,当它不运行艾德代码时)。
LuaJIT is open-source,所以如果你走这条路,你可能会从中得到一些提示。或者,你可能想看看forth的源代码(它的创建者开发了你正在尝试使用的the principle),如果有一个MSVC构建,你可以看到他们是如何完成的,否则你会被GCC卡住(这不是一件坏事,它可以在所有主要平台上工作)。

eni9jsuy

eni9jsuy2#

看看Erlang在Windows上的构建。他们使用MSVC进行大部分构建,然后使用GCC进行一个文件,以利用标签作为值的扩展。然后对所得到的目标代码进行黑客攻击,使其与MSVC链接器兼容。
http://www.erlang.org/doc/installation_guide/INSTALL-WIN32.html

laawzig2

laawzig23#

看起来你可以把实际的代码移到函数上,而不是case标签上。然后字节码可以简单地转换成直接调用。例如,字节码1将转换为CALL BC1。由于您生成的是直接调用,因此没有函数指针的开销。大多数CPU的流水线可以遵循这样的无条件直接分支。
结果,每个字节码的实际实现被优化,并且从字节码到机器码的转换是平凡的1:1转换。由于每个CALL是5个字节(假设是x86-32),所以代码扩展了一些,但这不太可能是一个大问题。

3htmauhk

3htmauhk4#

我发现的最好的方法是使用switch子句,然后为switch子句的每个元素编写后藤调用。

lablcmd1:
// code
goto dispach;
. . .

dispatch:
op = NextOp();
switch(op){
    case CMD1:
      goto lablcmd1;
    // default: __assume(false); // maybe necessary, verify
}

手动工作,但不使用汇编,看起来与MSVC兼容性良好。

相关问题