컴파일러는 코드를 가져 와서 매우 간단한 명령어로 분할 한 다음 최적이라고 생각하는 방식으로 다시 결합하고 정렬합니다.
코드
int i = 1;
int x = ++i + ++i;
다음 지침으로 구성됩니다.
1. store 1 in i
2. read i as tmp1
3. add 1 to tmp1
4. store tmp1 in i
5. read i as tmp2
6. read i as tmp3
7. add 1 to tmp3
8. store tmp3 in i
9. read i as tmp4
10. add tmp2 and tmp4, as tmp5
11. store tmp5 in x
그러나 이것이 내가 작성한 방식대로 번호가 매겨진 목록 임에도 불구하고 여기 에는 몇 가지 순서 종속성이 있습니다. 1-> 2-> 3-> 4-> 5-> 10-> 11 및 1-> 6-> 7- > 8-> 9-> 10-> 11은 상대적인 순서를 유지해야합니다. 그 외에 컴파일러는 자유롭게 재정렬 할 수 있으며 중복성을 제거 할 수 있습니다.
예를 들어 다음과 같이 목록을 주문할 수 있습니다.
1. store 1 in i
2. read i as tmp1
6. read i as tmp3
3. add 1 to tmp1
7. add 1 to tmp3
4. store tmp1 in i
8. store tmp3 in i
5. read i as tmp2
9. read i as tmp4
10. add tmp2 and tmp4, as tmp5
11. store tmp5 in x
컴파일러가 이것을 할 수있는 이유는 무엇입니까? 증분의 부작용에 대한 순서가 없기 때문입니다. 그러나 이제 컴파일러는 단순화 할 수 있습니다. 예를 들어 4에 데드 스토어가 있습니다. 값은 즉시 덮어 쓰여집니다. 또한 tmp2와 tmp4는 실제로 동일합니다.
1. store 1 in i
2. read i as tmp1
6. read i as tmp3
3. add 1 to tmp1
7. add 1 to tmp3
8. store tmp3 in i
5. read i as tmp2
10. add tmp2 and tmp2, as tmp5
11. store tmp5 in x
이제 tmp1로 할 수있는 모든 것은 죽은 코드입니다. 절대 사용되지 않습니다. 그리고 i를 다시 읽는 것도 제거 할 수 있습니다.
1. store 1 in i
6. read i as tmp3
7. add 1 to tmp3
8. store tmp3 in i
10. add tmp3 and tmp3, as tmp5
11. store tmp5 in x
이 코드는 훨씬 더 짧습니다. 옵티마이 저는 행복합니다. 내가 한 번만 증가했기 때문에 프로그래머는 그렇지 않습니다. 죄송합니다.
컴파일러가 대신 할 수있는 다른 작업을 살펴 보겠습니다. 원래 버전으로 돌아 갑시다.
1. store 1 in i
2. read i as tmp1
3. add 1 to tmp1
4. store tmp1 in i
5. read i as tmp2
6. read i as tmp3
7. add 1 to tmp3
8. store tmp3 in i
9. read i as tmp4
10. add tmp2 and tmp4, as tmp5
11. store tmp5 in x
컴파일러는 다음과 같이 재정렬 할 수 있습니다.
1. store 1 in i
2. read i as tmp1
3. add 1 to tmp1
4. store tmp1 in i
6. read i as tmp3
7. add 1 to tmp3
8. store tmp3 in i
5. read i as tmp2
9. read i as tmp4
10. add tmp2 and tmp4, as tmp5
11. store tmp5 in x
그리고 내가 두 번 읽 혔다는 것을 다시 확인하고 그중 하나를 제거하십시오.
1. store 1 in i
2. read i as tmp1
3. add 1 to tmp1
4. store tmp1 in i
6. read i as tmp3
7. add 1 to tmp3
8. store tmp3 in i
5. read i as tmp2
10. add tmp2 and tmp2, as tmp5
11. store tmp5 in x
좋지만 더 나아갈 수 있습니다. tmp1을 재사용 할 수 있습니다.
1. store 1 in i
2. read i as tmp1
3. add 1 to tmp1
4. store tmp1 in i
6. read i as tmp1
7. add 1 to tmp1
8. store tmp1 in i
5. read i as tmp2
10. add tmp2 and tmp2, as tmp5
11. store tmp5 in x
그런 다음 6에서 i를 다시 읽지 않아도됩니다.
1. store 1 in i
2. read i as tmp1
3. add 1 to tmp1
4. store tmp1 in i
7. add 1 to tmp1
8. store tmp1 in i
5. read i as tmp2
10. add tmp2 and tmp2, as tmp5
11. store tmp5 in x
이제 4는 죽은 상점입니다.
1. store 1 in i
2. read i as tmp1
3. add 1 to tmp1
7. add 1 to tmp1
8. store tmp1 in i
5. read i as tmp2
10. add tmp2 and tmp2, as tmp5
11. store tmp5 in x
이제 3과 7을 하나의 명령어로 병합 할 수 있습니다.
1. store 1 in i
2. read i as tmp1
3+7. add 2 to tmp1
8. store tmp1 in i
5. read i as tmp2
10. add tmp2 and tmp2, as tmp5
11. store tmp5 in x
마지막 임시 제거 :
1. store 1 in i
2. read i as tmp1
3+7. add 2 to tmp1
8. store tmp1 in i
10. add tmp1 and tmp1, as tmp5
11. store tmp5 in x
이제 Visual C ++가 제공하는 결과를 얻을 수 있습니다.
두 최적화 경로 모두에서 아무 작업도 수행하지 않은 경우 지침이 제거되지 않는 한 중요한 순서 종속성이 유지되었습니다.