lli: LLVM ОШИБКА: невозможно выбрать: X86ISD::WrapperRIP TargetGlobalTLS Адрес:i64
Выполнение следующего кода с clang++ -S -emit-llvm main.cpp && lli main.ll
в Linux(Debian)
#include <future>
int main () {
return std::async([]{return 1;}).get();
}
не запускается на lli из-за следующей ошибки:
LLVM ERROR: Cannot select: 0xd012e0:
i64 = X86ISD::WrapperRIP TargetGlobalTLSAddress:i64<i8** @_ZSt15__once_callable> 0 [TF=10]
0xd020c0: i64 = TargetGlobalTLSAddress<i8** @_ZSt15__once_callable> 0 [TF=10]
In function: _ZSt9call_onceIMNSt13__future_base13_State_baseV2EFvPSt8functionIFSt10unique_ptrINS0_12_Result_baseENS4_8_DeleterEEvEEPbEJPS1_S9_SA_EEvRSt9once_flagOT_DpOT0_
Вопросы:
Что это значит?
Существуют ли какие-либо флаги компилятора, которые решают эту проблему?
с помощью -stdlib=libc++
компилируется и запускается успешно *; какие особенности libstdC++ использует, которые вызывают эту проблему?
РЕДАКТИРОВАТЬ:
Мотивация этого вопроса состоит в том, чтобы понять различия между libC++ и libstdC++, которые приводят к этому конкретному сообщению об ошибке (в Linux) в orvjit llvm.
В OSX gcc устарел и clang использует по умолчанию libc++
, Чтобы воспроизвести эту ошибку на OSX, вам, вероятно, нужно установить gcc & use -stdlib=libstdc++
,
Вот что такое llvm-ir (к сожалению, встраивать его здесь напрямую)
2 ответа
РЕДАКТИРОВАТЬ:
Ошибка оказалась вызвана отсутствием поддержки TLS в JITer. Этот ответ описывает другую проблему, связанную со связыванием и lli
,
Если вы посмотрите на сгенерированный IR от clang++ -std=c++11 -S -emit-llvm test.cpp
вы найдете, что многие из символов, например, _ZNSt6futureIiE3getEv
, только объявлены, но никогда не определены. Линкер никогда не вызывается, так как -S "Выполнять только шаги предварительной обработки и компиляции" (clang --help).
lli
выполняет только модуль IR и не выполняет "неявного" связывания. Как он должен знать, в какие библиотеки связывать?
Есть разные решения для этого, в зависимости от того, почему вы используете lli:
- скомпилировать и связать модуль IR:
llc main.cpp && clang++ -lpthread main.s
(Требуется pthread s. Какие правильные параметры ссылок для использования std::thread в GCC под Linux?) - (неподтвержденное) использование
LD_PRELOAD="x.so y.so"
принудительно загрузить библиотеки перед запускомlli
- JIT модуль программно и использовать
LoadLibraryPermanently(nullptr)
(добавляет символы программы в область поиска) иLoadLibraryPermanently(file, err)
для дополнительных библиотек (с. http://llvm.org/docs/doxygen/html/classllvm_1_1sys_1_1DynamicLibrary.html)
Я могу только догадываться, почему libC++ работает для вас, поскольку он не работает на моей машине, но, вероятно, это так, потому что он уже загружен в lli и вызывает lli sys::DynamicLibrary::LoadLibraryPermanently(nullptr)
добавить символы программы в пространство поиска JIT (см. https://github.com/llvm-mirror/llvm/blob/release_40/tools/lli/OrcLazyJIT.cpp#L110).
Список рассылки LLVM-dev указал:
Что это значит?
База данных llvm в orcjit в настоящее время не поддерживает локальное хранилище потоков (TLS)
минимальный пример:
extern thread_local int tls;
int main() {
tls = 42;
return 0;
}
использование -stdlib=libC++ компилируется и успешно выполняется *; какие особенности libstdC++ использует, которые вызывают эту проблему?
это работает, потому что libC++ future::get реализация не использует thread_local
ключевое слово.
Существуют ли какие-либо флаги компилятора, которые решают эту проблему?
В настоящее время нет решения. С помощью lli -relocation-model=pic
обменивает эту проблему с ошибкой перемещения.