Open aytekinar opened 1 year ago
I have now created a minimal, reproducible example.
Assume we have the following library header:
#ifndef __MYLIB_H__
#define __MYLIB_H__
#include <stdlib.h>
float myfunc(const size_t n, const float *restrict x, const float *restrict y);
#endif // __MYLIB_H__
and its implementation file:
#include <stdlib.h>
#include "mylib.h"
__attribute__((target("default"))) static float
myfunc_impl_scalar(const size_t n, const float *restrict x,
const float *restrict y) {
float sum = 0;
for (size_t i = 0; i < n; i++) {
sum += x[i] * y[i];
}
return sum;
}
__attribute__((target("avx"))) static float
myfunc_impl_avx(const size_t n, const float *restrict x,
const float *restrict y) {
float sum = 0;
for (size_t i = 0; i < n; i++) {
sum -= x[i] * y[i];
}
return sum;
}
static float myfunc_dispatcher(const size_t n, const float *restrict x,
const float *restrict y);
static float (*myfunc_ptr)(const size_t n, const float *restrict x,
const float *restrict y) = myfunc_dispatcher;
static float myfunc_dispatcher(const size_t n, const float *restrict x,
const float *restrict y) {
if (__builtin_cpu_supports("avx")) {
myfunc_ptr = myfunc_impl_avx;
return myfunc_impl_avx(n, x, y);
} else {
myfunc_ptr = myfunc_impl_scalar;
return myfunc_impl_scalar(n, x, y);
}
}
float myfunc(const size_t n, const float *restrict x, const float *restrict y) {
return myfunc_ptr(n, x, y);
}
If we use the -flto=thin
switch, we get the following result:
$ clang-15 -Wall -Wpedantic -O2 -g -flto=thin mylib.c -c -emit-llvm -o mylib.bc
$ llvm-dis-15 mylib.bc
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:
0. Program arguments: llvm-dis-15 mylib.bc
Stack dump without symbol names (ensure you have llvm-symbolizer in your PATH or set the environment var `LLVM_SYMBOLIZER_PATH` to point to it):
/usr/lib/llvm-15/bin/../lib/libLLVM-15.so.1(_ZN4llvm3sys15PrintStackTraceERNS_11raw_ostreamEi+0x31)[0x7f5f5b9c53b1]
/usr/lib/llvm-15/bin/../lib/libLLVM-15.so.1(_ZN4llvm3sys17RunSignalHandlersEv+0xee)[0x7f5f5b9c30fe]
/usr/lib/llvm-15/bin/../lib/libLLVM-15.so.1(+0xf048d6)[0x7f5f5b9c58d6]
/lib/x86_64-linux-gnu/libc.so.6(+0x42520)[0x7f5f5a59f520]
/usr/lib/llvm-15/bin/../lib/libLLVM-15.so.1(+0xf256d5)[0x7f5f5b9e66d5]
/usr/lib/llvm-15/bin/../lib/libLLVM-15.so.1(_ZNK4llvm18ModuleSummaryIndex5printERNS_11raw_ostreamEb+0xbbe)[0x7f5f5b9d634e]
llvm-dis-15(+0x5e07)[0x55c135f0de07]
/lib/x86_64-linux-gnu/libc.so.6(+0x29d90)[0x7f5f5a586d90]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0x80)[0x7f5f5a586e40]
llvm-dis-15(+0x3c45)[0x55c135f0bc45]
fish: Job 1, 'llvm-dis-15 mylib.bc' terminated by signal SIGSEGV (Address boundary error)
$
Without the -flto-thin
switch, we seem to get going with the implementation:
$ clang-15 -Wall -Wpedantic -O2 -g mylib.c -c -emit-llvm -o mylib.bc
$ llvm-dis-15 mylib.bc
$
If, on the other hand, I resort to LLVM's function multi-versioning support (by unifying the function signatures), I don't have any problems at all. Revised mylib.c
is as follows:
#include <stdlib.h>
#include "mylib.h"
__attribute__((target("default"))) static float
myfunc_impl(const size_t n, const float *restrict x,
const float *restrict y) {
float sum = 0;
for (size_t i = 0; i < n; i++) {
sum += x[i] * y[i];
}
return sum;
}
__attribute__((target("avx"))) static float
myfunc_impl(const size_t n, const float *restrict x,
const float *restrict y) {
float sum = 0;
for (size_t i = 0; i < n; i++) {
sum -= x[i] * y[i];
}
return sum;
}
float myfunc(const size_t n, const float *restrict x, const float *restrict y) {
return myfunc_impl(n, x, y);
}
with the commands as below:
$ clang-15 -Wall -Wpedantic -O2 -g mylib.c -c -emit-llvm -o mylib.bc
mylib.c:16:1: warning: unused function 'myfunc_impl' [-Wunused-function]
myfunc_impl(const size_t n, const float *restrict x,
^
1 warning generated.
$ llvm-dis-15 mylib.bc
$ clang-15 -Wall -Wpedantic -O2 -g -flto=thin mylib.c -c -emit-llvm -o mylib.bc
mylib.c:16:1: warning: unused function 'myfunc_impl' [-Wunused-function]
myfunc_impl(const size_t n, const float *restrict x,
^
1 warning generated.
$ llvm-dis-15 mylib.bc
$
Obviously, if I go for the latter approach, or add __attribute__((target_clones(...)))
to a single function definition, for that matter, I lose portability of the code.
What should I do? Do you think this is a bug or I can do some workaround to alleviate the issue?
Reduced to:
reduced.c
static int __attribute__((target_clones("default,avx")))
has_target_clones(void) {
return 0;
}
int main(void) {
int (*func)(void) = has_target_clones;
return func();
}
$ clang -O0 -g reduced.c
$ clang -O0 -flto -g reduced.c
clang: error: unable to execute command: Segmentation fault (core dumped)
clang: error: linker command failed due to signal (use -v to see invocation)
$ clang --version
clang version 18.1.1 (Fedora 18.1.1-1.fc40)
Target: x86_64-redhat-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
Configuration file: /etc/clang/clang.cfg
Hi,
I receive a segmentation fault when running
llvm-lto -thinlto -thinlto-action=thinlink ...
.Note that I am not running this command myself --- it's part of the
Makefile
of a PostgreSQL extension, and the corresponding PostgreSQL instance has been built with--enable-llvm
configuration option.I have modified the
Makefile
to includePG_LDFLAGS += -Wl,--reproduce=repro.tar.gz
and am attaching repro.tar.gz in this issue. The trace is as follows:Cc: @aykut-bozkurt