Bagaimana saya bisa memberi tahu gcc untuk tidak menampilkan fungsi?

126

Katakanlah saya memiliki fungsi kecil ini dalam file sumber

static void foo() {}

dan saya membangun versi optimal biner saya, tetapi saya tidak ingin fungsi ini diuraikan (untuk keperluan optimasi). apakah ada makro yang bisa saya tambahkan dalam kode sumber untuk mencegah inlining?

Vehomzzz
sumber
Terima kasih untuk pertanyaan ini! Saya membuat profil dengan oprofile ketika suatu fungsi tidak muncul, jawaban di sini memperbaiki ini.
Simon A. Eugster
c ++: stackoverflow.com/questions/3329214/…
Ciro Santilli 郝海东 冠状 病 六四 六四 事件 法轮功

Jawaban:

149

Anda ingin atribut gcc-specific noinline.

Atribut fungsi ini mencegah fungsi dipertimbangkan untuk inlining. Jika fungsi tidak memiliki efek samping, ada optimasi selain inlining yang menyebabkan panggilan fungsi dioptimalkan, meskipun panggilan fungsi aktif. Agar panggilan tersebut tidak dioptimalkan, lakukan asm ("");

Gunakan seperti ini:

void __attribute__ ((noinline)) foo() 
{
  ...
}
alex tingle
sumber
32
Menggunakan gcc 4.4.3 di Arch Linux, saya mendapatkan kesalahan sintaks dengan atribut ditempatkan seperti di atas. Ia bekerja dengan benar ketika mendahului fungsi (misalnya, atribut ((noinline)) void foo () {})
mrkj
2
Arduino juga ingin meletakkannya di depan fungsi.
Peter N Lewis
2
Diedit untuk memperbaiki sintaks atribut.
Quuxplusone
1
Konstruksi asm ("") sebenarnya cukup lintas platform dan menyelesaikan pekerjaan. Saya melakukannya untuk Linux x86 dan tidak menyebabkan masalah build pada PowerPC AIX. Terima kasih atas saran yang bermanfaat ini!
Marty
1
Pendekatan yang membutuhkan perubahan kode di mana-mana tidak dapat dianggap sebagai jawaban yang dapat diterima.
ajeh
31

GCC memiliki saklar bernama

-fno-inline-small-functions

Jadi gunakan itu saat memanggil gcc. Tetapi efek sampingnya adalah semua fungsi kecil lainnya juga tidak inline.

lukmac
sumber
Tidak bekerja di level kompiler. Sedang menggunakan gcc 5.2.1 20150902 (Red Hat 5.2.1-2)
John Greene
Entah GCC 6.4 saat ini rusak, atau ini dan lebih sederhana -fno-inlinetidak berfungsi sama sekali. gdbmasih memasuki metode saat step-over. Ada yang rusak, dan saya ragu gdb.
ajeh
Ini akan mematikan optimasi inline untuk semua, tidak hanya untuk fungsi yang ditentukan.
where23
@ajeh Tidak fungsi inlining berarti mereka dipanggil secara normal, bukan?
Melebius
21

Cara portabel untuk melakukan ini adalah memanggil fungsi melalui pointer:

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

Meskipun ini menghasilkan instruksi yang berbeda untuk cabang, yang mungkin bukan tujuan Anda. Yang membawa titik yang baik: apa adalah tujuan Anda di sini?

Andy Ross
sumber
2
Jika pointer didefinisikan pada ruang lingkup file, dan bukan statis, itu harus berfungsi sejak kompiler maka tidak dapat menganggap itu memiliki nilai awal pada saat digunakan. Jika itu lokal (seperti yang ditunjukkan) itu hampir pasti diperlakukan sama dengan foo (). ("Dalam dekade ini", tambahnya, sambil melihat tanggalnya)
greggo
16

Saya tahu pertanyaannya adalah tentang GCC, tapi saya pikir mungkin berguna untuk memiliki beberapa informasi tentang kompiler kompiler lain juga.

noinline Atribut fungsi GCC juga cukup populer dengan kompiler lain. Setidaknya didukung oleh:

  • Dentang (periksa dengan __has_attribute(noinline))
  • Intel C / C ++ Compiler (dokumentasinya mengerikan, tapi saya yakin ini bekerja pada 16.0+)
  • Oracle Solaris Studio kembali ke setidaknya 12.2
  • ARM C / C ++ Compiler kembali ke setidaknya 4.1
  • IBM XL C / C ++ kembali ke setidaknya 10.1
  • TI 8.0+ (atau 7.3+ dengan --gcc, yang akan ditentukan __TI_GNU_ATTRIBUTE_SUPPORT__)

Selain itu, MSVC mendukung __declspec(noinline) kembali ke Visual Studio 7.1. Intel mungkin mendukungnya juga (mereka mencoba untuk kompatibel dengan GCC dan MSVC), tetapi saya belum repot-repot memverifikasi itu. Sintaks dasarnya sama:

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

PGI 10.2+ (dan mungkin lebih tua) mendukung noinlinepragma yang berlaku untuk fungsi selanjutnya:

#pragma noinline
static void foo(void) { }

TI 6.0+ mendukung FUNC_CANNOT_INLINE pragma yang (secara mengganggu) bekerja secara berbeda dalam C dan C ++. Dalam C ++, ini mirip dengan PGI:

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

Namun dalam C, nama fungsi diperlukan:

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

Cray 6.4+ (dan mungkin sebelumnya) mengambil pendekatan yang serupa, membutuhkan nama fungsi:

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

Oracle Developer Studio juga mendukung pragma yang mengambil nama fungsi, kembali ke setidaknya Forte Developer 6 , tetapi perhatikan bahwa itu harus datang setelah deklarasi, bahkan dalam versi terbaru:

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

Tergantung pada seberapa berdedikasi Anda, Anda bisa membuat makro yang akan bekerja di mana-mana, tetapi Anda harus memiliki nama fungsi serta deklarasi sebagai argumen.

Jika, OTOH, Anda baik-baik saja dengan sesuatu yang hanya berfungsi untuk kebanyakan orang, Anda bisa lolos dengan sesuatu yang sedikit lebih estetis dan tidak perlu mengulangi sendiri. Itulah pendekatan yang saya ambil untuk Hedley , tempat versi HEDLEY_NEVER_INLINE saat ini terlihat seperti:

#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

Jika Anda tidak ingin menggunakan Hedley (ini adalah header domain / CC0 publik tunggal) Anda dapat mengonversi versi memeriksa makro tanpa terlalu banyak usaha, tetapi lebih dari yang saya bersedia ☺.

nemequ
sumber
Terima kasih atas tautan ke proyek Anda @nemequ. Saya telah meminta pengembang kami yang lain untuk mengevaluasi penggunaan kami. Kami memiliki beragam arsitektur.
Daisuke Aramaki
Saya akan sangat tertarik untuk mengetahui apa yang mereka katakan, terutama jika mereka tidak tertarik. Dan, tentu saja, saya siap menjawab pertanyaan (GitHub mengeluarkan pelacak, email, apa pun ...).
nemequ
14

Jika Anda mendapatkan kesalahan kompiler __attribute__((noinline)), Anda bisa mencoba:

noinline int func(int arg)
{
    ....
}
Sam Liao
sumber
10
static __attribute__ ((noinline))  void foo()
{

}

Inilah yang bekerja untuk saya.

KenBee
sumber
8

Gunakan noinline atribut :

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

Anda mungkin harus menggunakannya baik ketika Anda mendeklarasikan fungsi untuk penggunaan eksternal dan ketika Anda menulis fungsi.

Chris Lutz
sumber
2

Saya bekerja dengan gcc 7.2. Saya secara khusus membutuhkan fungsi yang tidak di-inline, karena itu harus dipakai di perpustakaan. Saya mencoba __attribute__((noinline))jawabannya, juga asm("")jawabannya. Tidak ada yang memecahkan masalah.

Akhirnya, saya pikir bahwa mendefinisikan variabel statis di dalam fungsi akan memaksa kompiler untuk mengalokasikan ruang untuknya di blok variabel statis, dan mengeluarkan inisialisasi untuk itu ketika fungsi pertama kali dipanggil.

Ini semacam trik kotor, tetapi berhasil.

Ofri Sadowsky
sumber
Anda bisa mendefinisikan fungsi Anda inline void foo(void) { ... }di header dan mendeklarasikannya extern inline void foo(void);dalam file sumber perpustakaan. Mengikuti semantik C99, kompiler akan diizinkan untuk sebaris fungsi ketika diinginkan DAN memancarkan kode objek di perpustakaan Anda. Lihat Apakah "inline" tanpa "statis" atau "eksternal" pernah berguna di C99? .
diapir