#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 (правильно) не распознает их как встроенные.