【问题标题】:Address of labels (MSVC)标签地址 (MSVC)
【发布时间】:2011-09-19 06:28:36
【问题描述】:

我们正在为高级编译语言编写字节码,经过一些分析和优化后,很明显当前最大的性能开销是我们用来跳转到字节的 switch 语句-代码案例。

我们调查了提取每个案例标签的地址并将其存储在字节码流本身中,而不是我们通常打开的指令 ID。如果这样做,我们可以跳过跳转表,直接跳转到当前执行指令的代码位置。这在 GCC 中非常有效,但是,MSVC 似乎不支持这样的功能。

我们尝试使用内联汇编来获取标签的地址(并跳转到它们),它可以工作,但是,使用内联汇编会导致整个函数被 MSVC 优化器避免。

有没有办法让优化器仍然在代码上运行?不幸的是,我们无法将内联汇编提取到另一个函数中,而不是制作标签的那个函数,因为即使在内联汇编中也无法引用另一个函数的标签。有什么想法或想法吗?非常感谢您的意见,谢谢!

【问题讨论】:

  • 你试过函数指针吗?
  • 在字节码中放置函数地址而不是标签地址如何?然后,每个指令 ID 都有一个函数。除非您的 fetch-execute 循环在您的带有标签的大函数中。
  • 如果我对每种情况都使用函数并使用函数指针而不是标签地址,它会起作用。但是,我觉得函数调用开销太大了,以至于它会抵消任何性能提升,即使函数是微不足道的(没有参数,没有返回)。不过我会尝试一下,感谢您的发帖。
  • 如果我对您正在使用的硬件的猜测正确,那么函数调用开销的问题是间接分支引起的管道泡沫,在某些情况下无法预测-订购 PowerPC 处理器。但是无论如何,您仍然会遇到带有计算 goto 的相同气泡——事实上,在 ABI 级别,函数指针 is 是计算 goto。如果您使用 FASTCALL 约定,函数参数将在寄存器中传递,因此它们不会影响整体运行时间,因为 mov 无论如何都适合间接气泡。
  • @Rovert 虽然这对你来说为时已晚,但对于未来的读者来说:当涉及到低级性能时,你应该假设 nothing 并基准 everything我>。您可能是对的,但是您应该检查并重新检查每个新的 architecture 和编译器 version,因为它可能会发生变化。

标签: c++ assembly label inline-assembly goto


【解决方案1】:

在 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 所做的,这是导致虚拟机的速度非常快,当它没有运行 JIT 代码时)。

LuaJIT is open-source,所以如果你走那条路,你可能会从中得到一些提示。或者,您可能想查看 forth 的来源(其创建者开发了您正在尝试使用的the principle),如果有 MSVC 构建,您可以看到他们是如何完成它的,否则您会被 GCC 困住(其中 不是坏事,它适用于所有主要平台)。

【讨论】:

    【解决方案2】:

    看看 Erlang 为在 Windows 上构建所做的工作。他们在大部分构建中使用 MSVC,然后在一个文件中使用 GCC,以使用标签作为值扩展。然后破解生成的目标代码以与 MSVC 链接器兼容。

    http://www.erlang.org/doc/installation_guide/INSTALL-WIN32.html

    【讨论】:

    • 这就是我们用 watcom 编译器做了二十年的事情。它非常适合 i386 代码指定输入/输出寄存器,并且可以进行大量内部调整。它在 watcom 上编译、反汇编、提取和后处理程序集并填充其他代码。这是一个好主意,除非您的客户开始询问他们是否可以自行扩展语言....您不想公开 C 编译器的需求(除非它是 tinycc)。
    【解决方案3】:

    您似乎可以将实际代码移至函数,而不是大小写标签。然后可以将字节码简单地转换为直接调用。 IE。字节码 1 将转换为 CALL BC1。由于您正在生成直接调用,因此您没有函数指针的开销。大多数 CPU 的流水线都可以遵循这种无条件的直接分支。

    因此,每个字节码的实际实现都得到了优化,从字节码到机器码的转换是微不足道的 1:1 转换。你会得到一些代码扩展,因为每个 CALL 是 5 个字节(假设 x86-32),但这不太可能是一个主要问题。

    【讨论】:

      猜你喜欢
      • 2017-12-22
      • 1970-01-01
      • 2021-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多