Алексей Денисов

https://lowlevelbits.org
Оптимизации компилятора
Для Podlodka iOS Crew
1
• https://lowlevelbits.org

• https://twitter.com/1101_debian

• https://github.com/AlexDenisov
2
Обо мне
• Как компилятор оптимизирует программы

• Как компилятор видит программы

• Оптимизации скорости

• Оптимизации памяти

• Измерение оптимизаций
3
План
Что такое оптимизация?
int main() {


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


print(i);


}


return 0;


}
4
Что такое оптимизация?
int main() {


return 0;


}
5
Какие бывают оптимизации?
• скорость программы

• размер программы

• потребление памяти

• потребление энергии

• безопасность

• обфускация

• рефакторинг?

• разработка???
6
Как компилятор оптимизирует программы
bool condition(int i);


void case_0();


void case_1();


void case_2();


int main() {


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


if (condition(i)) {


goto first_label;


} else {


goto second_label;


}


case_0();


first_label:


case_1();


goto exit;


second_label:


case_2();


goto exit;


// next iteration?


}


exit:


return 0;


}
7
Как компилятор оптимизирует программы
bool condition(int i);


void case_0();


void case_1();


void case_2();


int main() {


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


if (condition(i)) {


goto first_label;


} else {


goto second_label;


}


case_0();


first_label:


case_1();


goto exit;


second_label:


case_2();


goto exit;


// next iteration?


}


exit:


return 0;


}
for (int i = 0;


i < 10000;


i++)
8
Как компилятор оптимизирует программы
bool condition(int i);


void case_0();


void case_1();


void case_2();


int main() {


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


if (condition(i)) {


goto first_label;


} else {


goto second_label;


}


case_0();


first_label:


case_1();


goto exit;


second_label:


case_2();


goto exit;


// next iteration?


}


exit:


return 0;


}
if (condition(i))
for (int i = 0;


i < 10000;


i++)
9
Как компилятор оптимизирует программы
bool condition(int i);


void case_0();


void case_1();


void case_2();


int main() {


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


if (condition(i)) {


goto first_label;


} else {


goto second_label;


}


case_0();


first_label:


case_1();


goto exit;


second_label:


case_2();


goto exit;


// next iteration?


}


exit:


return 0;


}
if (condition(i))
for (int i = 0;


i < 10000;


i++)
goto first_label; goto second_label;
10
Как компилятор оптимизирует программы
bool condition(int i);


void case_0();


void case_1();


void case_2();


int main() {


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


if (condition(i)) {


goto first_label;


} else {


goto second_label;


}


case_0();


first_label:


case_1();


goto exit;


second_label:


case_2();


goto exit;


// next iteration?


}


exit:


return 0;


}
if (condition(i))
for (int i = 0;


i < 10000;


i++)
goto first_label; goto second_label;
case_0();
11
Как компилятор оптимизирует программы
bool condition(int i);


void case_0();


void case_1();


void case_2();


int main() {


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


if (condition(i)) {


goto first_label;


} else {


goto second_label;


}


case_0();


first_label:


case_1();


goto exit;


second_label:


case_2();


goto exit;


// next iteration?


}


exit:


return 0;


}
if (condition(i))
for (int i = 0;


i < 10000;


i++)
goto first_label; goto second_label;
case_0();
first_label:


case_1();


goto exit;
second_label:


case_2();


goto exit;
12
Как компилятор оптимизирует программы
bool condition(int i);


void case_0();


void case_1();


void case_2();


int main() {


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


if (condition(i)) {


goto first_label;


} else {


goto second_label;


}


case_0();


first_label:


case_1();


goto exit;


second_label:


case_2();


goto exit;


// next iteration?


}


exit:


return 0;


}
if (condition(i))
for (int i = 0;


i < 10000;


i++)
goto first_label; goto second_label;
case_0();
first_label:


case_1();


goto exit;
second_label:


case_2();


goto exit;
exit:


return 0;
13
Как компилятор оптимизирует программы
bool condition(int i);


void case_0();


void case_1();


void case_2();


int main() {


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


if (condition(i)) {


goto first_label;


} else {


goto second_label;


}


case_0();


first_label:


case_1();


goto exit;


second_label:


case_2();


goto exit;


// next iteration?


}


exit:


return 0;


}
if (condition(i))
for (int i = 0;


i < 10000;


i++)
goto first_label; goto second_label;
case_0();
first_label:


case_1();


goto exit;
second_label:


case_2();


goto exit;
exit:


return 0;
// next iteration?
14
Как компилятор оптимизирует программы
bool condition(int i);


void case_0();


void case_1();


void case_2();


int main() {


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


if (condition(i)) {


goto first_label;


} else {


goto second_label;


}


case_0();


first_label:


case_1();


goto exit;


second_label:


case_2();


goto exit;


// next iteration?


}


exit:


return 0;


}
if (condition(i))
for (int i = 0;


i < 10000;


i++)
goto first_label; goto second_label;
case_0();
first_label:


case_1();


goto exit;
second_label:


case_2();


goto exit;
exit:


return 0;
// next iteration?
15
Как компилятор оптимизирует программы
bool condition(int i);


void case_0();


void case_1();


void case_2();


int main() {


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


if (condition(i)) {


goto first_label;


} else {


goto second_label;


}


case_0();


first_label:


case_1();


goto exit;


second_label:


case_2();


goto exit;


// next iteration?


}


exit:


return 0;


}
if (condition(i))
for (int i = 0;


i < 10000;


i++)
goto first_label; goto second_label;
case_0();
first_label:


case_1();


goto exit;
second_label:


case_2();


goto exit;
exit:


return 0;
// next iteration?
16
Как компилятор оптимизирует программы
bool condition(int i);


void case_0();


void case_1();


void case_2();


int main() {


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


if (condition(i)) {


goto first_label;


} else {


goto second_label;


}


case_0();


first_label:


case_1();


goto exit;


second_label:


case_2();


goto exit;


// next iteration?


}


exit:


return 0;


}
if (condition(i))
for (int i = 0;


i < 10000;


i++)
goto first_label; goto second_label;
case_0();
first_label:


case_1();


goto exit;
second_label:


case_2();


goto exit;
exit:


return 0;
// next iteration?
17
Как компилятор оптимизирует программы
bool condition(int i);


void case_0();


void case_1();


void case_2();


int main() {


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


if (condition(i)) {


goto first_label;


} else {


goto second_label;


}


case_0();


first_label:


case_1();


goto exit;


second_label:


case_2();


goto exit;


// next iteration?


}


exit:


return 0;


}
if (condition(i))
for (int i = 0;


i < 10000;


i++)
goto first_label; goto second_label;
case_0();
first_label:


case_1();


goto exit;
second_label:


case_2();


goto exit;
exit:


return 0;
// next iteration?
18
Как компилятор оптимизирует программы
bool condition(int i);


void case_0();


void case_1();


void case_2();


int main() {


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


if (condition(i)) {


goto first_label;


} else {


goto second_label;


}


case_0();


first_label:


case_1();


goto exit;


second_label:


case_2();


goto exit;


// next iteration?


}


exit:


return 0;


}
if (condition(i))
for (int i = 0;


i < 10000;


i++)
goto first_label; goto second_label;
case_0();
first_label:


case_1();


goto exit;
second_label:


case_2();


goto exit;
exit:


return 0;
// next iteration?
19
Как компилятор оптимизирует программы
bool condition(int i);


void case_0();


void case_1();


void case_2();


int main() {


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


if (condition(i)) {


goto first_label;


} else {


goto second_label;


}


case_0();


first_label:


case_1();


goto exit;


second_label:


case_2();


goto exit;


// next iteration?


}


exit:


return 0;


}
if (condition(i))
for (int i = 0;


i < 10000;


i++)
goto first_label; goto second_label;
case_0();
first_label:


case_1();


goto exit;
second_label:


case_2();


goto exit;
exit:


return 0;
// next iteration?
20
Как компилятор оптимизирует программы
bool condition(int i);


void case_0();


void case_1();


void case_2();


int main() {


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


if (condition(i)) {


goto first_label;


} else {


goto second_label;


}


case_0();


first_label:


case_1();


goto exit;


second_label:


case_2();


goto exit;


// next iteration?


}


exit:


return 0;


}
if (condition(i))
for (int i = 0;


i < 10000;


i++)
goto first_label; goto second_label;
case_0();
first_label:


case_1();


goto exit;
second_label:


case_2();


goto exit;
exit:


return 0;
// next iteration?
21
Как компилятор оптимизирует программы
bool condition(int i);


void case_0();


void case_1();


void case_2();


int main() {


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


if (condition(i)) {


goto first_label;


} else {


goto second_label;


}


case_0();


first_label:


case_1();


goto exit;


second_label:


case_2();


goto exit;


// next iteration?


}


exit:


return 0;


}
if (condition(i))
for (int i = 0;


i < 10000;


i++)
goto first_label; goto second_label;
case_0();
first_label:


case_1();


goto exit;
second_label:


case_2();


goto exit;
exit:


return 0;
// next iteration?
22
Как компилятор оптимизирует программы
bool condition(int i);


void case_0();


void case_1();


void case_2();


int main() {


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


if (condition(i)) {


goto first_label;


} else {


goto second_label;


}


case_0();


first_label:


case_1();


goto exit;


second_label:


case_2();


goto exit;


// next iteration?


}


exit:


return 0;


}
if (condition(0))
for (int i = 0;


i < 10000;


i++)
goto first_label; goto second_label;
case_0();
first_label:


case_1();


goto exit;
second_label:


case_2();


goto exit;
exit:


return 0;
// next iteration?
23
Как компилятор оптимизирует программы
bool condition(int i);


void case_0();


void case_1();


void case_2();


int main() {


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


if (condition(i)) {


goto first_label;


} else {


goto second_label;


}


case_0();


first_label:


case_1();


goto exit;


second_label:


case_2();


goto exit;


// next iteration?


}


exit:


return 0;


}
if (condition(0))
for (int i = 0;


i < 10000;


i++)
goto first_label; goto second_label;
case_0();
first_label:


case_1();


goto exit;
second_label:


case_2();


goto exit;
exit:


return 0;
// next iteration?
24
Как компилятор оптимизирует программы
bool condition(int i);


void case_0();


void case_1();


void case_2();


int main() {


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


if (condition(i)) {


goto first_label;


} else {


goto second_label;


}


case_0();


first_label:


case_1();


goto exit;


second_label:


case_2();


goto exit;


// next iteration?


}


exit:


return 0;


}
if (condition(0))
for (int i = 0;


i < 10000;


i++)
goto first_label; goto second_label;
case_0();
first_label:


case_1();


goto exit;
second_label:


case_2();


goto exit;
exit:


return 0;
// next iteration?
25
Как компилятор оптимизирует программы
bool condition(int i);


void case_0();


void case_1();


void case_2();


int main() {


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


if (condition(i)) {


goto first_label;


} else {


goto second_label;


}


case_0();


first_label:


case_1();


goto exit;


second_label:


case_2();


goto exit;


// next iteration?


}


exit:


return 0;


}
bool condition(int i);


void case_1();


void case_2();


int main() {


if (condition(0)) {


case_1();


} else {


case_2();


}


return 0;


}
26
Control Flow Graph
B1
Entry
B2 B4
B3
B5 B6
Exit
B7
27
Control Flow Graph
B1
Entry
B2 B4
B3
B5 B6
Exit
B7
28
Basic Block Predecessors Successors
Entry [ ] [ B1 ]
B1 [ Entry ] [ B2, B4 ]
B2 [ B1 ] [ B5 ]
B3 [ ] [ B5 ]
B4 [ B1 ] [ B6 ]
B5 [ B2 ] [ Exit ]
B6 [ B4 ] [ Exit ]
B7 [ ] [ Exit ]
Exit [ B5, B6, B7 ] [ ]
Control Flow Graph
B1
Entry
B2 B4
B3
B5 B6
Exit
B7
29
Basic Block Predecessors Successors
Entry [ ] [ B1 ]
B1 [ Entry ] [ B2, B4 ]
B2 [ B1 ] [ B5 ]
B3 [ ] [ B5 ]
B4 [ B1 ] [ B6 ]
B5 [ B2 ] [ Exit ]
B6 [ B4 ] [ Exit ]
B7 [ ] [ Exit ]
Exit [ B5, B6, B7 ] [ ]
Entry -> B1 -> B2 -> B5 -> Exit
Entry -> B1 -> B4 -> B6 -> Exit
Control Flow Graph
30
Basic Block Predecessors Successors
Entry [ ] [ B1 ]
B1 [ Entry ] [ B2, B4 ]
B2 [ B1 ] [ B5 ]
B3 [ ] [ B5 ]
B4 [ B1 ] [ B6 ]
B5 [ B2 ] [ Exit ]
B6 [ B4 ] [ Exit ]
B7 [ ] [ Exit ]
Exit [ B5, B6, B7 ] [ ]
func pred(_ bb: BasicBlock) -> [BasicBlock]


func succ(_ bb: BasicBlock) -> [BasicBlock]


func deadCodeElimination(f: Function) {


// 1


var reachable = [BasicBlock]()


var queue = [BasicBlock]()


queue.append(f.entry)


// 2


while !queue.isEmpty {


let head = queue.removeFirst()


reachable.append(head)


queue.append(contentsOf: succ(head))


}


// 3


for bb in f.basicBlocks {


if !reachable.contains(bb) {


f.removeBasicBlock(bb: bb)


}


}


}
Control Flow Graph
31
31
while (condition()) {


// body


}
if (condition()) {


// body


}
// body // body
if (condition()) {


// then body


} else {


// else body


}
condition() condition() condition()
// then // else
https://swift.godbolt.org/z/rG4KKEheG
Images:

https://icon-icons.com/icon/microchip-processor-chip-cpu/108630

https://icon-icons.com/icon/processor/47694

https://icon-icons.com/icon/ai-arti
fi
cial-intelligence-chip-technology-cpu/179503
 32
Constant-folding
Оптимизации скорости
let secondsPerDay = 60 * 60 * 24


print(secondPerDay)
print(86400)
33
Algebraic Simpli
fi
cation
Оптимизации скорости
func something(x: Int) {


print(x + 0)


print(x * 0)


print(x - 0)


print(x * 1)


}
func something(x: Int) {


print(x)


print(0)


print(x)


print(x)


}
34
Common-subexpression Elimination (CSE)
Оптимизации скорости
func something(a: Int, b: Int) {


let x = a + b


let y = a + b


}
func something(a: Int, b: Int) {


let t = a + b


let x = t


let y = t


}
35
Copy Propagation
Оптимизации скорости
func something(a: Int, b: Int) {


let x = a + b


let a1 = a


let y = a1 + b


let b1 = b


let z = a1 + b1


}
func something(a: Int, b: Int) {


let x = a + b


let a1 = a


let y = a + b


let b1 = b


let z = a + b


}
func something(a: Int, b: Int) {


let t = a + b


let x = t


let y = t


let z = t


}
36
Loop-invariant Code Motion (LICM)
Оптимизации скорости
func compute() -> Int {


// heavy stuff


}


for i in 0...10 {


let x = compute()


print(x + i)


}
func compute() -> Int {


// heavy stuff


}


let x = compute()


for i in 0...10 {


print(x + i)


}
37
Inlining
Оптимизации скорости
func getSomething() -> Int {


return 42


}


print(getSomething())
func getSomething() -> Int {


return 42


}


print(42)
38
Loop Unrolling
Оптимизации скорости
Demo
39
Tail-call оптимизация
40
Demo
Link-time оптимизация
41
Demo
What else?
Demo
42
Оптимизации и безопасность
43
char *getPWHash() {


long i; char pwd[64];


char *sha1 = (char*)malloc(41);


// read password


fgets(pwd, sizeof(pwd), stdin); // <<<


// calculate sha1 of password ... // <<<




// overwrite pwd in memory


// Alternative (A) : use memset


memset(pwd, 0, sizeof(pwd)); // (A)


// Alternative (B) : reset pwd in a loop


for (i=0; i<sizeof(pwd); ++i)


pwd[i]=0; // (B)




// return only hash of pwd


return sha1;


}
Оптимизации и безопасность
44
https://nebelwelt.net/publications/
fi
les/15LangSec.pdf
Оптимизации памяти
45
Оптимизации памяти
46
struct A {


let a: Int8


let b: Int16


let c: Int8


let d: Int64


}


typealias MLA = MemoryLayout<A>


print(MLA.size) // 16


print(MLA.stride) // 16


print(MLA.alignment) // 8


print(MLA.offset(of: A.a)!) // 0


print(MLA.offset(of: A.b)!) // 2


print(MLA.offset(of: A.c)!) // 4


print(MLA.offset(of: A.d)!) // 8
struct B {


let a: Int8


let b: Int8


let c: Int64


let d: Int16


}


typealias MLB = MemoryLayout<B>


print(MLB.size) // 18


print(MLB.stride) // 24


print(MLB.alignment) // 8


print(MLB.offset(of: B.a)!) // 0


print(MLB.offset(of: B.b)!) // 1


print(MLB.offset(of: B.c)!) // 8


print(MLB.offset(of: B.d)!) // 16
Оптимизации памяти
47
struct A {


let a: Int8


let b: Int16


let c: Int8


let d: Int64


}


typealias MLA = MemoryLayout<A>


print(MLA.size) // 16


print(MLA.stride) // 16


print(MLA.alignment) // 8


print(MLA.offset(of: A.a)!) // 0


print(MLA.offset(of: A.b)!) // 2


print(MLA.offset(of: A.c)!) // 4


print(MLA.offset(of: A.d)!) // 8
struct B {


let a: Int8


let b: Int8


let c: Int64


let d: Int16


}


typealias MLB = MemoryLayout<B>


print(MLB.size) // 18


print(MLB.stride) // 24


print(MLB.alignment) // 8


print(MLB.offset(of: B.a)!) // 0


print(MLB.offset(of: B.b)!) // 1


print(MLB.offset(of: B.c)!) // 8


print(MLB.offset(of: B.d)!) // 16
Оптимизации памяти
48
struct A {


let a: Int8


let b: Int16


let c: Int8


let d: Int64


}


typealias MLA = MemoryLayout<A>


print(MLA.size) // 16


print(MLA.stride) // 16


print(MLA.alignment) // 8


print(MLA.offset(of: A.a)!) // 0


print(MLA.offset(of: A.b)!) // 2


print(MLA.offset(of: A.c)!) // 4


print(MLA.offset(of: A.d)!) // 8
struct B {


let a: Int8


let b: Int8


let c: Int64


let d: Int16


}


typealias MLB = MemoryLayout<B>


print(MLB.size) // 18


print(MLB.stride) // 24


print(MLB.alignment) // 8


print(MLB.offset(of: B.a)!) // 0


print(MLB.offset(of: B.b)!) // 1


print(MLB.offset(of: B.c)!) // 8


print(MLB.offset(of: B.d)!) // 16
Array<A>(repeating: A(), count: 1_000_000)


// 16MB
Array<B>(repeating: B(), count: 1_000_000)


// 24MB
Оптимизации памяти
49
enum EntityKind {


case Player


case NPC


case Enemy


}


struct Entity {


let health: Int


let kind : EntityKind


}


print(MemoryLayout<Entity>.size) // 9


print(MemoryLayout<Entity>.stride) // 16


print(MemoryLayout<Entity>.alignment) // 8
let entities = Array<Entity>(count: 1_000_000)


// 1 player + 100 NPCs + 999899 enemies


// 1_000_000 * 16B = 16MB
Оптимизации памяти
50
enum EntityKind {


case Player


case NPC


case Enemy


}


struct Entity {


let health: Int


let kind : EntityKind


}


print(MemoryLayout<Entity>.size) // 9


print(MemoryLayout<Entity>.stride) // 16


print(MemoryLayout<Entity>.alignment) // 8
struct Entity {


let health: Int


}


print(MemoryLayout<Entity>.size) // 8


print(MemoryLayout<Entity>.stride) // 8


print(MemoryLayout<Entity>.alignment) // 8
let entities = Array<Entity>(count: 1_000_000)


// 1 player + 100 NPCs + 999899 enemies


// 1_000_000 * 16B = 16MB
let players = Array<Entity>(count: 1)


let NPCs = Array<Entity>(count: 100)


let enemies = Array<Entity>(count: 999899)


// (999899 + 100 + 1) * 8B = 8MB
Измерение оптимизаций
51
https://dl.acm.org/doi/10.1145/2528521.1508275
Ссылки
• CS 6120: Advanced Compilers by Adrian Sampson

https://www.cs.cornell.edu/courses/cs6120/2020fa/

• Advanced Compiler Design and Implementation

https://www.goodreads.com/book/show/
887908.Advanced_Compiler_Design_and_Implementation

• Performance Analysis & Tuning on Modern CPU

https://book.easyperf.net/perf_book

• Data-oriented design: software engineering for limited resources and short
schedules

https://www.dataorienteddesign.com/dodbook/

52

Как работают оптимизации компилятора

  • 1.
  • 2.
    • https://lowlevelbits.org • https://twitter.com/1101_debian •https://github.com/AlexDenisov 2 Обо мне
  • 3.
    • Как компилятороптимизирует программы • Как компилятор видит программы • Оптимизации скорости • Оптимизации памяти • Измерение оптимизаций 3 План
  • 4.
    Что такое оптимизация? intmain() { for (int i = 0; i < 1000000; i++) { print(i); } return 0; } 4
  • 5.
  • 6.
    Какие бывают оптимизации? •скорость программы • размер программы • потребление памяти • потребление энергии • безопасность • обфускация • рефакторинг? • разработка??? 6
  • 7.
    Как компилятор оптимизируетпрограммы bool condition(int i); void case_0(); void case_1(); void case_2(); int main() { for (int i = 0; i < 10000; i++) { if (condition(i)) { goto first_label; } else { goto second_label; } case_0(); first_label: case_1(); goto exit; second_label: case_2(); goto exit; // next iteration? } exit: return 0; } 7
  • 8.
    Как компилятор оптимизируетпрограммы bool condition(int i); void case_0(); void case_1(); void case_2(); int main() { for (int i = 0; i < 10000; i++) { if (condition(i)) { goto first_label; } else { goto second_label; } case_0(); first_label: case_1(); goto exit; second_label: case_2(); goto exit; // next iteration? } exit: return 0; } for (int i = 0; i < 10000; i++) 8
  • 9.
    Как компилятор оптимизируетпрограммы bool condition(int i); void case_0(); void case_1(); void case_2(); int main() { for (int i = 0; i < 10000; i++) { if (condition(i)) { goto first_label; } else { goto second_label; } case_0(); first_label: case_1(); goto exit; second_label: case_2(); goto exit; // next iteration? } exit: return 0; } if (condition(i)) for (int i = 0; i < 10000; i++) 9
  • 10.
    Как компилятор оптимизируетпрограммы bool condition(int i); void case_0(); void case_1(); void case_2(); int main() { for (int i = 0; i < 10000; i++) { if (condition(i)) { goto first_label; } else { goto second_label; } case_0(); first_label: case_1(); goto exit; second_label: case_2(); goto exit; // next iteration? } exit: return 0; } if (condition(i)) for (int i = 0; i < 10000; i++) goto first_label; goto second_label; 10
  • 11.
    Как компилятор оптимизируетпрограммы bool condition(int i); void case_0(); void case_1(); void case_2(); int main() { for (int i = 0; i < 10000; i++) { if (condition(i)) { goto first_label; } else { goto second_label; } case_0(); first_label: case_1(); goto exit; second_label: case_2(); goto exit; // next iteration? } exit: return 0; } if (condition(i)) for (int i = 0; i < 10000; i++) goto first_label; goto second_label; case_0(); 11
  • 12.
    Как компилятор оптимизируетпрограммы bool condition(int i); void case_0(); void case_1(); void case_2(); int main() { for (int i = 0; i < 10000; i++) { if (condition(i)) { goto first_label; } else { goto second_label; } case_0(); first_label: case_1(); goto exit; second_label: case_2(); goto exit; // next iteration? } exit: return 0; } if (condition(i)) for (int i = 0; i < 10000; i++) goto first_label; goto second_label; case_0(); first_label: case_1(); goto exit; second_label: case_2(); goto exit; 12
  • 13.
    Как компилятор оптимизируетпрограммы bool condition(int i); void case_0(); void case_1(); void case_2(); int main() { for (int i = 0; i < 10000; i++) { if (condition(i)) { goto first_label; } else { goto second_label; } case_0(); first_label: case_1(); goto exit; second_label: case_2(); goto exit; // next iteration? } exit: return 0; } if (condition(i)) for (int i = 0; i < 10000; i++) goto first_label; goto second_label; case_0(); first_label: case_1(); goto exit; second_label: case_2(); goto exit; exit: return 0; 13
  • 14.
    Как компилятор оптимизируетпрограммы bool condition(int i); void case_0(); void case_1(); void case_2(); int main() { for (int i = 0; i < 10000; i++) { if (condition(i)) { goto first_label; } else { goto second_label; } case_0(); first_label: case_1(); goto exit; second_label: case_2(); goto exit; // next iteration? } exit: return 0; } if (condition(i)) for (int i = 0; i < 10000; i++) goto first_label; goto second_label; case_0(); first_label: case_1(); goto exit; second_label: case_2(); goto exit; exit: return 0; // next iteration? 14
  • 15.
    Как компилятор оптимизируетпрограммы bool condition(int i); void case_0(); void case_1(); void case_2(); int main() { for (int i = 0; i < 10000; i++) { if (condition(i)) { goto first_label; } else { goto second_label; } case_0(); first_label: case_1(); goto exit; second_label: case_2(); goto exit; // next iteration? } exit: return 0; } if (condition(i)) for (int i = 0; i < 10000; i++) goto first_label; goto second_label; case_0(); first_label: case_1(); goto exit; second_label: case_2(); goto exit; exit: return 0; // next iteration? 15
  • 16.
    Как компилятор оптимизируетпрограммы bool condition(int i); void case_0(); void case_1(); void case_2(); int main() { for (int i = 0; i < 10000; i++) { if (condition(i)) { goto first_label; } else { goto second_label; } case_0(); first_label: case_1(); goto exit; second_label: case_2(); goto exit; // next iteration? } exit: return 0; } if (condition(i)) for (int i = 0; i < 10000; i++) goto first_label; goto second_label; case_0(); first_label: case_1(); goto exit; second_label: case_2(); goto exit; exit: return 0; // next iteration? 16
  • 17.
    Как компилятор оптимизируетпрограммы bool condition(int i); void case_0(); void case_1(); void case_2(); int main() { for (int i = 0; i < 10000; i++) { if (condition(i)) { goto first_label; } else { goto second_label; } case_0(); first_label: case_1(); goto exit; second_label: case_2(); goto exit; // next iteration? } exit: return 0; } if (condition(i)) for (int i = 0; i < 10000; i++) goto first_label; goto second_label; case_0(); first_label: case_1(); goto exit; second_label: case_2(); goto exit; exit: return 0; // next iteration? 17
  • 18.
    Как компилятор оптимизируетпрограммы bool condition(int i); void case_0(); void case_1(); void case_2(); int main() { for (int i = 0; i < 10000; i++) { if (condition(i)) { goto first_label; } else { goto second_label; } case_0(); first_label: case_1(); goto exit; second_label: case_2(); goto exit; // next iteration? } exit: return 0; } if (condition(i)) for (int i = 0; i < 10000; i++) goto first_label; goto second_label; case_0(); first_label: case_1(); goto exit; second_label: case_2(); goto exit; exit: return 0; // next iteration? 18
  • 19.
    Как компилятор оптимизируетпрограммы bool condition(int i); void case_0(); void case_1(); void case_2(); int main() { for (int i = 0; i < 10000; i++) { if (condition(i)) { goto first_label; } else { goto second_label; } case_0(); first_label: case_1(); goto exit; second_label: case_2(); goto exit; // next iteration? } exit: return 0; } if (condition(i)) for (int i = 0; i < 10000; i++) goto first_label; goto second_label; case_0(); first_label: case_1(); goto exit; second_label: case_2(); goto exit; exit: return 0; // next iteration? 19
  • 20.
    Как компилятор оптимизируетпрограммы bool condition(int i); void case_0(); void case_1(); void case_2(); int main() { for (int i = 0; i < 10000; i++) { if (condition(i)) { goto first_label; } else { goto second_label; } case_0(); first_label: case_1(); goto exit; second_label: case_2(); goto exit; // next iteration? } exit: return 0; } if (condition(i)) for (int i = 0; i < 10000; i++) goto first_label; goto second_label; case_0(); first_label: case_1(); goto exit; second_label: case_2(); goto exit; exit: return 0; // next iteration? 20
  • 21.
    Как компилятор оптимизируетпрограммы bool condition(int i); void case_0(); void case_1(); void case_2(); int main() { for (int i = 0; i < 10000; i++) { if (condition(i)) { goto first_label; } else { goto second_label; } case_0(); first_label: case_1(); goto exit; second_label: case_2(); goto exit; // next iteration? } exit: return 0; } if (condition(i)) for (int i = 0; i < 10000; i++) goto first_label; goto second_label; case_0(); first_label: case_1(); goto exit; second_label: case_2(); goto exit; exit: return 0; // next iteration? 21
  • 22.
    Как компилятор оптимизируетпрограммы bool condition(int i); void case_0(); void case_1(); void case_2(); int main() { for (int i = 0; i < 10000; i++) { if (condition(i)) { goto first_label; } else { goto second_label; } case_0(); first_label: case_1(); goto exit; second_label: case_2(); goto exit; // next iteration? } exit: return 0; } if (condition(i)) for (int i = 0; i < 10000; i++) goto first_label; goto second_label; case_0(); first_label: case_1(); goto exit; second_label: case_2(); goto exit; exit: return 0; // next iteration? 22
  • 23.
    Как компилятор оптимизируетпрограммы bool condition(int i); void case_0(); void case_1(); void case_2(); int main() { for (int i = 0; i < 10000; i++) { if (condition(i)) { goto first_label; } else { goto second_label; } case_0(); first_label: case_1(); goto exit; second_label: case_2(); goto exit; // next iteration? } exit: return 0; } if (condition(0)) for (int i = 0; i < 10000; i++) goto first_label; goto second_label; case_0(); first_label: case_1(); goto exit; second_label: case_2(); goto exit; exit: return 0; // next iteration? 23
  • 24.
    Как компилятор оптимизируетпрограммы bool condition(int i); void case_0(); void case_1(); void case_2(); int main() { for (int i = 0; i < 10000; i++) { if (condition(i)) { goto first_label; } else { goto second_label; } case_0(); first_label: case_1(); goto exit; second_label: case_2(); goto exit; // next iteration? } exit: return 0; } if (condition(0)) for (int i = 0; i < 10000; i++) goto first_label; goto second_label; case_0(); first_label: case_1(); goto exit; second_label: case_2(); goto exit; exit: return 0; // next iteration? 24
  • 25.
    Как компилятор оптимизируетпрограммы bool condition(int i); void case_0(); void case_1(); void case_2(); int main() { for (int i = 0; i < 10000; i++) { if (condition(i)) { goto first_label; } else { goto second_label; } case_0(); first_label: case_1(); goto exit; second_label: case_2(); goto exit; // next iteration? } exit: return 0; } if (condition(0)) for (int i = 0; i < 10000; i++) goto first_label; goto second_label; case_0(); first_label: case_1(); goto exit; second_label: case_2(); goto exit; exit: return 0; // next iteration? 25
  • 26.
    Как компилятор оптимизируетпрограммы bool condition(int i); void case_0(); void case_1(); void case_2(); int main() { for (int i = 0; i < 10000; i++) { if (condition(i)) { goto first_label; } else { goto second_label; } case_0(); first_label: case_1(); goto exit; second_label: case_2(); goto exit; // next iteration? } exit: return 0; } bool condition(int i); void case_1(); void case_2(); int main() { if (condition(0)) { case_1(); } else { case_2(); } return 0; } 26
  • 27.
    Control Flow Graph B1 Entry B2B4 B3 B5 B6 Exit B7 27
  • 28.
    Control Flow Graph B1 Entry B2B4 B3 B5 B6 Exit B7 28 Basic Block Predecessors Successors Entry [ ] [ B1 ] B1 [ Entry ] [ B2, B4 ] B2 [ B1 ] [ B5 ] B3 [ ] [ B5 ] B4 [ B1 ] [ B6 ] B5 [ B2 ] [ Exit ] B6 [ B4 ] [ Exit ] B7 [ ] [ Exit ] Exit [ B5, B6, B7 ] [ ]
  • 29.
    Control Flow Graph B1 Entry B2B4 B3 B5 B6 Exit B7 29 Basic Block Predecessors Successors Entry [ ] [ B1 ] B1 [ Entry ] [ B2, B4 ] B2 [ B1 ] [ B5 ] B3 [ ] [ B5 ] B4 [ B1 ] [ B6 ] B5 [ B2 ] [ Exit ] B6 [ B4 ] [ Exit ] B7 [ ] [ Exit ] Exit [ B5, B6, B7 ] [ ] Entry -> B1 -> B2 -> B5 -> Exit Entry -> B1 -> B4 -> B6 -> Exit
  • 30.
    Control Flow Graph 30 BasicBlock Predecessors Successors Entry [ ] [ B1 ] B1 [ Entry ] [ B2, B4 ] B2 [ B1 ] [ B5 ] B3 [ ] [ B5 ] B4 [ B1 ] [ B6 ] B5 [ B2 ] [ Exit ] B6 [ B4 ] [ Exit ] B7 [ ] [ Exit ] Exit [ B5, B6, B7 ] [ ] func pred(_ bb: BasicBlock) -> [BasicBlock] func succ(_ bb: BasicBlock) -> [BasicBlock] func deadCodeElimination(f: Function) { // 1 var reachable = [BasicBlock]() var queue = [BasicBlock]() queue.append(f.entry) // 2 while !queue.isEmpty { let head = queue.removeFirst() reachable.append(head) queue.append(contentsOf: succ(head)) } // 3 for bb in f.basicBlocks { if !reachable.contains(bb) { f.removeBasicBlock(bb: bb) } } }
  • 31.
    Control Flow Graph 31 31 while(condition()) { // body } if (condition()) { // body } // body // body if (condition()) { // then body } else { // else body } condition() condition() condition() // then // else https://swift.godbolt.org/z/rG4KKEheG
  • 32.
  • 33.
    Constant-folding Оптимизации скорости let secondsPerDay= 60 * 60 * 24 print(secondPerDay) print(86400) 33
  • 34.
    Algebraic Simpli fi cation Оптимизации скорости funcsomething(x: Int) { print(x + 0) print(x * 0) print(x - 0) print(x * 1) } func something(x: Int) { print(x) print(0) print(x) print(x) } 34
  • 35.
    Common-subexpression Elimination (CSE) Оптимизациискорости func something(a: Int, b: Int) { let x = a + b let y = a + b } func something(a: Int, b: Int) { let t = a + b let x = t let y = t } 35
  • 36.
    Copy Propagation Оптимизации скорости funcsomething(a: Int, b: Int) { let x = a + b let a1 = a let y = a1 + b let b1 = b let z = a1 + b1 } func something(a: Int, b: Int) { let x = a + b let a1 = a let y = a + b let b1 = b let z = a + b } func something(a: Int, b: Int) { let t = a + b let x = t let y = t let z = t } 36
  • 37.
    Loop-invariant Code Motion(LICM) Оптимизации скорости func compute() -> Int { // heavy stuff } for i in 0...10 { let x = compute() print(x + i) } func compute() -> Int { // heavy stuff } let x = compute() for i in 0...10 { print(x + i) } 37
  • 38.
    Inlining Оптимизации скорости func getSomething()-> Int { return 42 } print(getSomething()) func getSomething() -> Int { return 42 } print(42) 38
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
    Оптимизации и безопасность 43 char*getPWHash() { long i; char pwd[64]; char *sha1 = (char*)malloc(41); // read password fgets(pwd, sizeof(pwd), stdin); // <<< // calculate sha1 of password ... // <<< // overwrite pwd in memory // Alternative (A) : use memset memset(pwd, 0, sizeof(pwd)); // (A) // Alternative (B) : reset pwd in a loop for (i=0; i<sizeof(pwd); ++i) pwd[i]=0; // (B) // return only hash of pwd return sha1; }
  • 44.
  • 45.
  • 46.
    Оптимизации памяти 46 struct A{ let a: Int8 let b: Int16 let c: Int8 let d: Int64 } typealias MLA = MemoryLayout<A> print(MLA.size) // 16 print(MLA.stride) // 16 print(MLA.alignment) // 8 print(MLA.offset(of: A.a)!) // 0 print(MLA.offset(of: A.b)!) // 2 print(MLA.offset(of: A.c)!) // 4 print(MLA.offset(of: A.d)!) // 8 struct B { let a: Int8 let b: Int8 let c: Int64 let d: Int16 } typealias MLB = MemoryLayout<B> print(MLB.size) // 18 print(MLB.stride) // 24 print(MLB.alignment) // 8 print(MLB.offset(of: B.a)!) // 0 print(MLB.offset(of: B.b)!) // 1 print(MLB.offset(of: B.c)!) // 8 print(MLB.offset(of: B.d)!) // 16
  • 47.
    Оптимизации памяти 47 struct A{ let a: Int8 let b: Int16 let c: Int8 let d: Int64 } typealias MLA = MemoryLayout<A> print(MLA.size) // 16 print(MLA.stride) // 16 print(MLA.alignment) // 8 print(MLA.offset(of: A.a)!) // 0 print(MLA.offset(of: A.b)!) // 2 print(MLA.offset(of: A.c)!) // 4 print(MLA.offset(of: A.d)!) // 8 struct B { let a: Int8 let b: Int8 let c: Int64 let d: Int16 } typealias MLB = MemoryLayout<B> print(MLB.size) // 18 print(MLB.stride) // 24 print(MLB.alignment) // 8 print(MLB.offset(of: B.a)!) // 0 print(MLB.offset(of: B.b)!) // 1 print(MLB.offset(of: B.c)!) // 8 print(MLB.offset(of: B.d)!) // 16
  • 48.
    Оптимизации памяти 48 struct A{ let a: Int8 let b: Int16 let c: Int8 let d: Int64 } typealias MLA = MemoryLayout<A> print(MLA.size) // 16 print(MLA.stride) // 16 print(MLA.alignment) // 8 print(MLA.offset(of: A.a)!) // 0 print(MLA.offset(of: A.b)!) // 2 print(MLA.offset(of: A.c)!) // 4 print(MLA.offset(of: A.d)!) // 8 struct B { let a: Int8 let b: Int8 let c: Int64 let d: Int16 } typealias MLB = MemoryLayout<B> print(MLB.size) // 18 print(MLB.stride) // 24 print(MLB.alignment) // 8 print(MLB.offset(of: B.a)!) // 0 print(MLB.offset(of: B.b)!) // 1 print(MLB.offset(of: B.c)!) // 8 print(MLB.offset(of: B.d)!) // 16 Array<A>(repeating: A(), count: 1_000_000) // 16MB Array<B>(repeating: B(), count: 1_000_000) // 24MB
  • 49.
    Оптимизации памяти 49 enum EntityKind{ case Player case NPC case Enemy } struct Entity { let health: Int let kind : EntityKind } print(MemoryLayout<Entity>.size) // 9 print(MemoryLayout<Entity>.stride) // 16 print(MemoryLayout<Entity>.alignment) // 8 let entities = Array<Entity>(count: 1_000_000) // 1 player + 100 NPCs + 999899 enemies // 1_000_000 * 16B = 16MB
  • 50.
    Оптимизации памяти 50 enum EntityKind{ case Player case NPC case Enemy } struct Entity { let health: Int let kind : EntityKind } print(MemoryLayout<Entity>.size) // 9 print(MemoryLayout<Entity>.stride) // 16 print(MemoryLayout<Entity>.alignment) // 8 struct Entity { let health: Int } print(MemoryLayout<Entity>.size) // 8 print(MemoryLayout<Entity>.stride) // 8 print(MemoryLayout<Entity>.alignment) // 8 let entities = Array<Entity>(count: 1_000_000) // 1 player + 100 NPCs + 999899 enemies // 1_000_000 * 16B = 16MB let players = Array<Entity>(count: 1) let NPCs = Array<Entity>(count: 100) let enemies = Array<Entity>(count: 999899) // (999899 + 100 + 1) * 8B = 8MB
  • 51.
  • 52.
    Ссылки • CS 6120:Advanced Compilers by Adrian Sampson
 https://www.cs.cornell.edu/courses/cs6120/2020fa/ • Advanced Compiler Design and Implementation
 https://www.goodreads.com/book/show/ 887908.Advanced_Compiler_Design_and_Implementation • Performance Analysis & Tuning on Modern CPU
 https://book.easyperf.net/perf_book • Data-oriented design: software engineering for limited resources and short schedules
 https://www.dataorienteddesign.com/dodbook/
 52