2015-06-18 27 views
13

Pracuję nad kompilatorem, który emituje kod IL. Ważne jest, aby wynik IL był JIT zwany najszybszym możliwym kodem maszynowym przez kompilatory Mono i Microsoft .NET JIT.Optymalizacja IL dla kompilatorów JIT

Moje pytania są następujące:

  1. Czy jest sens, aby zoptymalizować wzory jak:

    'stloc.0; ldloc.0; ret' => 'ret' 
    'ldc.i4.0; conv.r8' => 'ldc.r8.0' 
    

    i takie, lub są JIT jest wystarczająco inteligentny, aby dbać o nich?

  2. Czy istnieje specyfikacja z listą optymalizacji wykonanych przez kompilatory JIT firmy Microsoft/Mono?

  3. Czy istnieje dobry odczyt z praktycznymi zaleceniami/najlepszymi praktykami optymalizacji IL, aby kompilatory JIT mogły z kolei generować najbardziej optymalny kod maszynowy (pod względem wydajności)?

+1

Z tego, co zbieram, JIT jest całkiem dobry w eliminowaniu 'stloc.0; ldloc.0; '. W przypadku IronScheme, próbowałem zmodyfikować wyjściowy il tak, aby był podobny do C#, opierając się na przekonaniu, że JIT prawdopodobnie będzie starał się zoptymalizować znane wzorce. Ale to tylko uczucie: D Zawsze możesz po prostu stworzyć mikrobenki, żeby je zmierzyć. – leppie

+1

. Jittery .NET nie są szczególnie inteligentne (w końcu nie mają zbyt wiele czasu). Dlaczego zależy ci na "najszybszym możliwym"? – Luaan

+1

@Luaan, zależy mi na "najszybszym możliwym", ponieważ jest to kompilator, który musi wytworzyć kod do intensywnych obliczeń. Najlepiej byłoby, gdyby tworzył natywny kod maszynowy, ale myślę o IL dla lepszej przenośności i łatwości konserwacji. Jednak wydajność nadal jest najwyższym priorytetem. –

Odpowiedz

5
  1. Oba wzory yo opisane są proste rzeczy, że JIT faktycznie dostaje prawo (z wyjątkiem non-prymitywnych elemencie). W formie SSA stała propagacja i eliminacja wartości martwych jest bardzo łatwa.
  2. Nie, musisz sprawdzić, co może zrobić JIT. Sprawdź literaturę kompilatora, aby zobaczyć, jakich standardowych optymalizacji oczekiwać. Następnie przetestuj je. Dwa JIT, które mamy obecnie, optymalizują się bardzo niewiele, a czasem nie są w stanie uzyskać najbardziej podstawowych rzeczy. Na przykład MyStruct s; s.x = 1; s.x = 1; nie jest zoptymalizowany przez RyuJIT. s = s; też nie jest. s.x + s.x ładuje x dwa razy z pamięci. Oczekuj niewiele.
  3. Musisz zrozumieć, na czym polega podstawowa operacja na kodzie maszynowym. To nie jest zbyt skomplikowane. Wypróbuj kilka rzeczy i spójrz na listę demontażu. Szybko zorientujesz się, jak będą wyglądać wydruki.
+0

Dlaczego SSA jest trafny? Czy kompilatory JIT używają tego wewnętrznie? – svick

+0

@svick Jestem prawie pewien, że tak. Wydaje się to bardzo istotne. "ssabuilder.cpp" w CoreCLR wydaje się robić coś takiego. https://en.wikipedia.org/wiki/Static_single_assignment_form#Compilers_using_SSA_form Zobacz, jak wszechobecny jest. – usr

5

Nadmiarowe konwersje i ładowanie/zapisywanie w ten sposób są dość nieuniknionym efektem ubocznym rekurencyjnego porządnego parsera. Możesz technicznie pozbyć się ich za pomocą optymalizatora peephole. Ale nie ma się czym martwić, kompilatory C# i VB.NET również je generują.

Istniejące zakłócenia .NET/Mono są bardzo dobre w optymalizacji. Koncentrują się na optymalizacji kodu, który naprawdę ma znaczenie dla szybkości wykonania, kodu maszyny. Z bardzo dobrą zaletą, że każdy, kto pisze kompilator, który generuje IL, automatycznie czerpie korzyści z tych optymalizacji bez konieczności robienia czegoś specjalnego.

Optymalizacje drgań są opisane w this post.