Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ЛР9.docx
Скачиваний:
0
Добавлен:
02.08.2026
Размер:
2 Мб
Скачать

6) Вызов calculate из main

  • При -O2 и включённом inlining функция calculate может быть заинлайнена в main, так как её тело достаточно компактно.

  • Тогда компилятор знает конкретные значения base = 10, iterations = 5 и может частично или полностью свёрнуть цикл:

    • цикл от i = 0 до 4 — конечное количество итераций,

    • все вычисления могут быть выполнены в compile-time,

    • итоговая функция main может свестись к:

    • int main() {

    • printf("Result: %d\n", <константа>);

    • return 0;

    • }

Типы оптимизаций в этой программе:

  • Constant folding (100 * 50, (10 + 20) * 3 и возможные составные выражения).

  • Loop-invariant code motion (вынос invariant из цикла).

  • Strength reduction (i % 2 → i & 1).

  • Упрощение ветвлений (использование select).

  • Inlining (встраивание calculate в main).

  • Dead code elimination (удаление неиспользуемых временных переменных).

  • Упрощение CFG, сокращение числа переходов.

Рисунок 22 - Сгенерированный ассемблер с оптимизатором -O0

Рисунок 23 - Продолжение сгенерированного ассемблера с оптимизатором -O0

Рисунок 24 - Сгенерированный LLVM IR с оптимизатором -O0

Рисунок 25 - Продолжение сгенерированного LLVM IR с оптимизатором -O0

Рисунок 26 - Сгенерированный ассемблер с оптимизатором -O1

Рисунок 27 - Сгенерированный LLVM IR с оптимизатором -O1

Рисунок 28 - Сгенерированный ассемблер с оптимизатором -O2

Рисунок 29 - Продолжение сгенерированного ассемблера с оптимизатором -O2

Рисунок 30 - Продолжение сгенерированного ассемблера с оптимизатором -O2

Рисунок 31 - Сгенерированный LLVM IR с оптимизатором -O2

Рисунок 32 - Продолжение сгенерированного LLVM IR с оптимизатором -O2

Тексты программ: исходные и “оптимизированные”

5.1. Исходный вариант (все листинги одним файлом)

#include <stdio.h>

// Листинг 1

int constant_operations() {

int a = 10 + 20 * 5;

int b = (1 << 4) | 0x0F;

float c = 3.14 * 2.0 + 1.0;

return a + b + (int)c;

}

// Листинг 2

int dead_code_elimination() {

int x = 10;

int y = 20;

int z = x + y;

int unused1 = 100;

int unused2 = 200;

if (0) {

unused1 = 300;

}

return z;

}

// Листинг 3

int helper1(int a, int b) {

return a * b + 10;

}

int helper2(int x) {

return helper1(x, x + 1);

}

int main_inline() {

int result = 0;

for (int i = 0; i < 10; i++) {

result += helper2(i);

}

return result;

}

// Листинг 4

int simple_loop() {

int sum = 0;

for (int i = 0; i < 100; i++) {

sum += i;

}

return sum;

}

int loop_with_invariant(int n) {

int result = 0;

int constant = 100 * 50;

for (int i = 0; i < n; i++) {

result += i + constant;

}

return result;

}

int nested_loops() {

int sum = 0;

for (int i = 0; i < 10; i++) {

for (int j = 0; j < 10; j++) {

sum += i * j;

}

}

return sum;

}

// Листинг 5

int calculate(int base, int iterations) {

int result = base;

if (iterations < 0) {

printf("This should never happen\n");

return -1;

}

for (int i = 0; i < iterations; i++) {

if (i % 2 == 0) {

result += i * 2;

} else {

result += i;

}

int invariant = 100 * 50;

result += invariant;

}

int final_adjustment = (10 + 20) * 3;

result += final_adjustment;

return result;

}

int main() {

int value = calculate(10, 5);

printf("Result: %d\n", value);

return 0;

}

5.2. Вариант “после оптимизации” (ручная эквивалентная оптимизация)

Это не обязательно совпадает 1:1 с реальным выводом Clang, но отражает те же идеи оптимизации.

#include <stdio.h>

// Листинг 1 – свёртка констант

int constant_operations_opt() {

// 10 + 20*5 = 110

// (1 << 4) | 0x0F = 31

// (int)(3.14*2.0 + 1.0) ≈ 7

return 110 + 31 + 7; // 148

}

// Листинг 2 – удаление мёртвого кода

int dead_code_elimination_opt() {

// unused1, unused2 и if (0) удалены

return 10 + 20; // 30

}

// Листинг 3 – инлайнинг

int main_inline_opt() {

int result = 0;

for (int i = 0; i < 10; i++) {

// helper2(i) = helper1(i, i + 1) = i*(i+1) + 10

result += i * (i + 1) + 10;

}

return result;

}

// Листинг 4 – циклы

// simple_loop: сумма от 0 до 99 заранее известна

int simple_loop_opt() {

return 4950;

}

int loop_with_invariant_opt(int n) {

int result = 0;

const int constant = 100 * 50; // 5000

for (int i = 0; i < n; i++) {

result += i + constant;

}

return result;

}

int nested_loops_opt() {

int sum = 0;

// те же вложенные циклы, но компилятор может частично развернуть

for (int i = 0; i < 10; i++) {

for (int j = 0; j < 10; j++) {

sum += i * j;

}

}

return sum;

}

// Листинг 5 – сложная программа

int calculate_opt(int base, int iterations) {

if (iterations < 0) {

// ветка не удаляется, т.к. зависит от аргумента

printf("This should never happen\n");

return -1;

}

int result = base;

const int invariant = 100 * 50; // 5000

const int final_adjustment = (10 + 20) * 3; // 90

for (int i = 0; i < iterations; i++) {

if ((i & 1) == 0) { // i % 2 == 0

result += i * 2;

} else {

result += i;

}

result += invariant;

}

result += final_adjustment;

return result;

}

int main_opt() {

int value = calculate_opt(10, 5);

printf("Result: %d\n", value);

return 0;

}

Соседние файлы в предмете Системное программное обеспечение