jjzjj

c++ - 优化处理标签(空结构)函数参数

coder 2024-02-23 原文

在某些情况下,我们使用标签来区分功能。标签通常是一个空结构:

struct Tag { };

假设我有一个函数,它使用这个标签:

void func(Tag, int a);

现在,让我们调用这个函数:

func(Tag(), 42);

并检查生成的 x86-64 反汇编,godbolt :

mov     edi, 42
jmp     func(Tag, int)            # TAILCALL

很好,标签被完全优化掉了:没有为它分配寄存器/堆栈空间。

但是,如果我查看其他平台,就会发现该标签存在。

在 ARM 上,r0 被用作标签,它被清零(似乎没有必要):

mov     r1, #42
mov     r0, #0
b       func(Tag, int)

在 MSVC 中,ecx 被用作标签,并且它是从堆栈“初始化”的(同样,似乎没有必要):

movzx   ecx, BYTE PTR $T1[rsp]
mov     edx, 42                             ; 0000002aH
jmp     void func(Tag,int)                 ; func

我的问题是:是否存在在所有这些平台上同样优化的标记技术?


注意:我没有找到 SysV ABI 在哪里指定空类可以在参数传递时被优化掉...(甚至,Itanium C++ ABI 说:“空类的传递与普通类没有区别” .)

最佳答案

我认为这里的基本问题是,在生成函数的独立版本时,编译器必须根据各自的调用约定生成可供任何人从任何地方调用的代码。当在不知道其定义的情况下生成对函数的调用时,编译器真正知道的只是该函数期望根据调用约定被调用。基于此,似乎除非调用约定指定删除空类型的函数参数,否则编译器通常无法真正优化函数调用中的参数。现在,C++ 编译器在现场为给定的函数签名制定它认为合适的任何调用约定在技术上可能是合法的,除非该函数具有非 C++ 语言链接(例如,extern "C"功能)。但在实践中,这很可能不会那么简单。首先,您需要一种算法来确定给定函数签名的最佳调用约定通常是什么样的。其次,使用完全相同的标志链接不一定全部由完全相同版本的完全相同编译器生成的代码的能力虽然不是 C++ 标准所要求的,但在实践中可能是相关的。函数调用约定优化当然不是不可能的。但我不知道有任何实际执行此操作的 C++ 编译器(在生成目标代码时)。

一个可能的解决方案是,例如,为实际函数实现使用不同的名称,并使用简单的内联包装函数将带有标签类型的调用转换为相应的实现:

struct TagA { };
struct TagB { };

inline void func(int a, TagA)
{
    void funcA(int a);
    funcA(a);
}

inline void func(int a, TagB)
{
    void funcB(int a);
    funcB(a);
}

void call() {
    func(42, TagA());
    func(42, TagB());
}

try it out here

另请注意,虽然编译器可能会生成类似于初始目标文件中的函数调用,但链接时优化最终可能能够摆脱未使用的参数。至少一个主要编译器甚至 documents这样的行为……

关于c++ - 优化处理标签(空结构)函数参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55303927/

有关c++ - 优化处理标签(空结构)函数参数的更多相关文章

  1. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  2. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  3. ruby-on-rails - 如何在 ruby​​ 中使用两个参数异步运行 exe? - 2

    exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby​​中使用两个参数异步运行exe吗?我已经尝试过ruby​​命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何ruby​​gems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除

  4. ruby - 在院子里用@param 标签警告 - 2

    我试图使用yard记录一些Ruby代码,尽管我所做的正是所描述的here或here#@param[Integer]thenumberoftrials(>=0)#@param[Float]successprobabilityineachtrialdefinitialize(n,p)#initialize...end虽然我仍然得到这个奇怪的错误@paramtaghasunknownparametername:the@paramtaghasunknownparametername:success然后生成的html看起来很奇怪。我称yard为:$yarddoc-mmarkdown我做错了什么?

  5. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  6. ruby - RSpec - 使用测试替身作为 block 参数 - 2

    我有一些Ruby代码,如下所示:Something.createdo|x|x.foo=barend我想编写一个测试,它使用double代替block参数x,这样我就可以调用:x_double.should_receive(:foo).with("whatever").这可能吗? 最佳答案 specify'something'dox=doublex.should_receive(:foo=).with("whatever")Something.should_receive(:create).and_yield(x)#callthere

  7. ruby - 如何在 Ruby 中拆分参数字符串 Bash 样式? - 2

    我正在为一个项目制作一个简单的shell,我希望像在Bash中一样解析参数字符串。foobar"helloworld"fooz应该变成:["foo","bar","helloworld","fooz"]等等。到目前为止,我一直在使用CSV::parse_line,将列分隔符设置为""和.compact输出。问题是我现在必须选择是要支持单引号还是双引号。CSV不支持超过一个分隔符。Python有一个名为shlex的模块:>>>shlex.split("Test'helloworld'foo")['Test','helloworld','foo']>>>shlex.split('Test"

  8. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

    我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

  9. ruby - 检查方法参数的类型 - 2

    我不确定传递给方法的对象的类型是否正确。我可能会将一个字符串传递给一个只能处理整数的函数。某种运行时保证怎么样?我看不到比以下更好的选择:defsomeFixNumMangler(input)raise"wrongtype:integerrequired"unlessinput.class==FixNumother_stuffend有更好的选择吗? 最佳答案 使用Kernel#Integer在使用之前转换输入的方法。当无法以任何合理的方式将输入转换为整数时,它将引发ArgumentError。defmy_method(number)

  10. ruby-on-rails - 在默认方法参数中使用 .reverse_merge 或 .merge - 2

    两者都可以defsetup(options={})options.reverse_merge:size=>25,:velocity=>10end和defsetup(options={}){:size=>25,:velocity=>10}.merge(options)end在方法的参数中分配默认值。问题是:哪个更好?您更愿意使用哪一个?在性能、代码可读性或其他方面有什么不同吗?编辑:我无意中添加了bang(!)...并不是要询问nobang方法与bang方法之间的区别 最佳答案 我倾向于使用reverse_merge方法:option

随机推荐