Выполнение следующего кода с 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 & использование -stdlib=libstdc++
,
Здесь LLVM-л (к большому сожалению, вставлять его сюда напрямую)
РЕДАКТИРОВАТЬ:
Ошибка оказалась вызвана отсутствием поддержки TLS в JITer. Этот ответ описывает другую проблему, связанную со связыванием и lli
,
Если вы посмотрите на сгенерированный IR от clang++ -std=c++11 -S -emit-llvm test.cpp
вы найдете, что многие из символов, например, _ZNSt6futureIiE3getEv
, только объявлены, но никогда не определены. Линкер никогда не вызывается, так как -S «Выполнять только шаги предварительной обработки и компиляции» (clang —help).
lli
выполняет только модуль IR и не выполняет «неявного» связывания. Как он должен знать, в какие библиотеки связывать?
Есть разные решения для этого, в зависимости от того, почему вы используете lli:
llc main.cpp && clang++ -lpthread main.s
(требуется указание s. Каковы правильные параметры ссылок для использования std :: thread в GCC под Linux?)LD_PRELOAD="x.so y.so"
принудительно загрузить библиотеки перед запуском lli
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 (s. 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
обменивает эту проблему с ошибкой перемещения.