Thiết kế trình biên dịch: Tối ưu hóa mã

Trong hướng dẫn trước, bạn sẽ tìm hiểu tạo mã và trình tạo mã trong thiết kế trình biên dịch. Nếu bỏ lỡ thì bạn có thể xem ở đây:

Thiết kế trình biên dịch: Tạo mã
Trong hướng dẫn này, bạn sẽ tìm hiểu tạo mã và trình tạo mã trong thiết kế trình biên dịch.

Tối ưu hóa mã là một kỹ thuật chuyển đổi chương trình, cố gắng cải thiện mã bằng cách làm cho nó tiêu thụ ít tài nguyên hơn (tức là CPU, Bộ nhớ) và cung cấp tốc độ cao.

Trong tối ưu hóa, các cấu trúc lập trình chung cấp cao được thay thế bằng các mã lập trình cấp thấp rất hiệu quả. Quy trình tối ưu hóa mã phải tuân theo ba quy tắc được đưa ra dưới đây:

  • Mã đầu ra không được thay đổi ý nghĩa của chương trình theo bất kỳ cách nào.
  • Việc tối ưu hóa sẽ làm tăng tốc độ của chương trình và nếu có thể, chương trình sẽ yêu cầu ít tài nguyên hơn.
  • Bản thân việc tối ưu hóa phải nhanh chóng và không được làm chậm trễ quá trình biên dịch tổng thể.

Các nỗ lực cho một mã được tối ưu hóa có thể được thực hiện ở nhiều cấp độ khác nhau của quá trình biên dịch.

  • Khi bắt đầu, người dùng có thể thay đổi / sắp xếp lại mã hoặc sử dụng các thuật toán tốt hơn để viết mã.
  • Sau khi tạo mã trung gian, trình biên dịch có thể sửa đổi mã trung gian bằng cách tính toán địa chỉ và cải thiện các vòng lặp.
  • Trong khi tạo mã máy đích, trình biên dịch có thể sử dụng phân cấp bộ nhớ và thanh ghi CPU.

Tối ưu hóa có thể được phân loại thành hai loại: độc lập với máy và phụ thuộc vào máy.

Tối ưu hóa độc lập với máy

Trong tối ưu hóa này, trình biên dịch lấy mã trung gian và biến đổi một phần của mã không liên quan đến bất kỳ thanh ghi CPU nào và / hoặc vị trí bộ nhớ tuyệt đối. Ví dụ:

do
{
    item = 10;
    value = value + item; 
} while (value < 100);

Mã này liên quan đến việc gán lặp lại định danh item, nếu chúng ta viết lại theo cách này:

item = 10;
do
{
    value = value + item; 
} while (value < 100);

không chỉ tiết kiệm các chu kỳ CPU mà có thể được sử dụng trên bất kỳ bộ xử lý nào.

Tối ưu hóa phụ thuộc vào máy

Tối ưu hóa phụ thuộc vào máy được thực hiện sau khi mã đích đã được tạo và khi mã được chuyển đổi theo kiến ​​trúc máy đích.

Nó liên quan đến các thanh ghi CPU và có thể có tham chiếu bộ nhớ tuyệt đối hơn là tham chiếu tương đối.

Các trình tối ưu hóa phụ thuộc vào máy nỗ lực để tận dụng tối đa hệ thống phân cấp bộ nhớ.

Khối cơ bản

Mã nguồn thường có một số lệnh, các lệnh này luôn được thực thi theo trình tự và được coi là các khối cơ bản của mã.

Các khối cơ bản này không có bất kỳ lệnh nhảy nào trong số chúng, tức là, khi lệnh đầu tiên được thực hiện, tất cả các lệnh trong cùng một khối cơ bản sẽ được thực hiện theo trình tự xuất hiện của chúng mà không làm mất quyền kiểm soát luồng của chương trình.

Một chương trình có thể có nhiều cấu trúc khác nhau dưới dạng các khối cơ bản, như IF-THEN-ELSE, câu lệnh điều kiện SWITCH-CASE và các vòng lặp như WHILE, DO-WHILE, FOR và FOREACH, v.v.

Nhận biết khối cơ bản

Chúng tA có thể sử dụng thuật toán sau để tìm các khối cơ bản trong một chương trình:

Câu lệnh tiêu đề tìm kiếm của tất cả các khối cơ bản từ nơi bắt đầu một khối cơ bản:

  • Câu lệnh đầu tiên của một chương trình.
  • Các câu lệnh là đích của bất kỳ nhánh nào (có điều kiện / không điều kiện).
  • Các câu lệnh theo sau bất kỳ câu lệnh nhánh nào.

Các câu lệnh tiêu đề và các câu lệnh theo sau chúng tạo thành một khối cơ bản.

Một khối cơ bản không bao gồm bất kỳ câu lệnh tiêu đề nào của bất kỳ khối cơ bản nào khác.

Các khối cơ bản là những khái niệm quan trọng theo cả quan điểm tạo mã và tối ưu hóa.

Khối cơ bản

Các khối cơ bản đóng một vai trò quan trọng trong việc xác định các biến, chúng đang được sử dụng nhiều lần trong một khối cơ bản duy nhất.

Nếu bất kỳ biến nào đang được sử dụng nhiều hơn một lần, bộ nhớ thanh ghi được cấp cho biến đó không cần được làm trống trừ khi khối kết thúc quá trình thực thi.

Biểu đồ luồng điều khiển

Các khối cơ bản trong một chương trình có thể được biểu diễn bằng biểu đồ luồng điều khiển.

Biểu đồ luồng điều khiển mô tả cách điều khiển chương trình đang được chuyển giữa các khối.

Nó là một công cụ hữu ích giúp tối ưu hóa bằng cách giúp định vị bất kỳ vòng lặp không mong muốn nào trong chương trình.

Biểu đồ luồng điều khiển

Tối ưu hóa vòng lặp

Hầu hết các chương trình chạy như một vòng lặp trong hệ thống. Nó trở nên cần thiết để tối ưu hóa các vòng lặp để tiết kiệm chu kỳ CPU và bộ nhớ. Các vòng lặp có thể được tối ưu hóa bằng các kỹ thuật sau:

  • Mã bất biến: Một đoạn mã nằm trong vòng lặp và tính giá trị giống nhau tại mỗi lần lặp được gọi là mã bất biến vòng lặp. Mã này có thể được di chuyển ra khỏi vòng lặp bằng cách lưu nó để được tính chỉ một lần, thay vì mỗi lần lặp lại.
  • Phân tích thay đổi: Một biến được gọi là biến thay đổi nếu giá trị của nó bị thay đổi trong vòng lặp bởi một giá trị bất biến của vòng lặp.
  • Giảm chi phí: Có những biểu thức tiêu tốn nhiều chu kỳ, thời gian và bộ nhớ của CPU hơn. Các biểu thức này nên được thay thế bằng các biểu thức rẻ hơn mà không ảnh hưởng đến kết quả đầu ra của biểu thức. Ví dụ, phép nhân (x * 2) tốn kém về chu kỳ CPU hơn (x << 1) và cho kết quả tương tự.

Loại bỏ mã chết

Mã chết là một hoặc nhiều câu lệnh mã:

  • Không bao giờ được thực thi hoặc không thể truy cập,
  • Hoặc nếu được thực thi, đầu ra của chúng sẽ không bao giờ được sử dụng.

Do đó, mã chết không đóng vai trò gì trong bất kỳ hoạt động nào của chương trình và do đó nó có thể bị loại bỏ một cách đơn giản.

Mã chết một phần

Có một số câu lệnh mà các giá trị được tính toán chỉ được sử dụng trong một số trường hợp nhất định, tức là, đôi khi các giá trị được sử dụng và đôi khi chúng không. Những mã như vậy được gọi là mã chết một phần.

Mã chết một phần

Biểu đồ luồng điều khiển ở trên mô tả một đoạn chương trình trong đó biến 'a' được sử dụng để gán đầu ra của biểu thức 'x * y'. Giả sử rằng giá trị được gán cho 'a' không bao giờ được sử dụng trong vòng lặp.

Ngay sau khi điều khiển rời khỏi vòng lặp, 'a' được gán giá trị của biến 'z', giá trị này sẽ được sử dụng sau này trong chương trình.

Chúng tôi kết luận ở đây rằng mã gán của 'a' không bao giờ được sử dụng ở bất kỳ đâu, do đó nó đủ điều kiện để bị loại bỏ.

Mã chết một phần

Tương tự như vậy, hình trên mô tả rằng câu lệnh điều kiện luôn sai, ngụ ý rằng mã, được viết trong trường hợp đúng, sẽ không bao giờ được thực thi, do đó nó có thể bị xóa.

Dư thừa một phần

Các biểu thức dư thừa được tính toán nhiều lần trong một đường dẫn song song mà không có bất kỳ thay đổi nào trong toán hạng.

Trong khi các biểu thức dư thừa một phần được tính toán nhiều lần trong một đường dẫn mà không có bất kỳ thay đổi nào trong các toán hạng. Ví dụ,

Biểu thức dư thừa
Biểu thức dư thừa
Biểu thức dư thừa một phần
Biểu thức dư thừa một phần

Mã bất biến vòng lặp là một phần dư thừa và có thể được loại bỏ bằng cách sử dụng kỹ thuật di chuyển mã.

Một ví dụ khác về mã dư thừa một phần có thể là:

if (condition)
{
   a = y OP z;
}
else
{
   //...
}
c = y OP z;

Chúng ta giả sử rằng giá trị của các toán hạng (yz) không bị thay đổi khi gán biến a cho biến c.

Ở đây, nếu câu lệnh điều kiện là đúng, thì y OP z được tính hai lần, nếu không thì một lần. Di chuyển mã có thể được sử dụng để loại bỏ sự dư thừa này, như được hiển thị bên dưới:

if (condition)
{
   //...
   tmp = y OP z;
   a = tmp;
   //...
}
else
{
   //...
   tmp = y OP z;
}
c = tmp;

Ở đây, cho dù điều kiện là đúng hay sai; y OP z chỉ nên được tính một lần.

Trong hướng dẫn tiếp theo, bạn sẽ tìm hiểu bảng ký hiệu là gì? Cách trình biên dịch sử dụng bảng ký hiệu trong thiết kế trình biên dịch.

Thiết kế trình biên dịch: Bảng ký hiệu
Trong hướng dẫn này, bạn sẽ tìm hiểu bảng ký hiệu là gì? Cách trình biên dịch sử dụng bảng ký hiệu trong thiết kế trình biên dịch.
Trình Biên Dịch
Bài Viết Liên Quan:
Thiết kế trình biên dịch: Môi trường thực thi
Trung Nguyen 07/04/2021
Thiết kế trình biên dịch: Môi trường thực thi

Trong hướng dẫn này, bạn sẽ tìm hiểu chi tiết về môi trường thực thi, nơi chương trình sau khi biên dịch sẽ được thực thi.

Thiết kế trình biên dịch: Bảng ký hiệu
Trung Nguyen 07/04/2021
Thiết kế trình biên dịch: Bảng ký hiệu

Trong hướng dẫn này, bạn sẽ tìm hiểu bảng ký hiệu là gì? Cách trình biên dịch sử dụng bảng ký hiệu trong thiết kế trình biên dịch.

Thiết kế trình biên dịch: Tạo mã
Trung Nguyen 07/04/2021
Thiết kế trình biên dịch: Tạo mã

Trong hướng dẫn này, bạn sẽ tìm hiểu tạo mã và trình tạo mã trong thiết kế trình biên dịch.

Thiết kế trình biên dịch: Tạo mã trung gian
Trung Nguyen 06/04/2021
Thiết kế trình biên dịch: Tạo mã trung gian

Trong hướng dẫn này, bạn sẽ tìm hiểu vì sao cần phải tạo mã trung gian? Cách tạo mã trung gian trong thiết kế trình biên dịch.