问题标签 [inlining]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
1 回答
518 浏览

c++ - 了解 C++ 函数内联

我正在使用特定于 MS 的关键字来强制内联全局函数,但我注意到如果该函数使用具有显式平凡析构函数的对象,则该函数无法内联自身。

引用MSDN

即使使用__forceinline,编译器也不能在所有情况下内联代码。如果出现以下情况,编译器不能内联函数:

  • 该函数或其调用者是用/Ob0(调试构建的默认选项)编译的。

  • 函数和调用者使用不同类型的异常处理(一种是 C++ 异常处理,另一种是结构化异常处理)。

  • 该函数有一个可变参数列表。

  • 该函数使用内联汇编,除非使用/Og/Ox/O1或编译/O2

  • 该函数是递归的,不伴随#pragma inline_recursion(on). 使用 pragma,递归函数被内联到 16 个调用的默认深度。要减少内联深度,请使用inline_depthpragma。

  • 该函数是虚拟的,并且被虚拟调用。可以内联对虚拟函数的直接调用。

  • 程序获取函数的地址,并通过指向函数的指针进行调用。可以内联对已获取地址的函数的直接调用。

  • 该函数还标有裸__declspec修饰符。

我正在尝试以下自包含程序来测试行为

有了简单的析构函数INLINE ~Spam() {},我们有以下反汇编

在没有析构函数的情况下,INLINE ~Spam() {}我们有以下反汇编

我无法理解,为什么在存在析构函数的情况下,编译器无法内联函数T movz(T& t)

  • 注意行为从 2008 年到 2013 年是一致的
  • 注意我检查了 cygwin-gcc 但编译器确实内联了代码。我目前无法验证其他编译器,但如果需要,我会在接下来的 12 小时内更新
0 投票
3 回答
200 浏览

java - 可见性和 javac / JVM 内联

方法/字段可见性如何影响 Java 中的方法内联?

我想到的情况类似于字段的public吸气剂private

这里出现了几个问题。

一方面,Java 编译器本身是否进行内联?这个问题似乎有不同的回答,有人说,有人说不是。我不知道那是因为它以前不做任何内联,但现在做了,还是只是有些人是对的,有些人是错的......

现在,如果它确实做了一些内联,我是否认为它不可能内联getBlah()调用?它们显然是内联有用的地方,因为该方法非常简单,并且调用方法的开销与方法本身的代码一样大。但是如果它被编译器内联,你最终会得到private直接访问字段的字节码;那么JVM肯定会抱怨吗?(即使这种方法是 . 也适用static final。)

其次,JIT 编译器呢?据我所知,当涉及到该级别的内联时,这个问题并不适用。一旦生成本机代码,JVM 就已经完成了检查,并确认我可以调用该方法(因为它是public);因此它可以生成内联调用的本机代码,而不会出现任何可见性问题......是吗?

0 投票
2 回答
2422 浏览

haskell - 函数式语言中的部分求值和函数内联有什么区别?

0 投票
1 回答
286 浏览

parameters - 查找使用的 simulink 参数

我正在寻找一种可能性来获取子系统中所有使用参数的列表。这是同一个列表,simulink 编码器在启动子系统的 s-Function 构建时显示。 f14-demo-model 示例

参数几乎可以存在于每个块中(增益、查找表、状态、常数...),也可以存在于嵌入式状态流中。

我的第一个想法是启动一个“find_system”来获取所有增益块,然后逐步检查它们的参数。但这似乎很复杂,因为我必须使用不同的有趣参数(增益=增益;查找表:表数据、断点数据...)检查每个块类型。我也不知道如何在状态流中查找参数。

是否有更简单的方法来获取所有使用的参数?

非常感谢。

0 投票
0 回答
64 浏览

haskell - 内联重复调用 (GHC)

GHC 会内联一个多次使用的函数吗?例如:

如果我们调用g innerLoop该函数innerLoop是否会重复三次?还是会变成这样g stuff...

我们如何才能强制innerLoop多次内联或防止它被多次内联?

0 投票
1 回答
444 浏览

c++ - Calls that precede a function's definition cannot be inlined?

The gcc documentation contains the following:

When a function is both inline and static, if all calls to the function are integrated into the caller, and the function's address is never used, then the function's own assembler code is never referenced. In this case, GCC does not actually output assembler code for the function, unless you specify the option -fkeep-inline-functions. Some calls cannot be integrated for various reasons (in particular, calls that precede the function's definition cannot be integrated, and neither can recursive calls within the definition).

That always sounded absurd to me -- why would a modern compiler be that dumb? After a quick test it does seem untrue.

The test code:

The result with gcc-4.9.2 on Linux contains code for bar() but none for foo(). You can see that foo() has been integrated:

If I compile as C++ the result is the same, except for name mangling.

Contrary to the documentation, despite foo() being defined after the call in bar(), foo() has been completely integrated into bar().

Do I misunderstand the documentation or is it incorrect? Perhaps it's correct for some more complicated case?

I don't know if there's a technical distinction between "integrate" and "inline" but I suspect "integrate" is being used to distinguish from keyword inline and it just refers to function inlining (hence the title).

This question is tagged as C and C++ because this portion of the gcc documentation pertains to the "C language family" and I expect the answer to be the same for the two languages.

0 投票
1 回答
57 浏览

c++ - 用户指定函数的内联

我目前正在编写一个模拟软件。我有一个相对复杂的算子要计算,有几个参数。其中一个参数可以是用户指定的非线性函数。就像是:

由于该函数将被多次调用,因此我想使编译器能够内联该函数。幸运的是,该函数可以在调用时进行硬编码op。Sou 我总是会有类似函数名称op(1.0, 2.0, ..., nonlinear1)在哪里nonlinear1而不是变量或其他东西的东西。

我在想两个想法:

  1. 函数指针double (*)(double):不起作用。
  2. 模板参数:

如下:

乍一看这似乎可行,但编译器是否真的知道 FCT 对象背后的函数,还是只看到函数指针和返回/参数规范?

我还能如何实现我想要的?

0 投票
2 回答
41 浏览

c++ - 当我可以将对象的实际类型指定为模板参数时,内联虚函数

我有一个虚拟类Calculator和该类的示例实现MyCalculator

当我使用op1()如下函数演示时,编译器当然不能内联op1(),因为它是虚拟的:

然而,在某些情况下,我知道calcAND 的实际类型,出于性能原因我想内联它。于是我想到了下面的想法:

我会调用这个函数,如下所示:

在第一个示例中,内联是不可能的,但我认为在第二个示例中,op1()ofMyCalculator应该内联 inside calculate()

我的假设是真的吗?

0 投票
2 回答
863 浏览

c - gcc 性能大幅下降,可能与内联有关

我目前正在经历一些奇怪的效果gcc(测试版本:4.8.4)。

我有一个面向性能的代码,它运行得非常快。它的速度在很大程度上取决于内联许多小函数。

由于跨多个.c文件的内联很困难(-flto尚未广泛使用),我将许多小函数(通常每个 1 到 5 行代码)保存到一个通用 C 文件中,我正在其中开发一个编解码器,并且其相关的解码器。按照我的标准,它“相对”大(大约 2000 行,尽管其中很多只是注释和空白行),但是将其分成更小的部分会带来新的问题,所以如果可能的话,我宁愿避免这种情况。

编码器和解码器是相关的,因为它们是逆运算。但是从编程的角度来看,它们是完全分开的,除了一些 typedef 和非常低级的函数(例如从未对齐的内存位置读取)之外,没有任何共同之处。

奇怪的效果是这样的:

我最近fnew在编码器端添加了一个新功能。这是一个新的“入口点”。它既不使用也不从.c文件中的任何地方调用。

它存在的简单事实使得解码器功能的性能fdec大幅下降,下降超过 20%,这是太多不容忽视的。

现在,请记住,编码和解码操作是完全分离的,几乎不共享任何内容,保存一些次要的typedef(u32u16) 和相关的操作 (读/写)。

当将新的编码函数定义fnewstatic时,解码器的性能fdec恢复正常。由于fnew没有从 中调用.c,我猜它就像它不存在一样(死代码消除)。

如果static fnew现在从编码器端调用,性能fdec仍然很强。

但是一旦fnew修改,fdec性能就会大幅下降。

假设fnew修改超过了一个阈值,我增加了以下gcc参数:(--param max-inline-insns-auto=60默认情况下,它的值应该是 40。)它起作用了:性能fdec现在恢复正常。

而且我猜这个游戏将永远持续下去,每一个小小的修改fnew或任何类似的东西,都需要进一步的调整。

这简直太奇怪了。函数中的一些小修改没有逻辑上的理由fnew对完全不相关的函数产生连锁反应fdec,唯一的关系是在同一个文件中。

到目前为止,我可以发明的唯一试探性解释是,也许简单的存在fnew就足以跨越某种global file threshold会影响fdec. fnew可以在以下情况下“不存在”:1. 不存在,2.static但不能从任何地方调用 3.static并且足够小可以内联。但这只是隐藏了问题。这是否意味着我不能添加任何新功能?

真的,我在网上找不到任何令人满意的解释。

我很想知道是否有人已经经历了一些等效的副作用,并找到了解决方案。

[编辑]

让我们进行一些更疯狂的测试。现在我正在添加另一个完全无用的功能,只是为了玩。它的内容严格来说就是 的复制粘贴fnew,但是函数的名称明显不同,所以我们称之为wtf

存在时,是否为静态wtf无关紧要, : 的值是多少,性能恢复正常。即使不使用也不从任何地方调用...... :'(fnewmax-inline-insns-autofdecwtf

[编辑 2] 没有inline说明。所有功能要么正常要么static。内联决策完全在编译器的范围内,到目前为止效果很好。

[编辑 3] 正如 Peter Cordes 所建议的,这个问题与内联无关,而是与指令对齐有关。在较新的 Intel cpu(Sandy Bridge 和更高版本)上,热循环受益于在 32 字节边界上对齐。问题是,默认情况下,gcc将它们对齐在 16 字节的边界上。根据先前代码的长度,有 50% 的机会进行正确对齐。因此,这是一个难以理解的问题,“看起来很随机”。

并非所有循环都是敏感的。它只对关键循环很重要,并且只有当它们的长度使它们在不太理想的对齐时越过一个 32 字节的指令段时才有意义。

0 投票
1 回答
289 浏览

postgresql - PostgreSQL 使用 OFFSET 0 防止子查询内联

我在 where 子句中有一个子查询,每次评估时都会扫描整个表。

当我将 OFFSET 0 添加到子查询的末尾时,查询计划没有变化。

参考这篇文章。在这种情况下,优化围栏“OFFSET 0”在 where 子句中不起作用吗?