2010-08-18 34 views
18

Tôi không hiểu làm thế nào LLVM JIT liên quan đến việc biên dịch JIT bình thường và tài liệu không tốt.LLVM jit và bản địa

Ví dụ giả sử tôi sử dụng clang kết thúc trước:

  1. Trường hợp 1: Tôi biên dịch tập tin C đến mẹ đẻ với kêu vang/llvm. Luồng này tôi hiểu giống như luồng gcc - tôi nhận được tệp thực thi x86 của mình và chạy.
  2. Trường hợp 2: Tôi biên dịch thành một số loại LLVM IR chạy trên LLVM JIT. Trong trường hợp này, tệp thực thi có chứa thời gian chạy LLVM để thực thi IR trên JIT, hoặc nó hoạt động như thế nào?

Sự khác biệt giữa hai loại này và chúng có đúng không? Luồng LLVM có hỗ trợ cho cả JIT và JIT không? Khi nào tôi muốn sử dụng JIT - nó có ý nghĩa gì cả cho một ngôn ngữ như C?

Trả lời

30

Bạn phải hiểu rằng LLVM là thư viện giúp bạn xây dựng trình biên dịch. Clang chỉ là một lối vào cho thư viện này.

Clang dịch mã C/C++ thành LLVM IR và chuyển nó sang LLVM, biên dịch mã đó thành mã gốc.

LLVM cũng có thể tạo mã gốc trực tiếp trong bộ nhớ, sau đó có thể được gọi là hàm bình thường. Vì vậy, trường hợp 1. và 2. chia sẻ tối ưu hóa và tạo mã của LLVM.

Vậy làm cách nào để sử dụng LLVM làm trình biên dịch JIT? Bạn xây dựng một ứng dụng tạo ra một số LLVM IR (trong bộ nhớ), sau đó sử dụng thư viện LLVM để tạo mã gốc (vẫn còn trong bộ nhớ). LLVM đưa bạn trở lại một con trỏ mà bạn có thể gọi sau đó. Không hề có liên quan gì cả.

Tuy nhiên, bạn có thể sử dụng tiếng kêu để dịch một số mã C thành LLVM IR và tải mã này vào ngữ cảnh JIT của bạn để sử dụng các hàm.

Real World ví dụ:

Ngoài ra còn có các Kaleidoscope hướng dẫn trong đó cho thấy làm thế nào để thực hiện một ngôn ngữ đơn giản với trình biên dịch JIT.

+0

Vì vậy, để sử dụng LLVM làm JIT bạn phải liên kết nó vào ứng dụng của bạn, phải không? Có ứng dụng nào làm điều đó không? – zaharpopov

2

Hầu hết các trình biên dịch đều có giao diện người dùng, một số mã/cấu trúc trung bình của một số loại và phần phụ trợ. Khi bạn dùng chương trình C của bạn và sử dụng clang và biên dịch sao cho bạn kết thúc với một chương trình không phải JIT x86 mà bạn có thể chạy, bạn vẫn đi từ giao diện đầu vào giữa đến phần cuối. Cùng đi với gcc, gcc đi từ giao diện người dùng đến phần giữa và phần phụ trợ. Điều Gccs ở giữa không mở rộng và có thể sử dụng giống như của LLVM.

Bây giờ một điều thú vị/thú vị về llvm, bạn không thể làm với những người khác, hoặc ít nhất là gcc, là bạn có thể lấy tất cả các mô-đun mã nguồn của bạn, biên dịch chúng thành bytecode llvms, kết hợp chúng thành một tập tin bytecode, sau đó tối ưu hóa toàn bộ điều, thay vì mỗi tập tin hoặc tối ưu hóa chức năng bạn nhận được với các trình biên dịch khác, với llvm bạn có thể nhận được bất kỳ mức độ nào để tối ưu hóa chương trình compilete bạn thích. sau đó bạn có thể lấy bytecode đó và sử dụng llc để xuất nó sang bộ thu mục tiêu. Tôi thường làm nhúng vì vậy tôi có mã khởi động riêng của tôi mà tôi quấn quanh đó nhưng về lý thuyết bạn sẽ có thể lấy tập tin đó và lắp ráp với biên dịch gcc và liên kết nó và chạy nó. gcc myfile.s -o myfile.Tôi tưởng tượng có một cách để có được các công cụ llvm để làm điều này và không phải sử dụng binutils hoặc gcc, nhưng tôi đã không dành thời gian.

Tôi thích llvm vì nó luôn luôn là một trình biên dịch chéo, không giống như gcc bạn không phải biên dịch một cái mới cho mỗi mục tiêu và đối phó với sắc thái cho mỗi mục tiêu. Tôi không biết rằng tôi có bất kỳ sử dụng cho điều JIT là những gì tôi đang nói tôi sử dụng nó như là một trình biên dịch chéo và như là một trình biên dịch bản địa.

Vì vậy, trường hợp đầu tiên của bạn là mặt trước, giữa, cuối và quá trình được ẩn khỏi bạn, bạn bắt đầu với nguồn và nhận được một nhị phân, thực hiện. Trường hợp thứ hai là nếu tôi hiểu ngay phía trước và giữa và dừng lại với một số tập tin đại diện cho giữa. Sau đó, giữa để kết thúc (bộ xử lý mục tiêu cụ thể) có thể xảy ra chỉ trong thời gian chạy. Sự khác biệt có phần phụ trợ, việc thực hiện thời gian thực của ngôn ngữ trung gian của trường hợp hai, có khả năng khác với phần phụ trợ của trường hợp một.

+4

cả gcc và icc đều có một lto và ipo mà "tối ưu hóa toàn bộ điều", do đó, nó không phải là một tính năng độc đáo của llvm. Ngoài ra, llvm không phải là một "trình biên dịch chéo" chỉ là một trình biên dịch, hỗ trợ nhiều mục tiêu trong nhị phân đơn. Nó tốt hơn một chút so với trình biên dịch chéo đơn giản, nó là trình biên dịch phổ quát - hoạt động cho bất kỳ mục tiêu nào. – osgx

+0

Tôi thích thuật ngữ "trình biên dịch phổ quát". cảm ơn cho bản cập nhật, tôi không biết bạn có thể nhận được gcc để làm điều đó, một cái gì đó để chơi với một số ngày. –

22

Đầu tiên, bạn sẽ có được LLVM bytecode (LLVM IR):

clang -emit-llvm -S -o test.bc test.c 

Thứ hai, bạn sử dụng LLVM JIT:

lli test.bc 

Đó chạy chương trình.

Sau đó, nếu bạn muốn để có được bản địa, bạn sử dụng LLVM backend:

llc test.bc 

Từ sản lượng lắp ráp:

as test.S 
5

Tôi đang thực hiện các bước để biên dịch và chạy JIT'ed mã từ thư trong cộng đồng LLVM.

[LLVMdev] MCJIT and Kaleidoscope Tutorial

tập tin tiêu đề:

// foo.h 
extern void foo(void); 

và chức năng cho một foo đơn giản() chức năng:

//foo.c 
#include <stdio.h> 
void foo(void) { 
    puts("Hello, I'm a shared library"); 
} 

Và chức năng chính:

//main.c 
#include <stdio.h> 
#include "foo.h" 
int main(void) { 
    puts("This is a shared library test..."); 
    foo(); 
    return 0; 
} 

Xây dựng thư viện được chia sẻ bằng cách sử dụng foo.c:

gcc foo.c -shared -o libfoo.so -fPIC 

Tạo mã bit LLVM cho chính.tập tin c:

clang -Wall -c -emit-llvm -O3 main.c -o main.bc 

Và chạy bitcode LLVM qua JIT (và MCJIT) để có được những kết quả mong muốn:

lli -load=./libfoo.so main.bc 
lli -use-mcjit -load=./libfoo.so main.bc 

Bạn cũng có thể đường ống đầu ra kêu vang vào lli:

clang -Wall -c -emit-llvm -O3 main.c -o - | lli -load=./libfoo.so 

Đầu ra

This is a shared library test... 
Hello, I'm a shared library 

Nguồn obt ained from

Shared libraries with GCC on Linux

Các vấn đề liên quan