Добавление встроенных функций с помощью прохода LLVM

Я добавил внутреннюю функцию во входной код, используя проход LLVM. Я могу видеть внутренний вызов, но не могу понять, как скомпилировать код для моей целевой архитектуры (x86_64). Я выполняю следующую команду:

clang++ $(llvm-config --ldflags --libs all) ff.s -o foo

Но компоновщик жалуется на неопределенные ссылки:

/tmp/ff-2ada42.o: In function `fact(unsigned int)':
/home/rubens/Desktop/ff.cpp:9: undefined reference to `llvm.x86.sse3.mwait.i32.i32'
/tmp/ff-2ada42.o: In function `fib(unsigned int)':
/home/rubens/Desktop/ff.cpp:16: undefined reference to `llvm.x86.sse3.mwait.i32.i32'
/home/rubens/Desktop/ff.cpp:16: undefined reference to `llvm.x86.sse3.mwait.i32.i32'
/home/rubens/Desktop/ff.cpp:16: undefined reference to `llvm.x86.sse3.mwait.i32.i32'

Несмотря на использование ldflags из llvm-config, компиляция не продолжается. Есть идеи, что нужно сделать для правильной компиляции кода?

Чтобы сгенерировать код сборки, я сделал следующее:

# Generating optimized code
clang++ $(llvm-config --cxxflags) -emit-llvm -c ff.cpp -o ff.bc
opt ff.bc -load path/to/mypass.so -mypass > opt_ff.bc

# Generating assembly
llc opt_ff.bc -o ff.s

Сейчас я использую llvm версии 3.4.2; clang версии 3.4.2 (теги / RELEASE_34 / dot2-final); gcc версии 4.9.2 (GCC); и Linux 3.17.2-1-ARCH x86_64.


Изменить: добавление IR с внутренним:

Файл ~ / llvm / include / llvm / IR / IntrinsicsX86.td:

...
589 // Thread synchronization ops.                                          
590 let TargetPrefix = "x86" in {  // All intrinsics start with "llvm.x86.".
591     def int_x86_sse3_monitor : GCCBuiltin<"__builtin_ia32_monitor">,      
592               Intrinsic<[], [llvm_ptr_ty,                               
593                          llvm_i32_ty, llvm_i32_ty], []>;                
594     def int_x86_sse3_mwait : GCCBuiltin<"__builtin_ia32_mwait">,          
595               Intrinsic<[], [llvm_i32_ty,                               
596                          llvm_i32_ty], []>;                             
597 }                                                                       
...

И звонки (из файла ff.s):

...
.Ltmp2:                                       
    callq   llvm.x86.sse3.mwait.i32.i32   
    movl    $_ZStL8__ioinit, %edi         
    callq   _ZNSt8ios_base4InitC1Ev       
    movl    $_ZNSt8ios_base4InitD1Ev, %edi
    movl    $_ZStL8__ioinit, %esi         
    movl    $__dso_handle, %edx           
    callq   __cxa_atexit                  
    popq    %rax                          
    ret                                   
...

Изменить 2: вот как я добавляю встроенный во время прохода opt:

Function *f(bb->getParent());
Module *m(f->getParent());

std::vector<Type *> types(2, Type::getInt32Ty(getGlobalContext()));
Function *mwait = Intrinsic::getDeclaration(m, Intrinsic::x86_sse3_mwait, types);

std::vector<Value *> args;
IRBuilder<> builder(&bb->front());
for (uint32_t i : {1, 2}) args.push_back(builder.getInt32(i));

ArrayRef<Value *> args_ref(args);
builder.CreateCall(mwait, args_ref);

person Rubens    schedule 19.12.2014    source источник
comment
Можете ли вы поделиться LLVM IR с внутренним с обоими: вызовом внутреннего и там объявлением?   -  person Michael Haidl    schedule 19.12.2014
comment
@MichaelHaidl Я добавил информацию о запросе. Я ожидал, что внутренние вызовы будут расширены до ассоциированных встроенных функций, но вызов остается в файле сборки после компиляции.   -  person Rubens    schedule 19.12.2014
comment
Я говорил о LLVM IR. Вы можете использовать llvm-dis, чтобы сделать ваши файлы .bc читаемыми, или передать -S для выбора. Было бы также интересно, как вы добавляете внутреннюю функцию и вызов в свой пропуск. в настоящее время похоже, что вызываемая функция не является внутренней, а просто функцией с тем же именем, что и встроенная функция llvm.   -  person Michael Haidl    schedule 20.12.2014


Ответы (1)


РЕДАКТИРОВАТЬ: в настоящее время я пишу проход LLVM, который в основном выполняет то, что вы пытались сделать в этом вопросе. Проблема с вашим кодом заключается в следующем:

std::vector<Type *> types(2, Type::getInt32Ty(getGlobalContext()));
Function *mwait = Intrinsic::getDeclaration(m, Intrinsic::x86_sse3_mwait, types);

Вы пытаетесь получить замедление для внутренней функции с именем llvm.x86.sse3.mwait.i32.i32, а эта внутренняя функция не существует. Однако существует llvm.x86.sse3.mwait, поэтому вы должны написать следующее:

Function *mwait = Intrinsic::getDeclaration(m, Intrinsic::x86_sse3_mwait);

обратите внимание на отсутствующий аргумент типа для вызова. Это потому, что llvm.x86.sse3.mwait не имеет перегрузок.

Надеюсь, вы тем временем в этом разобрались.


Хорошо, так как я хочу ответить вам некоторое время, вот ответ безумной догадки.

Проблема в том, как вы добавляете встроенную функцию через проход оптимизатора. Похоже, вы просто создаете функцию с тем же именем, что и внутренняя функция, а не сама встроенная функция.

Вот небольшой код на C ++, который просто использует встроенный clang для получения внутренней функции внутри IR (я использую clang 3.5, но это не должно иметь никакого влияния).

int main ()
{
    __builtin_ia32_mwait(4,2);
}

Компилируя его с clang -emit-llvm -S, я получаю:

; ModuleID = 'intrin.cpp'
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

; Function Attrs: nounwind uwtable
define i32 @main() #0 {
  call void @llvm.x86.sse3.mwait(i32 4, i32 2)
  ret i32 0
}

; Function Attrs: nounwind
declare void @llvm.x86.sse3.mwait(i32, i32) #1

attributes #0 = { nounwind uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { nounwind }

!llvm.ident = !{!0}

!0 = metadata !{metadata !"clang version 3.5.0 "}

Обратите внимание, что встроенный SSE3 не имеет перегрузок типов, как в вашей версии.

Использование llc в сгенерированном файле дает мне:

.Ltmp2:
        .cfi_def_cfa_register %rbp
        movl    $4, %ecx
        movl    $2, %eax
        mwait
        xorl    %eax, %eax
        popq    %rbp
        retq

Правильная сборка создана.

Поэтому я предполагаю, что способ, которым вы вводите внутреннюю функцию в функцию, неверен в вашем проходе opt.

Получите внутреннюю функцию и вызовите ее:

vector<Type*> types;
types.push_back(IntegerType::get(/*LLVM context*/, 32));
types.push_back(IntegerType::get(/*LLVM context*/, 32));

Function* func = Intrinsic::getDeclaration(/* module */, Intrinsic::x86_sse3_mwait, types);
CallInst* call = CallInst::Create(func, /* arguments */);

person Michael Haidl    schedule 19.12.2014
comment
Спасибо за ответ. Я использую почти тот же метод, который вы указали, чтобы вставить внутреннюю функцию. Видите ли вы в моем коде какую-нибудь ловушку, которая может помешать мне расширить внутреннюю функцию в окончательной сборке? Мне кажется, что при запуске llc не хватает какого-то флага или аргумента, поскольку функция llvm.x86.sse3.mwait.i32.i32 появляется в моей сборке. - person Rubens; 20.12.2014
comment
Что ж, это странно, попробуйте получить внутреннее отклонение без чего-либо в векторе типов. Возможно, проблема в перегрузке типов. Если это не так, вы можете посмотреть флаги командной строки -mcpu или -mattr от llc. - person Michael Haidl; 20.12.2014
comment
Не могли бы вы добавить, какие флаги вы использовали для генерации кода сборки с llc? Это может пролить свет на то, почему я не расширяю тело функции. - person Rubens; 21.12.2014
comment
Я просто использовал llc input.ll -o input.S - person Michael Haidl; 21.12.2014
comment
@Rubens Я обновил свой ответ, надеюсь, вы сами разобрались в этом. - person Michael Haidl; 19.01.2015
comment
Работает как шарм! Большое спасибо за ответ! : D Кстати, я серьезно подумываю о том, чтобы предложить запись llvm в stackexchange. Что вы думаете? - person Rubens; 21.01.2015
comment
@Rubens +1 за эту идею! - person Michael Haidl; 21.01.2015
comment
Предлагаемый area51.stackexchange.com/proposals/82389/ Надеюсь, вы присоединитесь к группе! : D - person Rubens; 22.01.2015