kategorie: ANSI C, Asembler, C++
[wyróżniony] [#31] Re: gcc - pytania

@Sventevith, post #26

Dziala to mniej wiecej tak:
WinUAE na zdefiniowane dwie trzy partycje: 1 z systemem, 2 z sasc (obie partycje typu hardfile) oraz 3 typu dir na projekty, gdzie jest plik solution, projektu, kod zrodlowy i gdzie generowany jest kod wynikowy.
Przy uruchomieniu winuae jest startowana emulacja AmigaOS i uruchamiany jest na nim serwer, ktory odbiera komendy z VS po tcp.
Dodatki to rozszerzenia, ktore definiuja nowe typy platform (m.in. AmigaOS-68k), dodaja nowe typy template projektow dla Amigi ze szkieletami kodu (m.in. Application, SharedLibrary, Device, ResidentModule itp) , umozliwiaja konfigurowanie kompilatora, linkera I debuggera z poziomu VS (dialog z project->properties), konfiguruja msbuild aby je wykorzystywal. Do tego przerobiony BuildCPPTasks.dll tak, aby parsowal i wywolywal kompilator i linker z odpowiednimi parametrami, specyficznymi dla danego kompilatora. W przypadku gcc to jest lokalnie (kroskompilacja), w przypadku sas jest cos w rodzaju remote shell, ktore wysyla polecenia po tcp do serwera, dzialajacego na winuae i przekazuje do VS output z konsoli amigowej (np. liste bledow czy warningow), ktory jest parsowany i wyswietlany w odpowiednich oknach VS.

BTW: Napisalem, ze uzywam Visual Studio a nie Visual Studio Code. To dwie rozne rzeczy - VSC to w zasadzie editor tekstu w typescripcie z pluginami, a VS to duze IDE z mnostwem wbudowanych funkcjonalnosci.
2
[#32] Re: gcc - pytania

@Don_Adan, post #29

No nie wiem, niby raczej to bez znaczenia w tym przypadku, ale kompilator do takich rzeczy powinien uzywac rejestrow scratch czyli D0 lub D1, a nie D2.
Skoro mu w kodzie jawnie kazał użyć D2... to użył.
1
[#33] Re: gcc - pytania

@Krashan, post #32

Czyli powinien mu kazac uzyc D1?
Swoja droga to kompilator raczej sam taka mikrooptymalizacje powinien potrafic zrobic.
Bez prowadzenia za raczke.
Tym bardziej, ze chyba ja zna, tak mi sie przynajmniej wydaje, patrzac po generowanym kodzie.
Sredniozaawansowany koder by cos takiego potrafil zrobic.
[#34] Re: gcc - pytania

@Don_Adan, post #33

Czyli powinien mu kazac uzyc D1?
W tym momencie tak, bo cała rzecz zasadzała się na tym, żeby zmusić kompilator do zapisania tego adresu do rejestru danych, żeby flagi się ustawiły bez konieczności wykonywania CMPA. Dla kompilatora jednakże to działanie bez sensu, bo dana jest adresem, w dodatku chwilę później jest użyta jako baza do zaadresowania elementu struktury.

Moim zdaniem robienie tego rodzaju optymalizacji w kodzie, który pewnie się wykonuje raz, przy starcie programu, to sztuka dla sztuki.

Ostatnia aktualizacja: 18.10.2024 13:03:12 przez Krashan
[#35] Re: gcc - pytania

@Don_Adan, post #29

Bo bojach udało mi się wygenerować z takiego kodu
void MemoryRelease(void)
{
	register APTR memoryBlock __asm("d1") = gm;

	if (memoryBlock)
	{
		register struct Library *SysBase __asm("a6") = GetExecBase();
		register APTR block __asm("d0") = gm->chip;

		if (block)
		{
			FreeMem(block, MEMORY_CHIP_SIZE);
		}

		FreeMem(memoryBlock, MEMORY_PUBLIC_SIZE); 
	}
}


Taki kod
nop
_MemoryRelease:	move.l	a4,d1
	beq.s	lbC000092
	move.l	4.w,a6
	move.l	(a4),d0
	beq.s	lbC000088
	move.l	d0,a1
	moveq	#$30,d0
	swap	d0
	jsr	-$D2(a6)
lbC000088:	moveq	#$10,d0
	swap	d0
	move.l	d1,a1
	jsr	-$D2(a6)
lbC000092:	rts


@Krashan

Moim zdaniem robienie tego rodzaju optymalizacji w kodzie, który pewnie się wykonuje raz, przy starcie programu, to sztuka dla sztuki.


Tak to sztuka dla sztuki i według mnie pełna pułapek. Ja to chciałem zobaczyć czy kompilator potrafi wygenerować kod, bardzo podobny do tego jaki kod ja bym chciał widzieć. I jak na razie stwierdzam, że jest możliwe napisanie kodu w C, który zostanie skompilowany do bardzo dobrego kodu asm. Co łamie moje przekonania na temat kompilatora C (już nie ważne jakiego), że kod asm po kompilacji to ja mogę przyspieszyć przynajmniej dwukrotnie. To ważna nauka dla mnie.
[#36] Re: gcc - pytania

@docent, post #31

Czyli to dużo bardziej skomplikowane niż myślałem. Zapewne można ustawić VSC aby projekty zaczytał z partycji plikowej UAE a kompilacje uruchomić z działającego emulatora. Jak wygląda sprawa debuggerów w przypadku m68k czy gcc oraz sas dostarczają takie narzędzie ?

PS. Tak wiem czym było/jest VS. Ostatni raz z VS korzystałem 20 lat temu nie widziałem że nadal jest rozwijany przez M$.
[#37] Re: gcc - pytania

@asman, post #35

Teraz to wyglada ok.
A co do szybkosci dzialania, to na pewno kompilator nie moze uzywac link.w/unlk.w tylko dzialac na rejestrach.
Podejrzewam, ze kompilator moze miec problem jesli brakuje mu rejestrow.
Czyli raczej skomplikowane procedury typu c2p albo audio mixer, tam powinny byc duze roznice.
Ale moze sie myle?
[#38] Re: gcc - pytania

@Don_Adan, post #37

Podejrzewam, ze kompilator moze miec problem jesli brakuje mu rejestrow.
Ale pisząc samodzielnie w asemblerze, też masz problem gdy brakuje Ci rejestrów... Kompilator użyje na pewno D0-D7 i A0-A3. Kompilator użyje też A4, jeżeli nie skorzystasz z opcji -fbaserel (adresowanie zmiennych globalnych offsetem do A4). Kompilator użyje A5, jeżeli wyłączysz robienie ramek stosu (LINK/UNLK) opcją -fomit-frame-pointer. Kompilator użyje też A6, zwłaszcza jeżeli nie wywołasz w procedurze żadnej funkcji systemowej. A7 raczej nie użyje, ale to już trochę jechanie po bandzie. Bo gdzieś wskaźnik stosu musisz jednak przechować i to najlepiej nie na stosie.

Ale podpowiem gdzie szukać słabych stron C. Mnożenie i dzielenie, zwłaszcza na 68000. Wynika to z pewnej zasady w C, zwanej promocją typów. Weźmy taki kod:
short a, b;
long c;

c = a * b;
Jeżeli ktoś myśli, że to się skompiluje do MULS.W, to będzie rozczarowany. Liczby 16-bitowe zostaną rozszerzone do 32 bitów i zostanie wykonany skok do procedury __mulsi3 z biblioteki standardowej. Promocja typów polega na tym, że najpierw typy wszystkich elementów wyrażenia są wyrównywane do "największego", a potem się robi operację. Można to obejść korzystając z extended asm, jak to zrobiłem w Untangle (dużo mnożeń jest potrzebnych przy sprawdzaniu czy poziom jest rozwiązany).

Ostatnia aktualizacja: 18.10.2024 17:21:49 przez Krashan
[#39] Re: gcc - pytania

@Krashan, post #38

W bardziej skomplikowanych procedurach uzywalem wszystkich 17 dostepnych rejestrow.
A jak bylo potrzebne to uzywalem tez "swap Dx", czyli mialem do dyspozycji 25 dostepnych rejestrow maksymalnie.
Nie wiem czy kompilator by tak potrafil, czy po prostu uzywal tylko pamieci ze stosu lub zlinkowanego A5.
[#40] Re: gcc - pytania

@Don_Adan, post #39

Nie wiem czy kompilator by tak potrafil
Raczej nie. Asembler wygrał. Wiem, że chciałeś to przeczytać.

Chociaż ja i tak bym wolał napisać tylko tą krytyczną 25-rejestrową procedurę w asemblerze i zlinkować z resztą kodu w C. Spróbuj kiedyś zrobić jakieś systemowe GUI w asemblerze... Nie to, że się nie da, ale nieciekawe zajęcie. Próbowałem, żeby nie było.
[#41] Re: gcc - pytania

@Sventevith, post #36

VS jest skomplikowany i jest bardzo malo dokumentacji o jego wewnetrznej budowie, wiec trzeba sie troche napracowac.
Co do VSCode to nie mam pojecia, nie uzywam - kiedys odpalilem, ubylo mi 500mb ramu, wiec sobie darowalem :)
Sas ma CodeProbe (cpr) - calkiem dobry C/C++ debugger okienkowy, dzialajacy pod systemem - mozna m.in. debugowac na zrodlach, assemblerze lub w trybie mieszanym. Cpr ma wszystkie opcje typu podglad zmiennych, struktur itp, ma tez mozliwosc przechwytywania nowych taskow, debugowania devices czy zdalnego debugowania po serialu albo sieci. Jedyny minus to taki, ze wiekszosc operacji robi sie za pomoca polecen, wpisywanych z klawiatury.
[#42] Re: gcc - pytania

@Krashan, post #40

Ja lubie/wole przerabiac robote innych.
Sam nic nie napisalem, bo sie na tym nie znam.
Jedyne "GUI" jakie uzywalem to bylo GUI do konfiguracji playerow do EaglePlayera.
Jakis prosty wybor typu slider do mixowania w kHz czy kropka do wyboru wersji.
Oryginal byl od Petera Kunatha (tworcy Delitrackera), potem przerobiony chyba przez Codetappera.
A potem juz sam robilem zmiany, typu save/load czy rozszerzenia wygladu.
Jak chcesz GUI w asemblerze to chyba EaglePlayer 2 ma tego najwiecej.
Zrodla kiedys byly na Aminecie, nie wiem czy dalej sa.
[#43] Re: gcc - pytania

@asman, post #35

Dla szybszego sprawdzania wygenerowanego kodu (dla przypadków z czystym C/C++) może się przydać takie narzędzie on line:
https://gcc.godbolt.org
Gdzie gcc dla 68k również jest dostępny.
2
[#44] Re: gcc - pytania

@asman, post #1

Mam kolejny problemik. Chciałbym umieścić wskaźnik funkcji w zmiennej. Czy idzie wygenerować kod pc-relative dla takiego przypadku ?

Przykładowy kod
typedef void(*PVF)(void);

static PVF state;

void foo(void)
{
}

void bar(void)
{
 state = foo;
}


Który jest generowany do takiego kodu (na tej stronie gcc.godbolt.org), niezależnie jaką wersję gcc wybiorę.

foo:
        nop
        rts
bar:
        move.l #foo,state
        nop
        rts
[wyróżniony] [#45] Re: gcc - pytania

@asman, post #44

sprobuj opcji -mpcrel
[#46] Re: gcc - pytania

@docent, post #45

Dzięki, faktycznie robi tak jak myślałem.

Z ciekawości sprawdziłem na ami na gcc 2.95.3 i tej opcji tam nie ma.
[#47] Re: gcc - pytania

@asman, post #1

Przybywam z kolejnymi pytania w sprawie gcc.
Chciałem użyć kodu z amiga.lib, by zobaczyć jak to będzie wyglądało. Udało mi się dodać do +lamiga do makefile i wszystko fajnie. Na tapętę wziąłem sobie NewList, które to sobie siedzi w tej bibliotece.
I wszystko jest dobrze do pewnego momentu. Otóż, jak dodam sobie parametr -fomit-frame-pointer,
To wtedy nie działa to dobrze. Zajrzałem w kod i NewList wygląda tak
_NewList:	move.l	4(sp),a0
	move.l	a0,8(a0)
	addq.l	#4,a0
	clr.l	(a0)
	move.l	a0,-(a0)
	rts

I tu jest pies pogrzebany, bo jak wywalę parametr -fomit-frame-pointer to na stos jest odkładany wskaźnik na strukturę List i wszystko jest wtedy w porządku.
I teraz pytanie czy trzeba użyć jakieś innej wersji biblioteki (która nie ma tego syfu w postaci move.l 4(sp),a0) a może jest makro (które jest w asm (lists.i a nie ma go w lists.h).
1
[#48] Re: gcc - pytania

@asman, post #47

Bardziej mi to wygląda na problem z przekazaniem argumentu. Z kodu, który tutaj pokazałeś wynika, że NewList() oczekuje przekazania argumentu na stosie (standard dla C). Opcja -fomit-frame-pointer nie powinna mieć na to wpływu, natomiast jeżeli użyłeś -mregparm, to masz przyczynę problemu.
1
[#49] Re: gcc - pytania

@Krashan, post #48

Faktycznie, chodziło mi o -mregparm. To znaczy że jak mam tą opcję, to mogę się pożegnać z amiga.lib ?

Druga sprawa jak używam gcc bez tego całego ixemul i innych rzeczy (dostarczam sam kod startowy) to czy mogę się również pożegnać z czymś takim jak funkcja exit ? Czy można ją jakoś samemu ogarnąć ?
1
[#50] Re: gcc - pytania

@asman, post #49

Faktycznie, chodziło mi o -mregparm. To znaczy że jak mam tą opcję, to mogę się pożegnać z amiga.lib?
Teoretycznie nie, o ile miałbyś jej źródła i skompilował je również z opcją -mregparm. Dotyczy to każdej biblioteki statycznej.

Druga sprawa jak używam gcc bez tego całego ixemul i innych rzeczy (dostarczam sam kod startowy) to czy mogę się również pożegnać z czymś takim jak funkcja exit?
Tak.

Czy można ją jakoś samemu ogarnąć?
W systemie bez śledzenia zasobów, a takim jest AmigaOS, będzie to zawsze hack. To, co jest w ixemul też jest hackiem.

Ostatnia aktualizacja: 15.09.2025 13:00:05 przez Krashan
1
[#51] Re: gcc - pytania

@Krashan, post #50

Czy można ją jakoś samemu ogarnąć?

W systemie bez śledzenia zasobów, a takim jest AmigaOS, będzie to zawsze hack. To, co jest w ixemul też jest hackiem.

Funkcja exit() z biblioteki standardowej C zamyka wszystkie pliki otwarte poleceniem fopen(), oraz zwalnia całą pamięć zaalokowaną przez malloc() i calloc(). Wykonuje też sekwencję procedur zarejestrowanych przez atexit(). Biblioteka standardowa C ma śledzenie własnych zasobów.

Funkcja Exit() z dos.library nie jest zalecana do zatrzymywania działania programu, dlatego że odpowiednik dostarczany przez kompilator zwalnia wspomniane zasoby.

Natomiast nie odnosi się to do zasobów otwieranych przez funkcje biblioteczne Amiga OS.

Faktycznie, chodziło mi o -mregparm. To znaczy że jak mam tą opcję, to mogę się pożegnać z amiga.lib?

Teoretycznie nie, o ile miałbyś jej źródła i skompilował je również z opcją -mregparm. Dotyczy to każdej biblioteki statycznej.

Istnieje kilka odpowiedników optymalizacji -mregparm:

- W C możemy podać słowo kluczowe register na liście parametrów. Jest to wskazówka dla kompilatora że dany parametr chcemy przechować w rejestrze. Parametr nadal jest przekazywany przez stos.

- Użyć makr, które są często stosowane np. przez stdio.h przy buforowanym odczycie znaków z plików.

To są sposoby w pełni zgodne z C.

Dla przykładu ja stosuję takie konstrukcje w C, korzystając z widoczności zmiennych:

struct Obiekt *obiekt = start;

{
    register LONG zmienna = obiekt->skladowa;
    /* Tutaj operacja na zmiennej */
} 

/* Tu zmienna niewidoczna - rejestr może być zwolniony */
obiekt++;

Z kolei wstawki asemblerowe dają wygodny dostęp do rejestrów, stosu itp. i można ich użyć, a czasami są niezbędne, np. przy korzystaniu z funkcji bibliotecznych Amiga OS.

Uważam, że warto wspomnieć o DICE czy SAS/C, które mają to - według mnie - rozwiązane troszkę wygodniej, w tym obsługę bibliotek linkowalnych (istnieją komendy do tworzenia takich, sam korzystałem).

Pozdrawiam.

Ostatnia aktualizacja: 15.09.2025 20:50:19 przez Hexmage960
[#52] Re: gcc - pytania

@Hexmage960, post #51

@Krashan
Dzięki. W sumie to mi nie szkoda tego exit.

@Hexmage960
Dzięki.
Z tym register to jest tak, że kompilator nie ma obowiązku przestrzegać.
Ja jestem też zwolennikiem by kod był jak najbardziej czytelny, więc dodatkowe słowo register w liście parametrów powoduje że mi się to osobiście nie podoba (lubię też jak w linii jest max 80 znaków - mowa o Ami).
[#53] Re: gcc - pytania

@asman, post #52

Tak, oczywiście należy korzystać z register z umiarem. Również nie lubię deklaracji funkcji w C z wieloma parametrami w rejestrach, szczególnie wskaźników na takie funkcje, ze względu na słabą czytelność.

DICE oferuje swoje narzędzia do przekazywania przez rejestry/stos, takie jak __regargs i __stkargs.

Gdyby w GCC dało się wykluczyć w podobny sposób funkcję NewList i inne z konwencji przekazywania przez rejestry, pewnie mogłoby to być bardzo zgrabne rozwiązanie.

Ja sam programując w DICE korzystam często np. z register __a1 w parametrach funkcji typu Hook, bo to mi wystarcza. Przy czym ten kompilator ma też przełączniki analogiczne do -mregparm (ale z opcją wykluczania wybranych funkcji). Z tych opcji sam nie korzystałem.

Ja bym na Twoim miejscu po prostu wyróżnił w GCC te funkcje gdzie przekazywanie przez stos ma duży wpływ na wydajność. Nie mam tutaj doświadczenia z GCC, ale robi się to z tego co wiem poprzez asm("a1").

Wtedy takie funkcje będą zachowywać się jak te z bibliotek Amiga OS.

GCC i tak bardzo dobrze optymalizuje kod, że chyba nie ma tu aż takiego problemu.

Ostatnia aktualizacja: 16.09.2025 18:22:07 przez Hexmage960
[#54] Re: gcc - pytania

@Hexmage960, post #53


Gdyby w GCC dało się wykluczyć w podobny sposób funkcję NewList i inne z konwencji przekazywania przez rejestry, pewnie mogłoby to być bardzo zgrabne rozwiązanie.

Oczywiście że można, wydzielając do osobnego modułu wywołania NewList (by zrobić regułę w makefile bez mregparm ). Albo opakowując wywołanie NewList robiąc makro które przewali z rejestru na stos.
Tylko to jakby dla mnie słabe rozwiązanie. Najlepsze jest to co powiedział Krashan, czyli biblioteka statyczna skompilowana z mregparm. Najlepsze bo nie musisz myśleć i przede wszystkim pamiętać o tym, bo to nie jest kwestia tego czy będę pamiętał tylko kiedy zapomnę o tym.

Być może zby słabo to zaakcentowałem ale tu chodzi o poprawność działania. Projekt bez mregparm działa a jak skompilowałem z mregparm to ubyło prawie 1kb i do tego jeszcze się zawiesił. Oczywiście od razu pojawiły się teorie spiskowe w moim umyśle, że mregparm nie działa a potem to już było rozdzieranie szat i wyrywanie włosów (tych, które jeszcze zostały). w końcu znalazłem przyczynę i w sumie to dobrze że się zawiesił. Przynajmniej wiadomo gdzie jest błąd.
[#55] Re: gcc - pytania

@asman, post #54

Oczywiście że można, wydzielając do osobnego modułu wywołania NewList (by zrobić regułę w makefile bez mregparm ). Albo opakowując wywołanie NewList robiąc makro które przewali z rejestru na stos.
Tylko to jakby dla mnie słabe rozwiązanie. Najlepsze jest to co powiedział Krashan, czyli biblioteka statyczna skompilowana z mregparm. Najlepsze bo nie musisz myśleć i przede wszystkim pamiętać o tym, bo to nie jest kwestia tego czy będę pamiętał tylko kiedy zapomnę o tym.

No tak, wydzielanie odwołań do NewList to słabe rozwiązanie. Mi chodziło o zwyczajne zamarkowanie deklaracji NewList przez __stkargs, tak jak jest to w DICE i wywoływanie z dowolnego modułu.

Rozwiązanie Krashana wymaga dostępu do kodu źródłowego biblioteki.

Być może zby słabo to zaakcentowałem ale tu chodzi o poprawność działania.

Jeśli chodzi tylko o poprawność działania to nie ma potrzeby korzystania z -mregparm. Zgoda, że pojawienie się usterki zasygnalizowało problem. Bez tego taki bug w programie mógłby pozostać niewykryty.

Ostatnia aktualizacja: 17.09.2025 13:37:22 przez Hexmage960
[wyróżniony] [#56] Re: gcc - pytania

@asman, post #47

Taki kod zawsze bedzie generowany, poniewaz glownym celem amiga.lib jest udostepnianie stubow do systemowych funkcji dla jezykow/kompilatorow, ktore przekazuja parametry do funkcji przez stos. Z tego powodu wszystkie dodatkowe funkcje w tej bibliotece tez przyjmuja parametry w takim formacie.
Jesli chcesz pozbyc sie tej obslugi stosu w kodzie wynikowym, to musisz sobie napisac taka funkcje sam. Akurat NewList jest banalne do zaimplementowania.
W ogole linkowanie z amiga.lib mozna sobie odpuscic - to jest zabytkowy produkt Commodore z czasow, gdy kompilatory nie radzily sobie z przekazywaniem odpowiednich parametrow w rejestrach. Jesli potrzebujesz dodatkowych funkcji z tej biblioteki, to lepiej uzywac small.lib - nie ma ona stubow systemowych, tylko funkcje pomocnicze. Warto pamietac, ze przy linkowaniu small.lib trzeba wlaczac odpowiednie inkludy z definicjami pragma, inaczej beda bledy.
Sasc jest dosc rozbudowany i pozwala parametry wywolania fukcji systemowych zdefiniowac za pomoca #pragma. Te definicje maja priorytet wzgledem stubow z amiga.lib, wiec w przypadku linkowania z ta biblioteka zalaczone pragmy zostana przetworzone do bezposrednich wywolan bez wykorzystania stosu na przekazanie parametrow. Dla funkcji bez zalaczonych pragm zostana wykorzystane stuby z amiga.lib z wykorzystaniem stosu!
Co ciekawe, sasc oferuje tez kompilowanie z ustawieniem obu sposobow przekazywania parametrow - mozesz np. zbudowac biblioteke, ktora mozna linkowac z programami, kompilowanymi z jednym lub drugim ze sposobow i bedzie to dzialalo. Funkcje z takiej biblioteki beda zawsze mialy na poczatku ladowanie parametrow ze stosu ale przy kompilacji programu z ustawieniem przekazywania parametrow w rejestrach w kodzie jest umieszczane wywolanie funkcji z biblioteki z pominieciem ladowania parametrow ze stosu.
2
[#57] Re: gcc - pytania

@docent, post #56

Dzięki za mnóstwo informacji, przetrawiam w wolnej chwili.

W sumie implementację NewList można znaleźć choćby tu.
Na stronie www.PPA.pl, podobnie jak na wielu innych stronach internetowych, wykorzystywane są tzw. cookies (ciasteczka). Służą ona m.in. do tego, aby zalogować się na swoje konto, czy brać udział w ankietach. Ze względu na nowe regulacje prawne jesteśmy zobowiązani do poinformowania Cię o tym w wyraźniejszy niż dotychczas sposób. Dalsze korzystanie z naszej strony bez zmiany ustawień przeglądarki internetowej będzie oznaczać, że zgadzasz się na ich wykorzystywanie.
OK, rozumiem