草庐IT

c++ - avr-gcc:(看似)简单功能中不需要的序言/结尾

coder 2024-02-01 原文

当尝试处理 uint64 中的单个字节时,AVR gcc⁽¹⁾ 给我一个奇怪的序言/结尾,而使用 uint32_t 编写的相同函数给了我一个单个 ret(示例函数是 NOP)。

为什么 gcc 这样做?我该如何删除它?

You can see the code here, in Compiler Explorer .

⁽¹⁾ 来自 Arduino 1.8.9 发行版的 gcc 5.4.0,参数 =-O3 -std=c++11

源代码:

#include <stdint.h>

uint32_t f_u32(uint32_t x) {
  union y {
    uint8_t p[4];
    uint32_t w;
  };
  return y{ .p = {
    y{ .w = x }.p[0],
    y{ .w = x }.p[1],
    y{ .w = x }.p[2],
    y{ .w = x }.p[3]
  } }.w;
}

uint64_t f_u64(uint64_t x) {
  union y {
    uint8_t p[8];
    uint64_t w;
  };
  return y{ .p = {
    y{ .w = x }.p[0],
    y{ .w = x }.p[1],
    y{ .w = x }.p[2],
    y{ .w = x }.p[3],
    y{ .w = x }.p[4],
    y{ .w = x }.p[5],
    y{ .w = x }.p[6],
    y{ .w = x }.p[7]
  } }.w;
}

uint32_t 版本生成的程序集:

f_u32(unsigned long):
  ret

uint64_t 版本生成的程序集:

f_u64(unsigned long long):
  push r28
  push r29
  in r28,__SP_L__
  in r29,__SP_H__
  subi r28,72
  sbc r29,__zero_reg__
  in __tmp_reg__,__SREG__
  cli
  out __SP_H__,r29
  out __SREG__,__tmp_reg__
  out __SP_L__,r28
  subi r28,-72
  sbci r29,-1
  in __tmp_reg__,__SREG__
  cli
  out __SP_H__,r29
  out __SREG__,__tmp_reg__
  out __SP_L__,r28
  pop r29
  pop r28
  ret

最佳答案

我不确定这是否是一个好的答案,但这是我能给出的最好答案。 f_u64() 函数的程序集在堆栈上分配 72 个字节,然后再次释放它们(因为这涉及寄存器 r28r29,它们开始保存,最后恢复)。

如果您尝试在没有优化的情况下进行编译(我也跳过了 c++11 标志,我认为这没有任何区别),那么您将看到 f_u64() 函数首先在堆栈上分配 80 个字节(类似于您在优化代码中看到的开头语句,只是使用 80 个字节而不是 72 个字节):

    in r28,__SP_L__
    in r29,__SP_H__
    subi r28,80
    sbc r29,__zero_reg__
    in __tmp_reg__,__SREG__
    cli
    out __SP_H__,r29
    out __SREG__,__tmp_reg__
    out __SP_L__,r28

这80个字节其实都用上了。首先存储参数 x 的值(8 个字节),然后进行涉及剩余 72 个字节的大量移动数据。

之后这 80 个字节被释放到堆栈上,类似于优化代码中的关闭语句:

    subi r28,-80
    sbci r29,-1
    in __tmp_reg__,__SREG__
    cli
    out __SP_H__,r29
    out __SREG__,__tmp_reg__
    out __SP_L__,r28

我的猜测是优化器认为可以节省用于存储参数的 8 个字节。因此它只需要 72 个字节。然后它得出结论,所有数据的移动都可以幸免。然而,它没有弄清楚这意味着堆栈上的72字节可以被节省下来。

因此,我最好的选择是这是优化器中的限制或错误(无论您喜欢如何调用它)。在这种情况下,唯一的“解决方案”是尝试打乱真正的代码以找到解决方法或将其作为编译器错误引发。

关于c++ - avr-gcc:(看似)简单功能中不需要的序言/结尾,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57780290/

有关c++ - avr-gcc:(看似)简单功能中不需要的序言/结尾的更多相关文章

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

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

  2. ruby-on-rails - 无法在centos上安装therubyracer(V8和GCC出错) - 2

    我正在尝试在我的centos服务器上安装therubyracer,但遇到了麻烦。$geminstalltherubyracerBuildingnativeextensions.Thiscouldtakeawhile...ERROR:Errorinstallingtherubyracer:ERROR:Failedtobuildgemnativeextension./usr/local/rvm/rubies/ruby-1.9.3-p125/bin/rubyextconf.rbcheckingformain()in-lpthread...yescheckingforv8.h...no***e

  3. ruby-on-rails - Cucumber 是否只是 rspec 的包装器以帮助将测试组织成功能? - 2

    只是想确保我理解了事情。据我目前收集到的信息,Cucumber只是一个“包装器”,或者是一种通过将事物分类为功能和步骤来组织测试的好方法,其中实际的单元测试处于步骤阶段。它允许您根据事物的工作方式组织您的测试。对吗? 最佳答案 有点。它是一种组织测试的方式,但不仅如此。它的行为就像最初的Rails集成测试一样,但更易于使用。这里最大的好处是您的session在整个Scenario中保持透明。关于Cucumber的另一件事是您(应该)从使用您的代码的浏览器或客户端的角度进行测试。如果您愿意,您可以使用步骤来构建对象和设置状态,但通常您

  4. ruby - 为什么在 ruby​​ 中创建 Rational 不需要新方法 - 2

    这个问题在这里已经有了答案:关闭10年前。PossibleDuplicate:Rubysyntaxquestion:Rational(a,b)andRational.new!(a,b)我正在阅读ruby镐书,我对创建有理数的语法感到困惑。Rational(3,4)*Rational(1,2)产生=>3/8为什么Rational不需要new方法(我还注意到例如我可以在没有new方法的情况下创建字符串)?

  5. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  6. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  7. arrays - Ruby 数组 += vs 推送 - 2

    我有一个数组数组,想将元素附加到子数组。+=做我想做的,但我想了解为什么push不做。我期望的行为(并与+=一起工作):b=Array.new(3,[])b[0]+=["apple"]b[1]+=["orange"]b[2]+=["frog"]b=>[["苹果"],["橙子"],["Frog"]]通过推送,我将推送的元素附加到每个子数组(为什么?):a=Array.new(3,[])a[0].push("apple")a[1].push("orange")a[2].push("frog")a=>[[“苹果”、“橙子”、“Frog”]、[“苹果”、“橙子”、“Frog”]、[“苹果”、“

  8. ruby-on-rails - rails 功能测试 - 2

    在Rails自动生成的功能测试(test/functional/products_controller_test.rb)中,我看到以下代码:classProductsControllerTest我的问题是:方法调用products()在哪里/如何定义?products(:one)到底是什么意思?看代码,大概意思是“创建一个产品”,但是它是如何工作的呢?注意我是Ruby/Rails的新手,如果这些是微不足道的问题,我深表歉意。 最佳答案 如果您查看test/fixtures文件夹,您会看到一个products.yml文件。这是在您创建

  9. += 的 Ruby 方法 - 2

    有没有办法让Ruby能够做这样的事情?classPlane@moved=0@x=0defx+=(v)#thisiserror@x+=v@moved+=1enddefto_s"moved#{@moved}times,currentxis#{@x}"endendplane=Plane.newplane.x+=5plane.x+=10putsplane.to_s#moved2times,currentxis15 最佳答案 您不能在Ruby中覆盖复合赋值运算符。任务在内部处理。您应该覆盖+,而不是+=。plane.a+=b与plane.a=

  10. ruby - Sinatra + Heroku + Datamapper 使用 dm-sqlite-adapter 部署问题 - 2

    出于某种原因,heroku尝试要求dm-sqlite-adapter,即使它应该在这里使用Postgres。请注意,这发生在我打开任何URL时-而不是在gitpush本身期间。我构建了一个默认的Facebook应用程序。gem文件:source:gemcuttergem"foreman"gem"sinatra"gem"mogli"gem"json"gem"httparty"gem"thin"gem"data_mapper"gem"heroku"group:productiondogem"pg"gem"dm-postgres-adapter"endgroup:development,:t

随机推荐