2014-12-12 15 views
23

ja przekształcić najprostszej kod CZrozumienie najprostszy llvm IR

#include <stdio.h> 

int main() 
{ 
    return 0; 
} 

jego llvm IR, przy użyciu

clang -emit-llvm -S hello.c 

wygenerowanego IR wynosi:

define i32 @main() #0 { 
     %1 = alloca i32, align 4 
     store i32 0, i32* %1 
     ret i32 0 
    } 

jednak zrobić nie rozumiem tego IR. (LLVM doc pomaga, ale nie tak dużo dla początkujących)

  1. Dlaczego mamy %1 = alloca i32, align 4? Co to odpowiada w oryginalnym kodzie?
  2. To samo pytanie dla store i32 0, i32* %1
  3. Czy alokacja oznacza alokację na stosie (zamiast alokacji dynamicznej)?
  4. Co oznacza "wyrównanie 4"?
+0

Wyrównanie wskazuje, że operacja pamięci powinna zostać wyrównana do 4 bajtów. Nie jestem pewien co do reszty. – MariusSiuram

Odpowiedz

19
define i32 @main() #0 

definiuje Ta funkcja nazywa main która zwraca 32 bitową liczbę całkowitą. #0 oznacza użycie atrybutów o nazwie #0 dla tej funkcji.Na przykład w IR może być coś w rodzaju attributes #0 = { alwaysinline alignstack=4 }, a te atrybuty zostaną zastosowane do main.

%1 = alloca i32, align 4 

Przydziela 32-bitową liczbę całkowitą na stosie. %1 to nazwa wskaźnika do tej lokalizacji na stosie. align 4 gwarantuje, że adres będzie wielokrotnością 4

store i32 0, i32* %1 

To ustawia 32 bitową liczbą całkowitą wskazywanego przez %1 do wartości 32 bit 0. To jak powiedzenie *x = 1 w C++

ret i32 0 

ten zwraca z funkcji z 32-bitową wartością zwracaną 0

Przypisanie jest nieparzyste, biorąc pod uwagę, że nie masz zmiennej lokalnej w main. LLVM używa BasicBlock do reprezentowania grup instrukcji, a podstawowy blok ma punkt wyjścia i listę instrukcji. Domyślam się, że kompilator zdecydował się użyć return jako wyjścia z podstawowego bloku i zdecydował się umieścić co najmniej jedną instrukcję w bloku. Zadanie jest w zasadzie nieoptymalne.

12

%n to wirtualne rejestry, które zostaną rozwiązane do rzeczywistych rejestrów podczas generowania kodu dla maszyny docelowej.

Numer i32 zawiera informacje o typie. W oryginalnym kodzie był to int, który kompilator przyjmuje jako 32-bitową liczbę całkowitą.

służy do przydzielania miejsca na stosie. W tym przykładzie jest to i32 (32-bitowa liczba całkowita), więc można załadować wartość 0 dla wartości zwracanej. align 4 podaje to przyrównanie 4 bajtowe, tj. Wskaźnik stosu będzie na 4-bajtowym adresie wyrównanym.

Nie jest to najskuteczniejsza reprezentacja, ale nie jest to celem, jeśli IR. IR powinien być przenośny dla różnych architektur. Następnie do zaplecza jest produkowany wydajny kod maszynowy.

LLVM Language Reference Manual

Dlaczego alloca i store to jest do zrobienia z tym jest funkcja main. Gdybyś nazwał tę funkcję czymś innym, IR po prostu zawierałby ret zgodnie z oczekiwaniami. Od sprawdzenia złożenia wyprodukowanego dla głównego wydaje się być powiązany ze wskaźnikiem bazowym stosu , ale nie do końca rozumiem, dlaczego tak się stało. Czas na wyciągnięcie normy C, jak sądzę.

Aktualizacja: Nie mogę znaleźć niczego w standardzie C, ale wygląda na to, że robi to dla każdej głównej funkcji. Nie znam podstawy kodu klangu na tyle dobrze, by ją wyśledzić.

Aktualizacja: Zobacz komentarze z Billem Lynchem poniżej. Te instrukcja obslugi istnieją:

do ewentualnego niejawny return 0 że główne funkcje mają

+0

Dziękuję. Dlaczego potrzebujemy tutaj% 1 (moje pytania nr 1 i nr 2)? – zell

+0

@zell: To nie jest konieczne. Jeśli włączyłeś optymalizatory (na przykład -O3), zostanie on usunięty. –

+0

@Bill. Dziękuję Ci. Nawet w przypadku nieskutecznego IR, powinien istnieć powód, dla którego% 1 jest używany. Co jest racjonalne, że LLVM IR potrzebuje dodatkowego% 1 (całkowicie rozumiem, że optymalizacja go odrzuci).? – zell

2

Zmienne są zwykle umieszczane na stosach w niezoptymalizowanych kompilacjach z powodów związanych z debugowaniem. W zoptymalizowanych kompilacjach, które używają prawdziwych rejestrów, wartość może zniknąć, zanim funkcja zostanie zamknięta.

Komentarz na temat przenośności nie jest dokładnie poprawny, jeśli to IR zostało przekazane przez "opt", wyeliminowałoby to magazyn stosów.

+0

Ale nie ma w głównej mierze żadnej zmiennej do wypróbowania i przechowywać na stosie. Patrząc na wiele innych wyników, zawsze wydaje się, że zapisują one 0 na stosie w main. – DrYap

+0

Wartość tam umieszczona to wartość zwracana. –

+0

Dziękuję Colin. Niesamowite informacje. Dodanie '-O3' do generatora ll w moich własnych cee sprawiło, że IRoo było łatwiejsze do zrozumienia :-) –

Powiązane problemy