Как заставить команду LLVM `opt` оптимизировать встроенные функции?

#clang #llvm #llvm-clang

#clang #llvm #llvm-clang

Вопрос:

Рассмотрим следующую программу на C:

 #include <stdlib.h>

int main() {
    int * ptr = malloc(8);
    *ptr = 14;
    return 4;
}
  

Компиляция с помощью clang -S -emit-llvm -O1 выдает следующее:

 ...
; Function Attrs: norecurse nounwind readnone uwtable
define dso_local i32 @main() local_unnamed_addr #0 !dbg !7 {
  call void @llvm.dbg.value(metadata i32* undef, metadata !13, metadata !DIExpression()), !dbg !15
  ret i32 4, !dbg !16
}
...
  

Вызов malloc пропал, потому что это встроенная функция, о которой clang известно.
Если мы запустим clang -S -emit-llvm -O1 -fno-builtin вместо этого, мы получим следующее:

 ...
; Function Attrs: nounwind uwtable
define dso_local i32 @main() local_unnamed_addr #0 !dbg !14 {
  %1 = call noalias i8* @malloc(i64 8) #3, !dbg !22
  %2 = bitcast i8* %1 to i32*, !dbg !22
  call void @llvm.dbg.value(metadata i32* %2, metadata !20, metadata !DIExpression()), !dbg !23
  store i32 14, i32* %2, align 4, !dbg !24, !tbaa !25
  ret i32 4, !dbg !29
}
...
  

clang не могу знать, что malloc такое, и должен оставить вызов.

Как я могу перейти от второй программы LLVM к первой, используя opt команду LLVM? Как мне сказать, opt использовать знания о встроенных функциях, которые clang , по-видимому, есть?

Комментарии:

1. Вы должны выполнить правильный проход. Опция -print-after-all печатает IR после каждого прохода; вы можете изучить выходные данные и выяснить, какой проход имеет значение в clang, а затем запустить этот проход с помощью opt.

2. Спасибо, вызов malloc удаляется обычным InstCombine проходом. Печать, с помощью которой выполняются проходы, -debug-pass=Arguments дает точно такой же результат с или без -fno-builtin .

Ответ №1:

В этом конкретном примере проблема заключается в том, что clang -fno-builtin будет создан код LLVM, который явно помечает вызовы встроенных функций nobuiltin , т. е. attributes #3 = { nobuiltin nounwind "no-builtins" } .

Как правило, какие встроенные функции доступны, угадывается путем прохода -targetlibinfo . Вы должны быть осторожны, чтобы объявлять и использовать встроенные функции с точно правильным параметром и возвращаемыми типами, иначе LLVM (правильно) не распознает их как встроенные.