Если оптимизация времени компоновки (LTO) используется с gcc или clang, возможна ли оптимизация кода на границе языков C и C++?
Например, можно ли встроить функцию C в вызывающую программу C++?
Если оптимизация времени компоновки (LTO) используется с gcc или clang, возможна ли оптимизация кода на границе языков C и C++?
Например, можно ли встроить функцию C в вызывающую программу C++?
Да!
Оптимизация времени компоновки обычно работает с промежуточным представлением (IR), представленным в «толстых» объектных файлах, которые могут содержать как машинный код для традиционной компоновки, так и IR для компоновки LTO.
На данном этапе языковых конструкций высокого уровня больше нет, поэтому оптимизация времени компоновки не зависит от языка.
оптимизация времени компоновки (LTO) GCC работает с GIMPLE, одним из промежуточные представления. IR всегда не зависит от языка, поэтому любые оптимизации времени компоновки будут работать в коде, сгенерированном на любом языке.
Из документации по Параметры оптимизации GCC:
Еще одна особенность LTO заключается в том, что можно применять межпроцедурные оптимизации к файлам, написанным на разных языках:
gcc -c -flto foo.c g++ -c -flto bar.cc gfortran -c -flto baz.f90 g++ -o myprog -flto -O3 foo.o bar.o baz.o -lgfortran
Обратите внимание, что последняя ссылка делается с помощью g++ для получения библиотек времени выполнения C++, а
-lgfortran
добавляется для получения библиотек времени выполнения Fortran. Как правило, при смешивании языков в режиме LTO следует использовать те же параметры команды link, что и при смешивании языков в обычной (не LTO) компиляции.
Вот пример, чтобы показать вам, насколько мощной является эта технология. Мы определим функцию C и вызовем ее из программы C++:
func.h
#ifndef FUNC_DOT_H
#define FUNC_DOT_H
#ifdef __cplusplus
extern "C" {
#endif
int func(int a, int b, int c);
#ifdef __cplusplus
}
#endif
#endif /* FUNC_DOT_H */
func.c
#include "func.h"
int func(int a, int b, int c)
{
return 3*a + 2*b + c;
}
main.cpp
#include "func.h"
int main()
{
int a = 1;
int b = 2;
int c = 3;
return func(a, b, c);
}
Скомпилировать
gcc -o func.o -c -Wall -Werror -flto -O2 func.c
g++ -o main.o -c -Wall -Werror -flto -O2 main.cpp
g++ -o testlto -flto -O2 main.o func.o
Разобрать (objdump -Mintel -d -R -C testlto
)
Disassembly of section .text:
00000000004003d0 <main>:
4003d0: b8 0a 00 00 00 mov eax,0xa ; 1*3 + 2*2 + 3 = 10
4003d5: c3 ret
Вы можете видеть, что он не только встроил мой C func()
в мой C++ main()
, но и превратил все это в константное выражение!
Используя тот же синтаксис, Clang может создавать «толстые» объектные файлы с LLVM IR, которые можно оптимизировать во время компоновки. См. раздел Оптимизация времени соединения LLVM.
Используя тот же тестовый код, что и выше, clang дает точно такой же результат:
00000000004004b0 <main>:
4004b0: b8 0a 00 00 00 mov eax,0xa
4004b5: c3 ret
.o
? В действительно странном случае, когда ваши gcc
и g++
были разными версиями, я думаю, это может иметь значение.
- person BeeOnRope; 30.12.2017
.a
был жиром компилятора и содержит IR, но был сгенерирован другим способом, на другой машине или в другое время, чем окончательный исполняемый файл. В этом случае GIMPLE в '.a' может быть проигнорирован, если он не совместим с локальным компилятором. Конечно, это всего лишь общая ошибка для LTO по сравнению с традиционным связыванием, и она не применяется конкретно к межъязыковой оптимизации.
- person BeeOnRope; 30.12.2017
func.o
- это просто битовый код LLVM IR, поэтому его нельзя скомпилировать ни с чем, кроме clang (предположительно, должно быть возможно и обратное, хотя в данный момент я борюсь): stackoverflow.com/questions/51259340/
- person jberryman; 06.03.2019