"内联"关键字VS"内联"概念 [英] "inline" keyword vs "inlining" concept

查看:147
本文介绍了"内联"关键字VS"内联"概念的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我问这个基本问题,使记录直。提到<一个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:


  1. 放大和递归函数不是内联和编译器忽略在线关键字。

  2. 较小的功能是由优化不论在线关键字自动内联被提及或没有。

  1. Larger and recursive functions are not inlined and the compiler ignores the inline keyword.
  2. 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. Putting inline 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:


  1. 即使它的身体在多个翻译单元中(例如包括多种的头的.cpp 文件),编译器将只产生1的定义,避免多个符号链接错误。 (注:如果该函数的机构不同,那么它是不确定的行为)

  2. 内嵌的身体函数可见/访问谁在使用它的所有翻译单元。换句话说,在 .H 声明一个在线功能和的任何一个的<定义code>的.cpp 文件将导致一个未定义的符号链接错误其他的.cpp 文件

  1. 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.)
  2. The body of the inline function has to be visible / accessible in all the translation units who use it. In other words, declaring an inline 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 InlineCosts 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆