C ++ / LLVM: генерация кода времени выполнения и контейнер STL

Предположим простой частичный сценарий оценки:

#include <vector>

/* may be known at runtime */
int someConstant();

/* can be partially evaluated */
double foo(std::vector<double> args) {
return args[someConstant()] * someConstant();
}

Скажем так someConstant() известен и не изменяется во время выполнения (например, предоставляется пользователем один раз) и может быть заменен соответствующим литералом int. Если foo является частью горячего пути, я ожидаю значительного улучшения производительности:

/* partially evaluated, someConstant() == 2 */
double foo(std::vector<double> args) {
return args[2] * 2;
}

Мое текущее решение этой проблемы заключается в том, чтобы генерировать LLVM IR во время выполнения, потому что я знаю структуру частично оцененного кода (поэтому мне не понадобится частичный оценщик общего назначения).
Поэтому я хочу написать функцию foo_ir который генерирует ИК-код, который делает то же самое, что и foo, но не звонит someConstant()потому что это известно во время выполнения.
Достаточно просто, не правда ли? Тем не менее, когда я смотрю на сгенерированный IR для кода выше:

 ; Function Attrs: uwtable
define double @_Z3fooSt6vectorIdSaIdEE(%"class.std::vector"* %args) #0 {
%1 = call i32 @_Z12someConstantv()
%2 = sext i32 %1 to i64
%3 = call double* @_ZNSt6vectorIdSaIdEEixEm(%"class.std::vector"* %args, i64 %2)
%4 = load double* %3
%5 = call i32 @_Z12someConstantv()
%6 = sitofp i32 %5 to double
%7 = fmul double %4, %6
ret double %7
}

; Function Attrs: nounwind uwtable
define linkonce_odr double* @_ZNSt6vectorIdSaIdEEixEm(%"class.std::vector"* %this, i64 %__n) #1 align 2 {
%1 = alloca %"class.std::vector"*, align 8
%2 = alloca i64, align 8
store %"class.std::vector"* %this, %"class.std::vector"** %1, align 8
store i64 %__n, i64* %2, align 8
%3 = load %"class.std::vector"** %1
%4 = bitcast %"class.std::vector"* %3 to %"struct.std::_Vector_base"*
%5 = getelementptr inbounds %"struct.std::_Vector_base"* %4, i32 0, i32 0
%6 = getelementptr inbounds %"struct.std::_Vector_base<double, std::allocator<double> >::_Vector_impl"* %5, i32 0, i32 0
%7 = load double** %6, align 8
%8 = load i64* %2, align 8
%9 = getelementptr inbounds double* %7, i64 %8
ret double* %9
}

Я вижу, что [] был включен из определения STL (функция @_ZNSt6vectorIdSaIdEEixEm) — справедливо. Проблема в том, что это может быть также функция-член или даже прямой доступ к данным, я просто не могу предположить, что расположение данных везде одинаково, поэтому во время разработки я не знаю конкретных std::vector макет хост-машины.

Есть ли способ использовать метапрограммирование C ++ для получения необходимой информации во время компиляции? то есть есть ли способ попросить llvm предоставить IR для std::vector«s [] метод?

В качестве бонуса: я бы предпочел не применять компиляцию библиотеки с помощью clang, вместо этого LLVM должен зависеть от времени выполнения, поэтому просто вызов clang во время компиляции (даже если я не знаю, как это сделать) — это вторая -лучшее решение.

5

Решение

Отвечая на мой собственный вопрос:

Хотя у меня до сих пор нет решения для общего случая (например, std::map), существует простое решение для std::vector:

В соответствии с стандарт C ++, следующее верно для функции-члена data()

Возвращает прямой указатель на массив памяти, используемый внутри
вектор для хранения принадлежащих ему элементов.

Поскольку элементы в векторе гарантированно хранятся в
смежные места хранения в том же порядке, как представлено
вектор, полученный указатель может быть смещен для доступа к любому элементу в
массив.

Так на самом деле, макет уровня объекта std::vector фиксируется стандартом.

3

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]