2012-05-06 31 views
6

Tôi đang viết một trình biên dịch cho một ngôn ngữ đơn giản giống như C cho một khóa học tôi đang dùng. bit này mã:Có gì sai với số đăng ký LLVM này?

int main() { 
    printInt(not(0)); 
    return 0; 
} 

int not(int n) { 
    if (n == 0) { 
     return 1; 
    } else { 
     int result = 0; 
     return result; 
    } 
} 

..Tôi ngây thơ biên dịch để bitcode này:

declare void @printInt(i32) 
declare void @printDouble(double) 
declare void @printString(i8*) 
declare i32 @readInt() 
declare double @readDouble() 

define i32 @main() { 
entry: 
    %0 = call i32 @not(i32 0) 
    call void @printInt(i32 %0) 
    ret i32 0 
    unreachable 
} 

define i32 @not(i32 %n_0) { 
entry: 
    %0 = icmp eq i32 %n_0, 0 
    br i1 %0, label %lab0, label %lab1 
lab0: 
    ret i32 1 
    br label %lab2 
lab1: 
    %result_0 = alloca i32 
    store i32 0, i32* %result_0 
    %1 = load i32* %result_0 
    ret i32 %1 
    br label %lab2 
lab2: 
    unreachable 
} 

Tuy nhiên, từ chối không chấp nhận mã.

opt: core023.ll:25:5: error: instruction expected to be numbered '%2' 
%1 = load i32* %result_0 

Bây giờ, từ những gì tôi hiểu về các thanh ghi tạm thời chưa được đặt tên, chúng được đánh số liên tục bắt đầu từ 0. Trường hợp ở đây. Nhưng dường như dòng "% 1 = sub .." phải được đánh số% 2. Tại sao vậy? Có bất kỳ hướng dẫn nào giữa% 0 ​​và% 1 tăng số thứ tự không? Hoặc có thể nó chỉ là một lỗi tiếp theo từ cái gì khác?

Trả lời

9

Trong LLVM, mọi thứ rằng có thể có tên nhưng không được gán một số. Điều này cũng bao gồm các khối cơ bản. Trong trường hợp của bạn

lab0: 
    ret i32 1 
    br label %lab2 

xác định hai khối cơ bản vì mỗi khối terminator instruction kết thúc một khối cơ bản. Điều này có nghĩa rằng, khái niệm, mã của bạn được phân tách như

lab0: 
    ret i32 1 
1: 
    br label %lab2 

và số miễn phí tiếp theo sau đó là 2.

Để ngăn chặn hành vi kỳ lạ như thế này, tôi khuyên bạn nên luôn luôn đặt tên một cách rõ ràng các khối cơ bản.

+0

Một cách khác để giải thích nguyên nhân gây ra sự cố là bạn cần tránh phân nhánh ngay lập tức sau câu lệnh trả về. Nếu ngôn ngữ của bạn có mã để đảm bảo rằng tất cả các đường dẫn điều khiển đều trở lại, thì nó sẽ là tầm thường để kiểm tra xem nhánh trước của bạn đã trả về chưa. Trong trường hợp nó đã trả về, không cần phải chèn lệnh nhánh (br). Có một số lượng sổ sách kế toán nhà nước bạn sẽ cần phải làm để làm cho LLVM hài lòng với các khối cơ bản của bạn. –

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