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:
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:
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.
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.
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 đượ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ớ.
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.
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á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.
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.
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.
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ã chết là một hoặc nhiều câu lệnh mã:
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.
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.
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ỏ.
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.
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ụ,
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 (y và z) 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.
Bạn có thể vui lòng tắt trình chặn quảng cáo ❤️ để hỗ trợ chúng tôi duy trì hoạt động của trang web.
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.
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.
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.
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.