Bạn viết một hàm tính toán phức tạp, gán kết quả vào biến temp, rồi quên dùng nó. Trình biên dịch sẽ phát hiện biến đó không bao giờ được đọc lại, và lặng lẽ xóa toàn bộ code liên quan. Đó chính là dead code elimination (DCE), một trong những kỹ thuật tối ưu hóa cổ điển nhất trong compiler, giúp chương trình chạy nhanh hơn và nhỏ hơn mà không thay đổi hành vi.

Phân biệt hai loại code "chết"

Có hai dạng code thừa mà compiler cần xử lý. Dạng thứ nhất là unreachable code, tức code nằm sau lệnh return hoặc trong nhánh if (false), không bao giờ được thực thi. Dạng thứ hai tinh vi hơn: code có chạy nhưng kết quả không ai dùng. Ví dụ bạn gọi một hàm tính toán nặng, gán vào biến x, nhưng x không bao giờ xuất hiện trong bất kỳ biểu thức nào phía sau. Cả hai dạng đều là "dead" và đều có thể loại bỏ an toàn.

SSA form là nền tảng

DCE hoạt động hiệu quả nhất trên biểu diễn trung gian SSA (Static Single Assignment). Trong SSA, mỗi biến chỉ được gán đúng một lần, và compiler xây dựng chuỗi use-def (sử dụng-định nghĩa) rõ ràng. Khi một định nghĩa không có use nào trỏ tới, nó được đánh dấu là dead. Hãy tưởng tượng một đồ thị: Mỗi node là một phép gán, mỗi cạnh nối từ nơi giá trị được tạo ra đến nơi nó được đọc. Node nào không có cạnh đi ra sẽ bị xóa.

Thuật toán Mark-Sweep

Cách triển khai phổ biến nhất là thuật toán mark-sweep DCE, hoạt động theo chiều ngược lại so với garbage collection. Bước 1: Đánh dấu tất cả lệnh có "side effect" rõ ràng, bao gồm lệnh ghi ra bộ nhớ, gọi I/O, return, hoặc ghi vào biến toàn cục. Bước 2: Từ các lệnh đã đánh dấu, duyệt ngược theo chuỗi use-def để đánh dấu mọi lệnh cung cấp giá trị cho chúng. Bước 3: Xóa mọi lệnh chưa được đánh dấu. Kết quả là chỉ những lệnh thực sự ảnh hưởng đến output mới được giữ lại.

Side effect là ranh giới khó

Thách thức lớn nhất của DCE là xác định chính xác side effect. Một lệnh gọi hàm calculateTax(order) có thể trông vô hại, nhưng bên trong nó ghi log, cập nhật cache, hoặc gửi metric. Nếu compiler không chắc hàm đó có side effect hay không, nó buộc phải giữ lại. Đây là lý do các ngôn ngữ hàm như Haskell, nơi side effect được kiểm soát chặt qua hệ thống kiểu, cho phép compiler tối ưu hóa mạnh tay hơn nhiều so với C hoặc Java.

DCE trong thực tế

Ở cấp độ ứng dụng web, tree shaking trong bundler như Webpack hay Rollup thực chất là DCE ở cấp module. Khi bạn import { Button } from 'ui-lib', bundler phân tích rằng bạn không dùng Modal hay Tooltip từ cùng thư viện, và loại bỏ chúng khỏi bundle. Kỹ thuật này giảm kích thước JavaScript đáng kể, đặc biệt khi dùng thư viện lớn.

Tin tức liên quan gần đây, Cloudflare vừa công bố cắt giảm 1.100 nhân sự khi AI giúp tự động hóa nhiều quy trình. Tương tự cách DCE loại bỏ code không cần thiết, các công ty công nghệ đang dùng AI để nhận diện và loại bỏ công việc dư thừa, tuy hệ quả với con người phức tạp hơn nhiều so với việc xóa vài dòng code.