nim-lang / Nim

Nim is a statically typed compiled systems programming language. It combines successful concepts from mature languages like Python, Ada and Modula. Its design focuses on efficiency, expressiveness, and elegance (in that order of priority).
https://nim-lang.org
Other
16.24k stars 1.46k forks source link

codegenDecl on functions overrides all attributes #10682

Open mratsim opened 5 years ago

mratsim commented 5 years ago

codegenDecl pragma on functions will override all function attributes.

Example:

proc foo() =
  echo 1

{.pragma: hot, codegenDecl: "__attribute__((hot)) $# $#$#".}

proc bar() {.hot.} =
  echo 1

proc baz() {.inline.} =
  echo 1

proc oops() {.inline, hot.} =
  echo 1

foo()
bar()
baz()
oops()

This produces (in release emode)

N_LIB_PRIVATE N_NIMCALL(void, foo_wznx9adj3TlVt3o5axJ9aYOg)(void) {
    echoBinSafe(TM_YoGu5Gbh4YxJ9c0z7IstHKg_2, 1);
}

__attribute__((hot)) void bar_wznx9adj3TlVt3o5axJ9aYOg_2(void) {
    echoBinSafe(TM_YoGu5Gbh4YxJ9c0z7IstHKg_2, 1);
}

static N_INLINE(void, baz_Ij9bzunIMj7NU3a7ws3YxBQattr_func)(void) {
    echoBinSafe(TM_YoGu5Gbh4YxJ9c0z7IstHKg_2, 1);
}

__attribute__((hot)) void oops_Ij9bzunIMj7NU3a7ws3YxBQ_2attr_func(void) {
    echoBinSafe(TM_YoGu5Gbh4YxJ9c0z7IstHKg_2, 1);
}

In the first case N_LIB_PRIVATE N_NIMCALL has been replaced and in the second case static N_INLINE has been replaced.

For a bit more context, I'm writing a domain specific compiler in Nim for machine learning and image processing and I need to implement one function per SIMD supported (nothing, SSE, AVX, AVX512, ...). Unfortunately, ideally those should be in separate C files to avoid the compiler using incompatible features in older sets which seems complicated. Alternatively I can use GCC/Clang only attributes like __attribute__((__target__("avx2"))).

mratsim commented 5 years ago

I checked how this is implemented in ccgtypes genProcHeader: https://github.com/nim-lang/Nim/blob/2610b16f6ede15888de9769b7226233dc8e86b68/compiler/ccgtypes.nim#L888-L912

I'm not sure there is a way to do what is needed in a backward compatible way.

I've found the current workaround:

proc foo() =
  echo 1

{.pragma: hot, codegenDecl: "__attribute__((hot)) N_LIB_PRIVATE N_NIMCALL($#, $#)$#".}
{.pragma: hot_inline, codegenDecl: "__attribute__((hot)) static N_INLINE($#, $#)$#".}

proc bar() {.hot.} =
  echo 1

proc baz() {.inline.} =
  echo 1

proc oops() {.hot_inline.} =
  echo 1

foo()
bar()
baz()
oops()
N_LIB_PRIVATE N_NIMCALL(void, foo_ZEVWdPzph9aEvWzKnk2jr4w)(void) {
    echoBinSafe(TM_rnFJuQ50wUpy8kftbt2QJA_2, 1);
}

__attribute__((hot)) N_LIB_PRIVATE N_NIMCALL(void, bar_ZEVWdPzph9aEvWzKnk2jr4w_2)(void) {
    echoBinSafe(TM_rnFJuQ50wUpy8kftbt2QJA_2, 1);
}

static N_INLINE(void, baz_txURmaVFiHb6ZhpniaNZhgattr_func3)(void) {
    echoBinSafe(TM_rnFJuQ50wUpy8kftbt2QJA_2, 1);
}

__attribute__((hot)) static N_INLINE(void, oops_ZEVWdPzph9aEvWzKnk2jr4w_3)(void) {
    echoBinSafe(TM_rnFJuQ50wUpy8kftbt2QJA_2, 1);
}
mratsim commented 4 years ago

Removing the low priority tag.

We are considering using LLVM Xray for instrumenting Nimbus. Fine-grained instrumenting can be controlled with GCC attributes:

void alt_always_instrumented() __attribute__((xray_always_instrument));
void alt_never_instrumented() __attribute__((xray_never_instrument));