Har flera gånger råkat ut för att kompilatorn (gcc (MC32)) optimerar bort valid kod, vilket naturligtvis får resterande kod att inte fungera.
Till exempel:
while(adj) { // fill spaces before numbers
adj--;
str[adj] = i2str_fill;
}
Aldrig kan köras.
Hur i helsike skall man kunna spåra sånt?
Man kan ju naturligtvis deklarera alla variabler som volatila, men det skall ju knappast behövas.
Någon som har ideér?
Det jag reagerar på är att adj bara verkar tilldelas ett värde när if-satsen if(i >0) är sann? Om if-satsen är falsk kommer adj aldrig få ett värde?
Nu vet jag iofs inte varför kompilatorn får för sig att optimera bort tilldelningen på grund av det...
Men generellt är det ju sån där röra med nästade if-satser som oftast ligger bakom bortoptimerad kod, eftersom kompilatorn kommer fram till att "det här kommer aldrig användas".
Spelar ingen roll om det är en massa nestade if-satser, kompilatorn får inte optimera bort kod, oavsett, möjligen ge en varning att den tror att raden är onödig.
Min gissning är att kompilatorn har analyserat vad du skickar in som argument och kommit fram till att den delen aldrig behövs.
Om inkommande värde på opt alltid har ett relativt lågt värde, så kommer opt - 32 bli ett stort värde, vilket sen efter opt >> 5 ändå kan göra så att opt alltid är större än i på rad 37 när du gör r = i - opt. Då blir r större än 128, vilket gör att r blir 0 på rad 38, vilket leder till att adj också blir 0 och while(adj)-loopen aldrig kommer att köras, och därför inte behövs.
Just för nästlade if-satser har jag råkat ut för GCC-buggar när -Os användes på Linuxkärnan. Oklart om buggen var beroende av målmiljön (SH4) eller det var generellt. Nu var detta ett tag sedan, kanske gcc 3,x eller tidig gcc 4. Lösningen var att köra -O2 plus alla flaggor som -Os lade på normalt lägger på. Så mao var buggen i det specifika som just -Os gjorde.
Jag hade börjat att labba med kompileringsflaggor.
En fundering vi har är att debuggern kanske är rätt korkad.
Eftersom det är en MIPS-processor, så funkar den väldigt mycket annorlunda jämfört med vanliga processorer.
Det kan vara så att den behåller variabeln i ett register för senare användning, och debuggern inte fattar det.
Får kolla i morgon, plocka bort volitile och se vad som händer egentligen.
Vi kör med O1 på det mesta, skall även testa utan optimering, kan iofs vara så att den filen inte är optimerad, eftersom det går att stega genom koden.
Oavsett, åter till frågan hur skall man kunna hitta det som kompilatorn får för sig att optimera bort.
Det är ju inte helt enkelt att gå igenom assemblerlistningen och jämföra med C-filerna, speciellt om man har någon miljon rader källkod.
Att kompilatorn gör fel osv, händer, men hur i helsike skall man kunna hitta det.
Skall kontrollera lite mer i morgon, gissar att man får göra en buggrapport till gcc.
Prova att lägga till ett dummy-anrop till funktionen någonstans där du sätter opt till 32 och se om det förändringar saker och ting. Jag har flera gånger varit övertygad om att kompilatorn gjort fel, för att sedan upptäcka att den faktiskt istället gjort någonting riktigt smart.
Kompilatorn har all rätt att ta bort kod som den ser aldrig kommer att användas, då det inte påverkar resultatet av körningen.
Sen är det ju alltid problem om man försöker stega sig igenom optimerad kod, eftersom det inte behöver finnas specifik i kod genererad för varje källkodsrad, och variabler kan flytta mellan register och stack lite hursomhelst.
Oavsett, åter till frågan hur skall man kunna hitta det som kompilatorn får för sig att optimera bort.
Ja det är ju ett forskningsområde i sig själv inom datavetenskapen, "compiler correctness". Det finns egentligen bara två fundamentala angreppssätt: formell verifiering respektive testning. Hårda bud.
MIPS är väl en av de mera välstuderade arktitekturerna, den är gammal och föredömligt enkel. Har du kollat att optimeringen inte kommer av externa faktorer som någon var inne på tidigare? Eller så gör den helt enkelt fel.