Lli: ОШИБКА LLVM: Невозможно выбрать: X86ISD:: WrapperRIP TargetGlobalTLSAddress: 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++ компилируется и выполняется успешно *; какие конкретные функции libstdС++ используют, что вызывает эту проблему?

EDIT:

Мотивация этого вопроса заключается в понимании различий между libС++ и libstdС++, что приводит к этому конкретному сообщению об ошибке (в Linux) в llvm orcjit.

В OSX gcc устарел, а clang использует по умолчанию libc++. Чтобы воспроизвести эту ошибку на OSX, вам, вероятно, придется установить gcc и использовать -stdlib=libstdc++.

Вот llvm-ir (к сожалению, он может быть встроен в него напрямую)

Ответ 1

EDIT:

Ошибка оказалась вызвана отсутствием поддержки TLS в JITer. Этот ответ описывает еще одну проблему, связанную с привязкой и lli.


Если вы посмотрите на сгенерированный IR из clang++ -std=c++11 -S -emit-llvm test.cpp, вы обнаружите, что многие из символов, например. _ZNSt6futureIiE3getEv, объявляются, но не определены. Компоновщик никогда не вызывается, поскольку -S "Выполнять только шаги препроцесса и компиляции" (clang --help).

lli выполняет только ИК-модуль и не связывает "неявное" соединение, как он должен знать, к каким библиотекам следует подключаться?

В этом есть разные решения, в зависимости от того, почему вы используете lli:

Я могу только догадываться о том, почему libС++ работает для вас, поскольку он терпит неудачу на моей машине, но, по-видимому, это так, потому что он загружается в lli уже и lli вызывает sys::DynamicLibrary::LoadLibraryPermanently(nullptr), чтобы добавить символы программы в свое пространство поиска JIT ( s. https://github.com/llvm-mirror/llvm/blob/release_40/tools/lli/OrcLazyJIT.cpp#L110).

Ответ 2

В списке рассылки LLVM-dev указано:

Что это значит?

Llvm-backend в orcjit в настоящее время не поддерживает локальное хранилище потоков (TLS)

минимальный пример:

extern thread_local int tls;
int main() {
    tls = 42;
    return 0;
}

с использованием -stdlib = libС++ компилируется и успешно запускается *; какие конкретные функции libstdС++ используют, что вызывает эту проблему?

это работает, потому что libС++ future:: get реализация не использует ключевое слово thread_local.

Существуют ли какие-либо флагов-компиляторы, которые исправляют эту проблему?

в настоящее время нет решения. Использование lli -relocation-model=pic обрабатывает эту проблему с ошибкой перемещения.