Вот пример, показывающий, что ляг LLVM с уровнем оптимизации O3
обрабатывает класс с одним двойным элементом данных так же, как это было дважды:
$ cat main.cpp
#include <stdio.h>
class MyDouble {
public:
double d;
MyDouble(double _d):d(_d){}
};
void foo(MyDouble d)
{
printf("%lg\n",d.d);
}
int main(int argc, char **argv)
{
if (argc>5)
{
double x=(double)argc;
MyDouble d(x);
foo(d);
}
return 0;
}
Когда я компилирую его и просматриваю сгенерированный файл битового кода, я вижу, что foo ведет себя
как будто он работает с входным параметром типа double
:
$ clang++ -O3 -c -emit-llvm main.cpp
$ llvm-dis main.bc
Вот соответствующая часть:
; Function Attrs: nounwind uwtable
define void @_Z3foo8MyDouble(double %d.coerce) #0 {
entry:
%call = tail call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([5 x i8]* @.str, i64 0, i64 0), double %d.coerce)
ret void
}
Посмотрите, как foo
объявляет свой входной параметр как double
и перемещает его для
печать `` как есть ". Теперь давайте скомпилируем точно такой же код с помощью O0
:
$ clang++ -O0 -c -emit-llvm main.cpp
$ llvm-dis main.bc
Когда мы смотрим на соответствующую часть, мы видим, что clang использует инструкцию getelementptr для доступа к своему первому (и единственному) элементу данных d
:
; Function Attrs: uwtable
define void @_Z3foo8MyDouble(double %d.coerce) #0 {
entry:
%d = alloca %class.MyDouble, align 8
%coerce.dive = getelementptr %class.MyDouble* %d, i32 0, i32 0
store double %d.coerce, double* %coerce.dive, align 1
%d1 = getelementptr inbounds %class.MyDouble* %d, i32 0, i32 0
%0 = load double* %d1, align 8
%call = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([5 x i8]* @.str, i32 0, i32 0), double %0)
ret void
}