"内联"关键字VS"内联"概念 [英] "inline" keyword vs "inlining" concept
问题描述
我问这个基本问题,使记录直。提到<一个href=\"http://stackoverflow.com/questions/1932311/when-to-use-inline-function-and-when-not-to-use-it\">this问题和其目前公认的答案,这是不能令人信服的。然而,第二大投票的答案提供更好的洞察力,但也不是完美的。
I am asking this basic question to make the records straight. Have referred this question and its currently accepted answer, which is not convincing. However the second most voted answer gives better insight, but not perfect either.
在阅读下文中,在线
的关键字的和内联区分的概念的。
While reading below, distinguish between the inline
keyword and "inlining" concept.
下面是我的看法:
这样做是为了拯救一个函数的调用开销。它更类似于宏观风格code更换。没什么好争议的。
This is done to save the call overhead of a function. It's more similar to macro-style code replacement. Nothing to be disputed.
的在线
关键字是的要求应用于通常用于更小的函数,编译器,让编译器可以优化,并做出更快的电话。编译器可以自由忽略它。
The
inline
keyword is a request to the compiler usually used for smaller functions, so that compiler can optimize it and make faster calls. The Compiler is free to ignore it.
我同意此观点,下面的原因:
I dispute this, for below reasons:
- 放大和递归函数不是内联和编译器忽略
在线
关键字。 - 较小的功能是由优化不论
在线
关键字自动内联被提及或没有。
- Larger and recursive functions are not inlined and the compiler ignores the
inline
keyword. - Smaller functions are automatically inlined by the optimizer irrespective of the
inline
keyword being mentioned or not.
这是相当清楚的是,用户不具有与使用关键字在函数内联任何控制在线
。
It's quite clear that the user doesn't have any control over function inlining with the use of keyword inline
.
在线
的的没有的做内联的概念。把在线
提前大/递归函数将不利于小功能,不再需要它,为内联。
inline
has nothing to do with the concept of inlining. Puttinginline
ahead of big / recursive function won't help and smaller function won't need it, for being inlined.
的仅的确定性使用在线
是保持的一
定义规则的
The only deterministic use of inline
is to maintain the One
Definition Rule.
即。如果一个函数的声明用在线
然后的只有的下面的东西都规定:
i.e. if a function is declared with inline
then only below things are mandated:
- 即使它的身体在多个翻译单元中(例如包括多种的头
的.cpp
文件),编译器将只产生1的定义,避免多个符号链接错误。 (注:如果该函数的机构不同,那么它是不确定的行为) - 在
内嵌的身体
函数可见/访问谁在使用它的所有翻译单元。换句话说,在.H
声明一个在线
功能和的任何一个的<定义code>的.cpp 文件将导致一个未定义的符号链接错误其他的.cpp
文件
- Even if its body is found in multiple translation units (e.g. include that header in multiple
.cpp
files), the compiler will generate only 1 definition and avoid multiple symbol linker error. (Note: If the bodies of that function are different then it is undefined behavior.) - The body of the
inline
function has to be visible / accessible in all the translation units who use it. In other words, declaring aninline
function in.h
and defining in any one.cpp
file will result in an "undefined symbol linker error" for other.cpp
files
在A的看法是完全的错误的和B的看法是完全的右键的
Verdict
The "A" perception is entirely wrong and the "B" perception is entirely right.
有在这个标准的一些报价,但我期待一个答案在逻辑上解释说,如果这判决是真还是假。
There are some quotes in standard on this, however I am expecting an answer which logically explains if this verdict is true or false.
推荐答案
我不知道你的要求:
小功能是自动优化内联,不论内嵌的被提及或不...
这是相当清楚的是,用户不必切换功能内联的使用关键字的任何控制在线
。
Smaller functions are automatically "inlined" by optimizer irrespective of inline is mentioned or not... It's quite clear that the user doesn't have any control over function "inlining" with the use of keyword
inline
.
我听说编译器可以自由地忽略你的在线
的要求,但我没想到他们完全不理会它。
I've heard that compilers are free to ignore your inline
request, but I didn't think they disregarded it completely.
我看着通过Github上存储库锵和LLVM找出来。 (感谢开源软件!)我发现的的在线
关键字的确实的制作锵/ LLVM更可能内联函数。
I looked through the Github repository for Clang and LLVM to find out. (Thanks, open source software!) I found out that The inline
keyword does make Clang/LLVM more likely to inline a function.
在搜索中在线 href=\"https://github.com/llvm-mirror/clang\">铛库线索令牌说明 kw_inline
。它看起来像锵用一个巧妙的基于宏的系统来构建词法分析器等关键字相关的功能,所以有提直接像如果(tokenString ==内联)返回kw_inline
被发现。但是,<一个href=\"https://github.com/llvm-mirror/clang/blob/f8fdd744441d83f7d65108f348a3311564dd4d88/lib/Parse/ParseDecl.cpp#L2999-3001\">Here在ParseDecl.cpp ,我们看到 kw_inline
的结果调用 DeclSpec :: setFunctionSpecInline()
Searching for the word inline
in the Clang repository leads to the token specifier kw_inline
. It looks like Clang uses a clever macro-based system to build the lexer and other keyword-related functions, so there's noting direct like if (tokenString == "inline") return kw_inline
to be found. But Here in ParseDecl.cpp, we see that kw_inline
results in a call to DeclSpec::setFunctionSpecInline()
.
case tok::kw_inline:
isInvalid = DS.setFunctionSpecInline(Loc, PrevSpec, DiagID);
break;
<一个href=\"https://github.com/llvm-mirror/clang/blob/773d19cce43a660639a26fca94ca387c2faf4d39/lib/Sema/DeclSpec.cpp#L780-792\">Inside该函数,我们设置了一下,发出一个警告,如果它是一个重复的在线
:
Inside that function, we set a bit and emit a warning if it's a duplicate inline
:
if (FS_inline_specified) {
DiagID = diag::warn_duplicate_declspec;
PrevSpec = "inline";
return true;
}
FS_inline_specified = true;
FS_inlineLoc = Loc;
return false;
搜索 FS_inline_specified
其他地方,我们看到它在一个比特单位和<一个href=\"https://github.com/llvm-mirror/clang/blob/773d19cce43a660639a26fca94ca387c2faf4d39/include/clang/Sema/DeclSpec.h#L556-558\">it's在一个getter函数使用 isInlineSpecified()
:
Searching for FS_inline_specified
elsewhere, we see it's a single bit in a bitfield, and it's used in a getter function, isInlineSpecified()
:
bool isInlineSpecified() const {
return FS_inline_specified | FS_forceinline_specified;
}
搜索 isInlineSpecified的调用点()
,我们发现<一个href=\"https://github.com/llvm-mirror/clang/blob/07f5b04be7e51fa08d0c263728d069572b497b97/lib/$c$cGen/$c$cGenFunction.cpp#L588-597\">the codeGEN ,在这里我们转换C ++语法树成LLVM中间再presentation:
Searching for call sites of isInlineSpecified()
, we find the codegen, where we convert the C++ parse tree into LLVM intermediate representation:
if (!CGM.getCodeGenOpts().NoInline) {
for (auto RI : FD->redecls())
if (RI->isInlineSpecified()) {
Fn->addFnAttr(llvm::Attribute::InlineHint);
break;
}
} else if (!FD->hasAttr<AlwaysInlineAttr>())
Fn->addFnAttr(llvm::Attribute::NoInline);
锵到LLVM
我们正与C ++语法分析阶段完成。现在,我们的在线
符转换为与语言无关的LLVM 功能
对象的属性。我们从锵切换到的LLVM库。
Clang to LLVM
We are done with the C++ parsing stage. Now our inline
specifier is converted to an attribute of the language-neutral LLVM Function
object. We switch from Clang to the LLVM repository.
搜索 LLVM ::属性:: InlineHint
yields 内联:: getInlineThreshold(调用点CS)
的(有一个可怕的前瞻性braceless 如果
块)的:
Searching for llvm::Attribute::InlineHint
yields the method Inliner::getInlineThreshold(CallSite CS)
(with a scary-looking braceless if
block):
// Listen to the inlinehint attribute when it would increase the threshold
// and the caller does not need to minimize its size.
Function *Callee = CS.getCalledFunction();
bool InlineHint = Callee && !Callee->isDeclaration() &&
Callee->getAttributes().hasAttribute(AttributeSet::FunctionIndex,
Attribute::InlineHint);
if (InlineHint && HintThreshold > thres
&& !Caller->getAttributes().hasAttribute(AttributeSet::FunctionIndex,
Attribute::MinSize))
thres = HintThreshold;
所以,我们已经从优化级别和其他因素的基线内联门槛,但如果它比全球低 HintThreshold
,我们碰到它。的(HintThreshold是在命令行设置的。)的
getInlineThreshold()
仅显示有<一个href=\"https://github.com/llvm-mirror/llvm/blob/3666e7f4c161c50e5f6dcb0e015ca16bf69fb941/lib/Transforms/IPO/InlineSimple.cpp#L54-56\">one通话网站,成员 SimpleInliner
:
InlineCost getInlineCost(CallSite CS) override {
return ICA->getInlineCost(CS, getInlineThreshold(CS));
}
它调用一个虚拟的方法,也叫 getInlineCost
,其成员指针的一个实例 InlineCostAnalysis
。
It calls a virtual method, also named getInlineCost
, on its member pointer to an instance of InlineCostAnalysis
.
搜索 :: getInlineCost()
来查找类成员的版本中,我们找到一个是成员 AlwaysInline
- 这是一个非标准的,但广泛的支持编译器的功能 - 而另一个是 InlineCostAnalysis
中的一员。它使用阈值
参数<一个href=\"https://github.com/llvm-mirror/llvm/blob/5401ba7099b9f3cd32b3399276b549bea15e5d1e/lib/Analysis/IPA/InlineCost.cpp#L1312-1313\">here:
Searching for ::getInlineCost()
to find the versions that are class members, we find one that's a member of AlwaysInline
- which is a non-standard but widely supported compiler feature - and another that's a member of InlineCostAnalysis
. It uses its Threshold
parameter here:
CallAnalyzer CA(Callee->getDataLayout(), *TTI, AT, *Callee, Threshold);
bool ShouldInline = CA.analyzeCall(CS);
CallAnalyzer :: analyzeCall()
超过200线和<一个href=\"https://github.com/llvm-mirror/llvm/blob/5401ba7099b9f3cd32b3399276b549bea15e5d1e/lib/Analysis/IPA/InlineCost.cpp#L986-1211\">does决定是否该函数是inlineable 的真正细节问题的工作。它的重量的因素很多,但是我们通过该方法阅读我们看到其所有计算或者操纵阈值
或成本
。并在最后:
CallAnalyzer::analyzeCall()
is over 200 lines and does the real nitty gritty work of deciding if the function is inlineable. It weighs many factors, but as we read through the method we see that all its computations either manipulate the Threshold
or the Cost
. And at the end:
return Cost < Threshold;
不过,名为 ShouldInline
返回值是真的名不副实。事实上 analyzeCall的主要目的是()
是设置成本
和阈值
在 CallAnalyzer
对象的成员变量。返回值仅表示当其他因素已覆盖成本VS阈值分析,<一的情况下href=\"https://github.com/llvm-mirror/llvm/blob/5401ba7099b9f3cd32b3399276b549bea15e5d1e/lib/Analysis/IPA/InlineCost.cpp#L1317-1321\">as我们在这里看到:
But the return value named ShouldInline
is really a misnomer. In fact the main purpose of analyzeCall()
is to set the Cost
and Threshold
member variables on the CallAnalyzer
object. The return value only indicates the case when some other factor has overridden the cost-vs-threshold analysis, as we see here:
// Check if there was a reason to force inlining or no inlining.
if (!ShouldInline && CA.getCost() < CA.getThreshold())
return InlineCost::getNever();
if (ShouldInline && CA.getCost() >= CA.getThreshold())
return InlineCost::getAlways();
否则,我们返回存储成本对象
和阈值
。
return llvm::InlineCost::get(CA.getCost(), CA.getThreshold());
所以我们不返回一个是或否在大多数情况下的决定。继续搜索!哪里是这个返回值 getInlineCost()
使用吗?
<一个href=\"https://github.com/llvm-mirror/llvm/blob/5401ba7099b9f3cd32b3399276b549bea15e5d1e/lib/Transforms/IPO/Inliner.cpp#L317\">It's在找到布尔内联:: shouldInline(调用点CS)
。另一个大的功能。它在一开始调用 getInlineCost()
的权利。
It's found in bool Inliner::shouldInline(CallSite CS)
. Another big function. It calls getInlineCost()
right at the beginning.
原来, getInlineCost
分析的内在的内联函数的成本 - 它的参数签名,code的长度,递归,分支,联动等 - 以及有关的每个将使用该函数的一些汇总信息。在另一方面, shouldInline()
结合有关的具体的在使用场所的作用更多的数据信息。
It turns out that getInlineCost
analyzes the intrinsic cost of inlining the function - its argument signature, code length, recursion, branching, linkage, etc. - and some aggregate information about every place the function is used. On the other hand, shouldInline()
combines this information with more data about a specific place where the function is used.
在整个方法有以 InlineCost :: costDelta()
通话 - 将使用 InlineCost
取值为计算由
。最后,我们回到一个 analyzeCall阈值
值()布尔
。决定作出。在内联:: runOnSCC()
:
Throughout the method there are calls to InlineCost::costDelta()
- which will use the InlineCost
s Threshold
value as computed by analyzeCall()
. Finally, we return a bool
. The decision is made. In Inliner::runOnSCC()
:
if (!shouldInline(CS)) {
emitOptimizationRemarkMissed(CallerCtx, DEBUG_TYPE, *Caller, DLoc,
Twine(Callee->getName() +
" will not be inlined into " +
Caller->getName()));
continue;
}
// Attempt to inline the function.
if (!InlineCallIfPossible(CS, InlineInfo, InlinedArrayAllocas,
InlineHistoryID, InsertLifetime, DL)) {
emitOptimizationRemarkMissed(CallerCtx, DEBUG_TYPE, *Caller, DLoc,
Twine(Callee->getName() +
" will not be inlined into " +
Caller->getName()));
continue;
}
++NumInlined;
InlineCallIfPossible()
确实根据 shouldInline内联()的决定。
所以阈值
是受在线
关键字,并最终被用于决定是否内联
So the Threshold
was affected by the inline
keyword, and is used in the end to decide whether to inline.
因此,你的感知B是部分错误的,因为至少有一个主要的编译器改变根据在线
关键字及其优化行为。
Therefore, your Perception B is partly wrong because at least one major compiler changes its optimization behavior based on the inline
keyword.
但是,我们还可以看到,在线
只是一个提示,以及其他因素可能超过它。
However, we can also see that inline
is only a hint, and other factors may outweigh it.
这篇关于&QUOT;内联&QUOT;关键字VS&QUOT;内联&QUOT;概念的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!