programing

"inline" 키워드 vs "인라이닝" 개념

muds 2023. 10. 13. 22:35
반응형

"inline" 키워드 vs "인라이닝" 개념

저는 기록을 바로 세우기 위해 이 기본적인 질문을 하는 것입니다.이 질문현재 수락된 답변을 참조했는데, 설득력이 없습니다.그러나 두 번째로 많이 투표된 답변은 더 나은 통찰력을 제공하지만, 완벽하지도 않습니다.

.inline 키워드와 "인라이닝" 컨셉.

제 의견은 이렇습니다.

'인라이닝(inlineing)' 개념

이것은 함수의 호출 오버헤드를 저장하기 위해 행해집니다.매크로 스타일의 코드 교체와 더 유사합니다.논쟁할 것 없습니다.

inline

지각 A

inline키워드(keyword)는 컴파일러가 이를 최적화하고 더 빠른 호출을 할 수 있도록 더 작은 기능에 주로 사용되는 컴파일러에게 요청하는 것입니다.컴파일러는 그것을 무시할 자유가 있습니다.

아래의 이유로 부분적으로 이의를 제기합니다.

  1. 더 큰 함수는 는 /합니다.inline
  2. 는 .inline키워드가 언급되는지 여부.

사용자가 합니다의 기능에 명백합니다.inline.

인식B

inline인라이닝의 개념과는 상관이 없습니다.놓는 것inline큰/재귀적 함수 앞에 있는 함수는 도움이 되지 않지만, 작은 함수는 줄을 긋는 데 필요하지 않습니다.

유일한 결정론적 용도는inline하나의 정의 규칙을 유지하는 것입니다.

,inline아래 사항만 의무화됩니다.

  1. 이 여러 에 )(: ).cpp파일), 컴파일러는 1개의 정의만 생성하고 다중 심볼 링커 오류를 방지합니다. (참고: 함수의 본문이 다르면 정의되지 않은 동작입니다.)
  2. 몸.inline함수를 사용하는 모든 번역 단위에서 볼 수 있어야 합니다.,하는 것,입니다.inline에서의 기능.h그리고 어느 한 에 정의를 내리는 것. .cpp하면 다른류 합니다" " 심볼 가 발생합니다..cpp

평결

IMO, "A"라는 인식은 전적으로 잘못된 것이고 "B"라는 인식은 전적으로 옳은 것입니다.

이에 대한 표준적인 인용문이 몇 개 있지만, 이 평결이 맞는지 아닌지 논리적으로 설명하는 답변이 기대됩니다.


Bjarne Strostrup에서 보낸 이메일 답장:

"수십 년 동안 사람들은 컴파일러/옵티마이저가 인간보다 인라인을 더 잘한다고 약속해 왔습니다.이것은 이론적으로는 사실일 수 있지만, 특히 전체 프로그램 최적화가 가능하지 않은 환경에서는 여전히 훌륭한 프로그래머에게는 실제로 적용되지 않습니다.명백한 인라이닝을 신중하게 사용함으로써 얻을 수 있는 중요한 이점이 있습니다."

저는 당신의 주장에 확신이 없었습니다.

더 작은 기능은 인라인 언급 여부에 관계없이 옵티마이저에 의해 자동으로 "인라인"됩니다...가 키워드닝 합니다"하여를 하여 " 제어권도 있지합니다.inline.

의 를 할 수 inline요청은 했지만 완전히 무시한 것 같지는 않았습니다.

Clang과 LLVM을 찾기 위해 Github 저장소를 찾아 보았습니다. (오픈소스 소프트웨어 감사합니다!)키워드를 사용하면 Clang/LLVM이 함수를 인라인화할 가능성이 높다는 것을 알게 되었습니다.

더 서치

를 검색하는 중입니다.inlineClang 저장소에서 토큰 지정자로 연결됩니다.kw_inline 관련 Clang 렉서 와 것이 그래서 바로 다음과 같은 주목할 만한 것이 있습니다.if (tokenString == "inline") return kw_inline발견될 겁니다하지만 여기 ParseDecl.cpp에서는kw_inline다로 됩니다.DeclSpec::setFunctionSpecInline().

case tok::kw_inline:
  isInvalid = DS.setFunctionSpecInline(Loc, PrevSpec, DiagID);
  break;

기능 안에서는 비트를 설정하고 중복되는 경우 경고를 표시합니다.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다른 곳에서는 비트 필드에 있는 단일 비트를 볼 수 있고 게터 기능에 사용됩니다.isInlineSpecified():

bool isInlineSpecified() const {
  return FS_inline_specified | FS_forceinline_specified;
}

의 통화 하는 중isInlineSpecified(), C++ 파싱 트리를 LLVM 중간 표현으로 변환하는 코드젠을 찾습니다.

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++ 파싱 단계가 끝났습니다.이제 우리의inline립 LLVM됩니다의 됩니다.Function물건.Clang에서 LLVM 저장소로 전환합니다.

중인 항목:llvm::Attribute::InlineHint 합니다를(를) 합니다. Inliner::getInlineThreshold(CallSite CS) (무서워 보이는 무안경 블록으로):

// 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()하나의 통화 사이트만 있는 것으로 보입니다.SimpleInliner:

InlineCost getInlineCost(CallSite CS) override {
  return ICA->getInlineCost(CS, getInlineThreshold(CS));
}

가상 메소드라고 하는데 이름도 이름이 붙여졌습니다.getInlineCost의 )를 . .InlineCostAnalysis.

중인 항목:::getInlineCost()다을 찾습니다.AlwaysInline다또 이기도 합니다.InlineCostAnalysis합니다.Threshold매개 변수 여기:

CallAnalyzer CA(Callee->getDataLayout(), *TTI, AT, *Callee, Threshold);
bool ShouldInline = CA.analyzeCall(CS);

CallAnalyzer::analyzeCall()는 200개 이상의 라인이며 함수가 인라인 가능한지 여부를 결정하는 실제 작업을 수행합니다.그것은 많은 요소들에 무게를 가하지만, 우리가 방법을 통해 읽을 때 우리는 그것의 모든 계산이 다음을 조작하는 것을 봅니다.ThresholdeCost 그리고 마지막에:

return Cost < Threshold;

값이 입니다.ShouldInline정말 잘못된 이름입니다.실의 은.analyzeCall()설정하는 것입니다.Cost그리고.ThresholdCallAnalyzer물건.반환 값은 다음과 같이 다른 요인이 비용 대 임계값 분석을 무시한 경우만 나타냅니다.

// 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();

않으면 합니다.Cost그리고.Threshold.

return llvm::InlineCost::get(CA.getCost(), CA.getThreshold());

그래서 우리는 대부분의 경우 찬성 또는 반대 결정을 하지 않을 것입니다.검색이 계속됩니다!?getInlineCost()고?

진정한 결정

bool Inliner::shouldInline(CallSite CS)또 의 큰 또 하나의 큰 기능.은라고 부릅니다.getInlineCost()

그 .getInlineCost는 함수의 인수 서명, 코드 길이, 재귀, 분기, 연결 등 함수에 대한 고유 비용과 함수가 사용되는 모든 곳에 대한 일부 집계 정보를 분석합니다.반면에.shouldInline()는 이 정보를 함수가 사용되는 특정 장소에 대한 더 많은 데이터와 결합합니다.

에 걸쳐 에 .InlineCost::costDelta()-합니다.InlineCosts Threshold한 값analyzeCall(). 마침내, 우리는 a를 돌려줍니다.bool. 결정되었습니다. 인.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()의 결정.

.Threshold다의 을 받았습니다inline키워드이며, 인라인 여부를 결정할 때 마지막에 사용됩니다.

가 B 는 를 에 당신의 왜냐하면 적어도 하나의 주요 컴파일러가 그것의 최적화 동작을 다음을 기반으로 바꾸기 때문입니다.inline키워드.

그 도 볼 수.inline힌트일 뿐이고 다른 요인이 더 클 수도 있습니다.

둘 다 맞습니다.

의 .inline함수에 대한 특정 호출을 인라인화하는 컴파일러의 결정에 영향을 미칠 수도 있고 그렇지 않을 수도 있습니다.따라서 A가 맞습니다. 컴파일러가 무시할 수 있는 인라인 함수를 호출하는 구속력 없는 요청으로 작용합니다.

의 .inline는 하나의 정의 규칙(One Definition Rule)의 제한을 완화하여 B에 설명된 것처럼 동일한 정의를 여러 번역 단위로 허용하는 것입니다.많은 컴파일러의 경우 함수 호출의 인라인을 허용하기 위해 이 기능이 필요합니다. 정의는 해당 시점에서 사용할 수 있어야 하며 컴파일러는 한 번에 하나의 번역 단위만 처리하면 됩니다.

언급URL : https://stackoverflow.com/questions/27042935/inline-keyword-vs-inlining-concept

반응형