gcc에게 함수를 인라인하지 말라고 어떻게 말할 수 있습니까?


126

소스 파일 에이 작은 기능이 있다고 가정 해보십시오.

static void foo() {}

바이너리의 최적화 된 버전을 빌드하지만이 기능을 최적화하지 않기 위해 인라인하지 않으려 고합니다. 인라인을 방지하기 위해 소스 코드에 추가 할 수있는 매크로가 있습니까?


이 질문에 감사드립니다! 함수가 표시되지 않을 때 oprofile을 사용하여 프로파일 링 중이 었으며 여기에 대한 답변이 수정되었습니다.
Simon A. Eugster

답변:


149

gcc-특정 noinline속성을 원합니다 .

이 함수 속성은 함수가 인라인으로 간주되지 않도록합니다. 함수에 부작용이없는 경우 함수 호출이 활성화되어 있지만 인라인 이외의 최적화를 통해 함수 호출을 최적화 할 수 있습니다. 이러한 통화가 최적화되지 않도록하려면 asm ("");

다음과 같이 사용하십시오.

void __attribute__ ((noinline)) foo() 
{
  ...
}

32
Arch Linux에서 gcc 4.4.3을 사용하면 위와 같은 속성으로 구문 오류가 발생합니다. 함수 앞에 올 때 올바르게 작동합니다 (예 : attribute ((noinline)) void foo () {})
mrkj

2
Arduino는 또한 기능 앞에 배치하기를 원했습니다.
피터 N 루이스

2
속성 구문을 수정하도록 편집되었습니다.
Quuxplusone

1
asm ( "") 구문은 실제로 상당히 크로스 플랫폼이며 작업이 완료되었습니다. 나는 x86 Linux를 위해 그것을했고 PowerPC AIX에서 빌드 문제를 일으키지 않았다. 이 유용한 제안에 감사드립니다!
Marty

1
모든 곳에서 코드를 변경해야하는 접근 방식은 합당한 대답으로 간주 될 수 없습니다.
ajeh

31

GCC에는

-fno-inline-small-functions

gcc를 호출 할 때 사용하십시오. 그러나 부작용은 다른 모든 작은 함수들도 인라인되지 않는다는 것입니다.


컴파일러 수준에서 작동하지 않았습니다. 20150902 (레드햇 5.2.1-2) GCC 5.2.1를 사용하고 있었다
존 그린

현재 GCC 6.4가 깨지거나 더 단순 -fno-inline하고 전혀 작동하지 않습니다. gdb여전히 스텝 오버시 메소드를 입력합니다. 무언가가 깨졌으며 의심 스럽다 gdb.
ajeh

지정된 함수뿐만 아니라 모두에 대한 인라인 최적화 기능을 해제합니다.
where

@ajeh 함수를 인라이닝하지 않으면 정상적으로 호출된다는 의미입니까?
Melebius

21

이를 수행하는 휴대용 방법은 포인터를 통해 함수를 호출하는 것입니다.

void (*foo_ptr)() = foo;
foo_ptr();

이것은 분기마다 다른 지침을 생성하지만 목표가 아닐 수도 있습니다. 다음 중 좋은 점을 제시합니다. 여기서 목표 무엇 입니까?


2
포인터가 정적이 아닌 파일 범위에 정의되어 있으면 컴파일러가 포인터를 사용할 때 초기 값이 있다고 가정 할 수 없으므로 작동해야합니다. 로컬 인 경우 (그림 참조) 거의 foo ()와 동일하게 취급됩니다. ( "10 년 후, 그는 날짜를 보며 덧붙였다")
greggo

16

질문은 GCC에 관한 것임을 알고 있지만 다른 컴파일러에도 컴파일러에 대한 정보가 있으면 도움이 될 것이라고 생각했습니다.

GCC의 noinline 함수 속성은 다른 컴파일러에서도 널리 사용됩니다. 최소한 다음에 의해 지원됩니다.

  • 클랑 (으로 확인 __has_attribute(noinline))
  • Intel C / C ++ Compiler (그들의 문서는 끔찍하지만 16.0 이상에서 작동한다고 확신합니다)
  • Oracle Solaris Studio를 12.2 이상으로 다시
  • 4.1 이상으로 ARM C / C ++ 컴파일러
  • IBM XL C / C ++를 10.1 이상으로 되돌림
  • TI 8.0 이상 (또는 --gcc를 사용하는 7.3 이상 __TI_GNU_ATTRIBUTE_SUPPORT__)

또한 MSVC는 __declspec(noinline) Visual Studio 7.1로 다시 지원합니다 . 인텔은 아마도 그것을 지원할 것입니다 (GCC와 MSVC 모두와 호환하려고 시도하지만). 문법은 기본적으로 같습니다 :

__declspec(noinline)
static void foo(void) { }

PGI 10.2+ (및 이전 버전)는 noinline다음 기능에 적용되는 pragma를 지원 합니다.

#pragma noinline
static void foo(void) { }

TI 6.0+는 FUNC_CANNOT_INLINE C와 C ++에서 다르게 작동 하는 pragma를 지원합니다 . C ++에서는 PGI와 비슷합니다.

#pragma FUNC_CANNOT_INLINE;
static void foo(void) { }

그러나 C에서는 함수 이름이 필요합니다.

#pragma FUNC_CANNOT_INLINE(foo);
static void foo(void) { }

Cray 6.4+ (및 이전 버전)는 비슷한 접근 방식을 취하며 함수 이름이 필요합니다.

#pragma _CRI inline_never foo
static void foo(void) { }

Oracle Developer Studio는 또한 함수 이름을 사용 하여 적어도 Forte Developer 6 로 돌아가는 pragma를 지원 하지만 , 최신 버전에서도 선언 뒤에 와야 합니다.

static void foo(void);
#pragma no_inline(foo)

얼마나 헌신적인지에 따라 모든 곳에서 작동하는 매크로를 만들 수 있지만 함수 이름과 인수로 선언해야합니다.

OTOH, 대부분의 사람들에게 적합한 것이 있으면 괜찮을 것입니다. 이것이 Hedley 에 대해 취한 접근법입니다 . 현재 HEDLEY_NEVER_INLINE 버전은 다음과 같습니다.

#if \
  HEDLEY_GNUC_HAS_ATTRIBUTE(noinline,4,0,0) || \
  HEDLEY_INTEL_VERSION_CHECK(16,0,0) || \
  HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
  HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
  HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
  HEDLEY_TI_VERSION_CHECK(8,0,0) || \
  (HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__))
#  define HEDLEY_NEVER_INLINE __attribute__((__noinline__))
#elif HEDLEY_MSVC_VERSION_CHECK(13,10,0)
#  define HEDLEY_NEVER_INLINE __declspec(noinline)
#elif HEDLEY_PGI_VERSION_CHECK(10,2,0)
#  define HEDLEY_NEVER_INLINE _Pragma("noinline")
#elif HEDLEY_TI_VERSION_CHECK(6,0,0)
#  define HEDLEY_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;")
#else
#  define HEDLEY_NEVER_INLINE HEDLEY_INLINE
#endif

Hedley (단일 퍼블릭 도메인 / CC0 헤더)를 사용하지 않으려는 경우 너무 많은 노력없이 버전 확인 매크로를 변환 할 수 있지만 ☺에 넣을 수있는 것 이상입니다.


프로젝트 @nemequ에 대한 링크를 주셔서 감사합니다. 다른 개발자들에게 사용에 대한 평가를 요청했습니다. 우리는 다양한 아키텍처를 가지고 있습니다.
다이스케 아라 마키

나는 그들이 무슨 말을 알고 매우 관심이있을 것 , 특히 그들이 관심이 있다면. 그리고 물론 질문에 답하기 위해 왔습니다 (GitHub 이슈 트래커, 이메일 등).
nemequ

14

에 대한 컴파일러 오류가 발생 __attribute__((noinline))하면 다음을 시도해보십시오.

noinline int func(int arg)
{
    ....
}

10
static __attribute__ ((noinline))  void foo()
{

}

이것이 나를 위해 일한 것입니다.


8

noinline 속성을 사용하십시오 .

int func(int arg) __attribute__((noinline))
{
}

외부 사용을 위해 함수를 선언 할 때와 함수를 작성할 때 둘 다 사용해야합니다.


2

나는 gcc 7.2와 함께 일한다. 라이브러리에서 인스턴스화해야했기 때문에 인라인이 아닌 함수가 필요했습니다. 나는 __attribute__((noinline))대답뿐만 아니라 대답을 시도했다 asm(""). 어느 쪽도 문제를 해결하지 못했습니다.

마지막으로 함수 내에서 정적 변수를 정의하면 컴파일러가 정적 변수 블록에 공간을 할당하고 함수가 처음 호출 될 때 초기화를 발행해야한다고 생각했습니다.

이것은 더러운 속임수이지만 작동합니다.


inline void foo(void) { ... }헤더에서 함수 를 정의 extern inline void foo(void);하고 라이브러리 소스 파일에서 선언 할 수 있습니다. C99 의미에 따라 컴파일러는 라이브러리에서 객체 코드를 기쁘게하고 방출 할 때 함수를 인라인 할 수 있습니다. 페이지 는 "고정"또는 C99의 적 "통근"유용하지 않고 "인라인"? .
diapir
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.