• Tidak ada hasil yang ditemukan

Chương 3 Công cụ định vị lỗi HiFa cho các ứng dụng C/C++

3.3 Quá trình điều chỉnh mã nguồn

3.3.1 Tổng quan về LLVM

LLVM [32] là một tập hợp các công nghệ toolchain và trình biên dịch mô đun có thể tái sử dụng. Xuất phát từ khái niệm Low Level Virtual Machine - Máy ảo cấp thấp, LLVM thường được xem là một khung để tạo nên các trình biên dịch được thiết kế để hỗ trợ phân tích và chuyển đổi chương trình suốt đời, suốt đời cho các chương trình tùy ý, bằng cách cung cấp thông tin cấp cao để chuyển đổi trình biên dịch tại thời điểm compile-time, link-time, run-time và idle time giữa các lần chạy. Nó cung cấp những công cụ mạnh mẽ để xây dựng phần front-end (parser, lexer) cũng như phần backend (phần chuyển phần code trung gian LLVM sang mã máy), cho các ngôn ngữ lập trình mới. LLVM đã được sử dụng để xây dựng nên nhiều bộ chuyển đổi (compiler) của nhiều ngôn ngữ lập trình cấp cao phổ biến hiện nay, ví dụ như C, C++, Python, Java, Ruby, cũng như Objective-C và Swift.

Hình 3-4 [33] thể hiện hệ sinh thái trình biên dịch LLVM gồm 3 phần:

- Front-end: phần này nhận đầu vào là các ngôn ngữ và chịu trách nhiệm thực hiện 3 bước gồm lexical analysis (phân tích từ tố) - đọc từng ký tự thành các token, syntax analysis (phân tích cú pháp) - parser chuyển các token ở bước trước thành AST (abstract syntax tree) và semantic analysis (phân tích ngữ nghĩa) - kiểm tra các thông tin khác ví dụ như type checking sau đó tạo mã trung gian IR.

- Middle-end: được biết đến với cái tên "LLVM Optimizer", nó sử dụng một ngôn ngữ lập trình cấp thấp gọi là intermediate representation (IR) làm mã trung gian, thứ có thể tồn tại một số dạng dạng khác nhau tùy vào lập trình viên. IR được sử dụng nhằm mục đích chuyển đổi giữa kết quả của phần front-end sang back-end để có thể tạo mã đích hay chính xác hơn mã trung gian IR chính là output của front-end và input của backend.

- Back-end: phần này sẽ chịu trách nhiệm tạo ra mã máy từ mã trung gian cho từng kiến trúc CPU cụ thể.

Hình 3-4: LLVM Framework

Nhờ thiết kế độc lập của 3 thành phần dạng module, LLVM giúp các nhà phát triển rất dễ hỗ trợ thêm ngôn ngữ front-end mới, cũng như hỗ trợ cho các kiến trúc CPU mới ở phía back-end, ngay cả những kiến trúc không tồn tại ở thời điểm ứng dụng ra đời. Cùng với nhiều công cụ mạnh mẽ khác, dự án LLVM mang đến sức mạnh, tốc độ, an toàn cùng với tiên lợi cho hầu hết các ngôn ngữ hiện đại ngày nay.

Như giới thiệu ở trên LLVM IR hay mã đại diện trung gian của LLVM là một loại mã đại diện trung gian cấp thấp được sử dụng bởi khung biên dịch LLVM. Ta có thể coi LLVM IR là một ngôn ngữ hợp ngữ độc lập với nền tảng với vô số thanh ghi cục bộ chức năng. Khi phát triển các trình biên dịch, có những lợi ích to lớn khi biên dịch ngôn ngữ nguồn sang một đại diện trung gian (IR) thay vì biên dịch trực tiếp đến một kiến trúc đích (ví dụ: x86) có thể kể đến như như có thể thực hiện các phương pháp tối ưu trực tiếp ở mức IR chẳng hạn như loại bỏ mã chết, lan truyền liên tục, ... từ đó cải thiện đáng kể hiệu năng cũng như tiết kiệm tài nguyên cho khi thực thi các đoạn mã trên.

Hình 3-5: Kiến trúc trình biên dịch LLVM

LLVM cung cấp các phương thức tương tác với LLVM IR thông qua LLVM Pass Framework. Cách thức hoạt động của nó là nhà phát triển viết một phiên bản của lớp llvm::Pass với các phương thức được gọi trong mỗi loại pass được khởi tạo và nhà phát triển cho nó biết phải làm gì với mã. Một số LLVM pass:

- Module Pass: là tổng quát nhất của tất cả các lớp cha mà nhà phát triển có thể sử dụng. Xuất phát từ ModulePass ta có thể sử dụng toàn bộ chương trình như một đơn vị, tham chiếu đến các hàm hoặc thêm và bớt các hàm.

Một đường chuyền mô-đun có thể sử dụng các đường chuyền cấp chức năng (ví dụ: Dominators) bằng cách sử dụng giao diện getAnalysis

<DominatorTree> (llvm ::Function *) để cung cấp chức năng truy xuất kết quả phân tích, nếu đường truyền chức năng không yêu cầu bất kỳ mô-đun nào hoặc các đường truyền bất biến.

- Function Pass: ngược lại với các lớp con Module Pass, các lớp con Function Pass có một hành vi cục bộ. Tất cả các Function Pass thực thi trên mỗi hàm trong chương trình độc lập với tất cả các hàm khác trong chương trình. Các lớp Function không yêu cầu chúng phải được thực thi theo một thứ tự cụ thể và các Function Pass không sửa đổi các hàm bên ngoài.

Hình 3-6: Các LLVM pass

Dokumen terkait