2012-07-14 27 views
56

LLVM có phi hướng dẫn với lời giải thích khá kỳ lạ:gì chính xác PHI hướng dẫn nào và làm thế nào để sử dụng nó trong LLVM

Các 'phi' hướng dẫn được sử dụng để thực hiện các nút φ trong đồ thị dưới SSA đại diện cho chức năng .

Thông thường nó được sử dụng để triển khai phân nhánh. Nếu tôi hiểu chính xác, nó là cần thiết để làm cho phân tích phụ thuộc có thể và trong một số trường hợp nó có thể giúp tránh tải không cần thiết. Tuy nhiên vẫn khó để hiểu chính xác nó là gì.

Kính vạn hoa example giải thích nó khá độc đáo đối với trường hợp if. Tuy nhiên, không rõ cách thực hiện các phép toán logic như &&||. Nếu tôi gõ như sau để online llvm biên dịch:

void main1(bool r, bool y) { 
    bool l = y || r; 
} 

ngoái, vài dòng hoàn toàn nhầm lẫn tôi:

; <label>:10          ; preds = %7, %0 
%11 = phi i1 [ true, %0 ], [ %9, %7 ] 
%12 = zext i1 %11 to i8 

Hình như nút phi sản xuất là kết quả mà có thể được sử dụng. Và tôi đã được ấn tượng rằng nút phi chỉ xác định từ đó các giá trị đường dẫn đến.

Ai đó có thể giải thích nút Phi là gì và cách triển khai || với nó?

Trả lời

52

Nút phi là lệnh được sử dụng để chọn giá trị tùy thuộc vào tiền thân của khối hiện tại (Xem here để xem hệ thống phân cấp đầy đủ - nó cũng được sử dụng làm giá trị, là một trong các lớp mà nó kế thừa) .

nút Phi là cần thiết do cấu trúc của SSA (nhiệm vụ đơn tĩnh) phong cách của mã LLVM - ví dụ, C sau ++ chức năng

void m(bool r, bool y){ 
    bool l = y || r ; 
} 

được dịch sang IR sau: (tạo ra thông qua clang -c -emit-llvm file.c -o out.bc - và sau đó xem qua llvm-dis)

define void @_Z1mbb(i1 zeroext %r, i1 zeroext %y) nounwind { 
entry: 
    %r.addr = alloca i8, align 1 
    %y.addr = alloca i8, align 1 
    %l = alloca i8, align 1 
    %frombool = zext i1 %r to i8 
    store i8 %frombool, i8* %r.addr, align 1 
    %frombool1 = zext i1 %y to i8 
    store i8 %frombool1, i8* %y.addr, align 1 
    %0 = load i8* %y.addr, align 1 
    %tobool = trunc i8 %0 to i1 
    br i1 %tobool, label %lor.end, label %lor.rhs 

lor.rhs:           ; preds = %entry 
    %1 = load i8* %r.addr, align 1 
    %tobool2 = trunc i8 %1 to i1 
    br label %lor.end 

lor.end:           ; preds = %lor.rhs, %entry 
    %2 = phi i1 [ true, %entry ], [ %tobool2, %lor.rhs ] 
    %frombool3 = zext i1 %2 to i8 
    store i8 %frombool3, i8* %l, align 1 
    ret void 
} 

Vậy điều gì xảy ra ở đây? Không giống như mã C++, trong đó biến l có thể là 0 hoặc 1, trong IR LLVM, nó phải được xác định khi. Vì vậy, chúng tôi kiểm tra xem% tobool có đúng hay không và sau đó chuyển đến lor.end hoặc lor.rhs.

Cuối cùng, chúng tôi cuối cùng cũng có giá trị của || nhà điều hành. Nếu chúng tôi đến từ khối nhập cảnh - thì đó là sự thật. Nếu không, giá trị này bằng với giá trị của% tobool2 - và đó chính xác là những gì chúng tôi nhận được từ dòng IR sau:

%2 = phi i1 [ true, %entry ], [ %tobool2, %lor.rhs ] 
+2

TL; Nút DR φ là biểu thức bậc ba. Người ta có thể tranh luận rằng nó không chứa điều kiện, nhưng thực sự, khi chuyển đổi sang mã cuối cùng, bạn không thể xác định bằng cách nào khác là một đối số đang hoạt động, vì vậy φ cũng phải có điều kiện. –

16

Bạn không cần sử dụng phi. Chỉ cần tạo ra các biến tạm thời. LLVM tối ưu hóa vượt qua sẽ chăm sóc tối ưu hóa biến tạm thời đi và sẽ sử dụng nút phi cho rằng tự động.

Ví dụ, nếu bạn muốn làm điều này:

x = 4; 
if (something) x = x + 2; 
print(x); 

Bạn có thể sử dụng nút phi cho lệnh này (trong giả):

  1. assign 4 đến x1
  2. if (một cái gì đó) chi nhánh đến 4
  3. tính x2 từ x1 bằng cách thêm 2
  4. gán x3 phi từ x1 và x2
  5. in
  6. cuộc gọi với x3

Nhưng bạn có thể làm mà không có nút phi (trong giả):

  1. phân bổ biến cục bộ trên đống gọi là x
  2. tải vào giá trị x1 tạm thời 4
  3. cửa hàng x1 đến x
  4. nếu (! something) branch đến 8
  5. tải x vào temp x2
  6. thêm x2 với 4 để tạm x3
  7. cửa hàng x3 đến x
  8. tải x để tạm x4
  9. gọi in với x4

Bằng cách chạy tối ưu hóa đi với llvm mã thứ hai này sẽ được tối ưu hóa để đầu tiên mã.

+0

Từ những gì tôi đã đọc nó có vẻ như có một vài hạn chế cần ghi nhớ ở đây. [mem2reg] (http://llvm.org/docs/Passes.html#mem2reg-promote-memory-to-register) là thẻ tối ưu hóa được đề cập và có một vài hạn chế được chỉ ra trong ví dụ về [Kính vạn hoa] ] (http://llvm.org/docs/tutorial/OCamlLangImpl7.html#memory-in-llvm). Nghe có vẻ như đây là, tuy nhiên, cách ưu tiên để xử lý vấn đề và được sử dụng bởi Clang. –

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