|
Виж темите без отговор | Виж активните теми
Дата и час: Вто Юли 28, 2026 12:29 am
GNU C/C++ static inline функция
| Автор |
Съобщение |
|
gicho
Ранг: Форумен бог
Регистриран на: Пон Мар 13, 2006 1:59 pm Мнения: 3867 Местоположение: Габрово
|
Питах дали се случва инлайнването защото ако не се случва, значи имаш нормална функция и съответно допълнителния код около нея.
Доколкото съм чел, за GCC няма начин да го "накараш" да извърши инлайнването, можеш да го "убедиш" като му осигуриш условията. Крайното решение винаги е негово.
Но за ARM това се случва и без някакви специални атрибути, дори при -O1. Стига тялото да инлайнваната функция да е било преди мястото на използването и.
|
| Сря Апр 20, 2011 1:37 pm |
|
 |
|
¶
Ранг: Форумен бог
Регистриран на: Пет Фев 25, 2005 1:58 pm Мнения: 4585 Местоположение: US
|
Значи грешката е моя, не е точно инструкции, както съм написал, а цикли на процесора, но общо взето е едно и също, защото само извикването на подпрограмата е 2 цикъла, всички останали инструкции са по 1 цикъл. И понеже тествам у нас, а поствам на другия ден се получават грешки. Тази вечер седнах и извъртях всички комбинации на оптимизациите с 4 различни версии на static inline и 2 версии на макроси, резултатите са най-отдолу. Това съобщение излиза когато използваш evaluation версия, при мен си е пълната версия.
Да, инлайнва се, при някои от оптимизациите
Основния проблем със static inline е, че не връща верен резултат, дори когато е само C код. Което е много странно. Включваш отпимизацията и резултата е неверен. Променливата в която записвам резултата е декларирам като volatile, което мисля, че трябва да накара компилатора да не я оптимизирва.
Ето и 6-те комбинации които изтествах:
 |  |  |  | Код: /* static1_MADD64() * - Оптимизация 0: работи, 34 instruction cycles * - Оптимизация 1: не работи, 11 instruction cycles * - Оптимизация 2: не работи, 11 instruction cycles * - Оптимизация s: не работи, 11 instruction cycles * - Оптимизация 3: не работи, 11 instruction cycles */ static __inline int64 static1_MADD64(int64 s, int x, int y) { s += (int64)x * y; return s; }
/* static2_MADD64() * - Оптимизация 0: работи, 23 instruction cycles * - Оптимизация 1: работи, 19 instruction cycles * - Оптимизация 2: работи, 19 instruction cycles * - Оптимизация s: работи, 19 instruction cycles * - Оптимизация 3: работи, 19 instruction cycles */ static __inline int64 __attribute__((always_inline)) static2_MADD64(int64 s, int x, int y) { __asm__ volatile ("madd %2,%3" : "+l" ( ((Int64*)&s)->lo ), "+h" ( ((Int64*)&s)->hi ) : "r" (x), "r" (y)); return s; }
/* static3_MADD64() * - Оптимизация 0: не работи, 31 instruction cycles * - Оптимизация 1: не работи, 10 instruction cycles * - Оптимизация 2: не работи, 10 instruction cycles * - Оптимизация s: не работи, 10 instruction cycles * - Оптимизация 3: не работи, 10 instruction cycles */ static __inline int64 static3_MADD64(int64 s, int x, int y) { __asm__ volatile ("madd %2,%3" : "+l" ( ((uint32*)&s)[0] ), "+h" ( ((int32*)&s)[0] ) : "r" (x), "r" (y)); return s; }
/* static4_MADD64() * - Оптимизация 0: работи, 31 instruction cycles * - Оптимизация 1: не работи, 11 instruction cycles * - Оптимизация 2: не работи, 11 instruction cycles * - Оптимизация s: не работи, 11 instruction cycles * - Оптимизация 3: не работи, 11 instruction cycles */ static __inline int64 static4_MADD64(int64 s, int x, int y) { return (s + ((int64)x * y)); }
/* macro1_MADD64() * - Оптимизация 0: работи, 11 instruction cycles * - Оптимизация 1: работи, 11 instruction cycles * - Оптимизация 2: работи, 11 instruction cycles * - Оптимизация s: работи, 11 instruction cycles * - Оптимизация 3: работи, 11 instruction cycles */ #define macro1_MADD64( s, x, y) __asm__ volatile ("madd %2,%3" : "+l" ( ((Int64*)&s)->lo ), "+h" ( ((Int64*)&s)->hi ) : "r" (x), "r" (y))
/* macro2_MADD64() * - Оптимизация 0: работи, 11 instruction cycles * - Оптимизация 1: работи, 11 instruction cycles * - Оптимизация 2: работи, 11 instruction cycles * - Оптимизация s: работи, 11 instruction cycles * - Оптимизация 3: работи, 11 instruction cycles */ #define macro2_MADD64( s, x, y) __asm__ volatile ("madd %2,%3" : "+l" ( ((uint32*)&s)[0] ), "+h" ( ((int32*)&s)[1] ) : "%r" (x), "r" (y))
|  |  |  |  |
"%r" или "r" miro_atc предположи, че ще дава разлика, но се генерира един и същ код при вградения асемблер. Пробвах и с вкл/изкл на Omit frame pointer, няма разлика, static inline кода е винаги по-голям от макроса, когато връща верен резултат де, щото например static4_MADD64() също дава 11 цикъла, колкото и макросите, но не връща верен резултат, докато в същото време резултата в хардуерните регистри [hi:lo] на всички комбинации на функции/макроси/оптимизации е коректен. Просто не винаги ми прехвърля [hi:lo] в резултатната клетка. Листинга на двата макроса:  |  |  |  | Код: 720: macro1_MADD64( s, x, y); 9D00BAD8 8FA20010 lw v0,16(sp) 9D00BADC 8FBF0014 lw ra,20(sp) 9D00BAE0 8FB80018 lw t8,24(sp) 9D00BAE4 00400013 mtlo v0 9D00BAE8 8FB9001C lw t9,28(sp) 9D00BAEC 03E00011 mthi ra 9D00BAF0 73190000 madd t8,t9 9D00BAF4 00009010 mfhi s2 9D00BAF8 00009812 mflo s3 9D00BAFC AFB20014 sw s2,20(sp) 9D00BB00 AFB30010 sw s3,16(sp)
725: macro2_MADD64( s, x, y); 9D00BB1C 8FAE0010 lw t6,16(sp) 9D00BB20 8FAD0014 lw t5,20(sp) 9D00BB24 8FAB0018 lw t3,24(sp) 9D00BB28 01C00013 mtlo t6 9D00BB2C 8FAC001C lw t4,28(sp) 9D00BB30 01A00011 mthi t5 9D00BB34 716C0000 madd t3,t4 9D00BB38 00004810 mfhi t1 9D00BB3C 00005012 mflo t2 9D00BB40 AFA90014 sw t1,20(sp) 9D00BB44 AFAA0010 sw t2,16(sp)
|  |  |  |  |
Листинга на static2_MADD64(), която единствено работи коректно при всички възможни комбинации на оптимизациите:  |  |  |  | Код: 21: /* static2_MADD64() 22: * - Оптимизация 0: работи, 23 instruction cycles 23: * - Оптимизация 1: работи, 19 instruction cycles 24: * - Оптимизация 2: работи, 19 instruction cycles 25: * - Оптимизация s: работи, 19 instruction cycles 26: * - Оптимизация 3: работи, 19 instruction cycles 27: */ 28: static __inline int64 __attribute__((always_inline)) static2_MADD64(int64 s, int x, int y) { 29: __asm__ volatile ("madd %2,%3" : "+l" ( ((Int64*)&s)->lo ), "+h" ( ((Int64*)&s)->hi ) : "r" (x), "r" (y)); 30: return s; 31: } ; Листинг static2_MADD64() при оптимизация s ; Разпределение на стека вътре в static2_MADD64( стека расте надолу ): ; SP(+16) -> s.lo ; SP(+20) -> s.hi ; SP(+24) -> x ; SP(+28) -> y ; SP(+32) -> lo клетка на резултата от static2_MADD64 /*res = static2_MADD64(s,x,y)*/ ; SP(+36) -> hi клетка на резултата от static2_MADD64 Address OpCode 9D00B9B0 8FB30010 lw s3,16(sp) ; s3 = s.lo; 9D00B9B4 8FB20014 lw s2,20(sp) ; s2 = s.hi; 9D00B9B8 AFB30020 sw s3,32(sp) ; SP[-32] = s3; // res = s.lo --> излишен код 9D00B9BC AFB20024 sw s2,36(sp) ; SP[-36] = s2; // res = s.hi --> излишен код 9D00B9C0 8FB10020 lw s1,32(sp) ; s1 = s.lo; // s.lo & s.hi сa вече в регистрите s3 & s2 9D00B9C4 8FAF0024 lw t7,36(sp) ; t7 = s.hi; // за какъв чеп се зареждат отново в s1 & t7 ??? 9D00B9C8 8FAD0018 lw t5,24(sp) ; t5 = x; 9D00B9CC 02200013 mtlo s1 ; lo = s1; // наместо mtlo s3 9D00B9D0 8FAE001C lw t6,28(sp) ; t6 = y; 9D00B9D4 01E00011 mthi t7 ; hi = t7; // наместо mthi s2 9D00B9D8 71AE0000 madd t5,t6 ; [hi:lo] += t5 * t6; // s += x * y; 9D00B9DC 00005810 mfhi t3 ; t3 = hi; // s.hi 9D00B9E0 00006012 mflo t4 ; t4 = lo; // s.lo 9D00B9E4 AFAB0024 sw t3,36(sp) ; SP[-36] = s.hi; // запис на резултата, или res = static2_MADD64(s,x,y); 9D00B9E8 AFAC0020 sw t4,32(sp) ; SP[-32] = s.lo; 9D00B9EC 8FAA0020 lw t2,32(sp) ; t2 = s.lo; // За какъв чеп ми са следващите 4-ри инструкции ? 9D00B9F0 8FA90024 lw t1,36(sp) ; t1 = s.hi; // След връщането от static2_MADD тези клетки от стека 9D00B9F4 AFAA0010 sw t2,16(sp) ; s.lo = lo; // са непотребни, защо копира там резултата ??? 9D00B9F8 AFA90014 sw t1,20(sp) ; s.hi = hi;
|  |  |  |  |
В заключение, static inline генерира минимум 19 инструкции , докато макроса 11, или с 43% по-голям код. Докато писах този пост възникна още един въпрос  Включваш оптимизациите и изведнъж при постъпково изпълнение кода полудява, подскача насам-натам. Вглеждайки се в последователността на извличане на инструкциите от адресите прави впечатление, че в листинг файла инструкциите не са подредени по реда на извикване от съответните адреси. Примерно горния листинг на static2_MADD64 оригинално изглежда така:  |  |  |  | Код: 9D00B9B0 8FB30010 lw s3,16(sp) 9D00B9B4 8FB20014 lw s2,20(sp) 9D00B9B8 AFB30020 sw s3,32(sp) 9D00B9BC AFB20024 sw s2,36(sp) 9D00B9C8 8FAD0018 lw t5,24(sp) 9D00B9D0 8FAE001C lw t6,28(sp) 9D00B9F4 AFAA0010 sw t2,16(sp) 9D00B9F8 AFA90014 sw t1,20(sp) 29: __asm__ volatile ("madd %2,%3" : "+l" ( ((Int64*)&s)->lo ), "+h" ( ((Int64*)&s)->hi ) : "r" (x), "r" (y)); 9D00B9C0 8FB10020 lw s1,32(sp) 9D00B9C4 8FAF0024 lw t7,36(sp) 9D00B9CC 02200013 mtlo s1 9D00B9D4 01E00011 mthi t7 9D00B9D8 71AE0000 madd t5,t6 9D00B9DC 00005810 mfhi t3 9D00B9E0 00006012 mflo t4 9D00B9E4 AFAB0024 sw t3,36(sp) 9D00B9E8 AFAC0020 sw t4,32(sp) 9D00B9EC 8FAA0020 lw t2,32(sp) 9D00B9F0 8FA90024 lw t1,36(sp) 30: return s; 31: }
|  |  |  |  |
Първите 4-ри инструкции са на последователни адреси, обаче 5-тата не е ами е
Наложи се ръчно да подредя листинг, че да проследя стъпка по стъпка генерирания код. Има ли някаква опция, което да задава последователна подредба, т.е. така както ще се запише кода в паметта на професора, а не както на GCC му кефне да ми го показва ?
_________________ Ето аз дишам, работя, живея и програми пиша тъй както умея, с проца под вежди се гледаме строго и боря се с него доколкото мога....
|
| Чет Апр 21, 2011 6:21 am |
|
 |
|
miro_atc
Ранг: Форумен бог
Регистриран на: Нед Фев 26, 2006 6:52 pm Мнения: 11266 Местоположение: Добрич
|
Меко казано "странно"... Не че при нов таргет няма трески, но това си е як чеп пък и MIPS ядрото изобщо не е ново. Тук не трябва ли да е "+h" ( ((int32*)&s)[1] ) ? Всъщност може и "l" да е грешно - не знам дали си с MSB или LSB, но при всички случаи low и hi не може да са еднакви... Не.. казах че няма смисъл от %-та. Той указва че може да размени тоя и следващия аргумент. Но файда от размяната няма.. Да, това го прави... предполагам с цел да подреди конвейра. И обикновено го прави винаги, дори и да нямаш конвейр. Примерно при АРМ7 редът няма значение, но то пак си го размества като за АРМ9. Тъй че дори и да нямаш конвейр не се учудвай.. може би има друго код-съвместимо ядро и то за всеки случай го подрежда...
Това е типично за GCC... Едното копие е входен параметър, другото е локална променлива. Естествено е че няма смисъл локалната променлива да е auto и може да е регистрова и няма смисъл да се ъпдейтва. Ама GCC-то така го прави. Едва при последната версия (4.6) забелязвам видим напредък в тая област и вече почти не забелязвам подобни недомислици в кода.
|
| Чет Апр 21, 2011 9:35 am |
|
 |
|
gicho
Ранг: Форумен бог
Регистриран на: Пон Мар 13, 2006 1:59 pm Мнения: 3867 Местоположение: Габрово
|
Разбирам че е спам, ама можеш ли да споделиш впечатления от 4.6? Иска ми се да минем на него, засега не виждам проблеми (спрямо 4.0.x). Не можах да намеря свястно описание какво е сменено. Има ли смисъл от прехода?
|
| Чет Апр 21, 2011 11:30 am |
|
 |
|
miro_atc
Ранг: Форумен бог
Регистриран на: Нед Фев 26, 2006 6:52 pm Мнения: 11266 Местоположение: Добрич
|
ми 4.6 има доста разлики... аз май писах в другата тема за тулчейна. Накратко има добавени неща в Ц++ (догонват стандартите). Изцяло е променена оптимизацията (вече бачка на ниво цяло приложение) и постига значително по-добри резултати. При мен от 200-250К успя да махне около 15К спрямо предишното GCC 4.4 май беше. Warmnings има добавени доста...
Абе има си разлики... Сега единственият недостатък дето съм забелязал е че при дебъг на определени функции не може да намери сорс кода. Не знам дали е компилатора или новото GDB... Засега не ми се е налагало толкова да дебъгвам, като се наложи ще го почопля повече.
|
| Чет Апр 21, 2011 1:27 pm |
|
 |
|
¶
Ранг: Форумен бог
Регистриран на: Пет Фев 25, 2005 1:58 pm Мнения: 4585 Местоположение: US
|
Да, сбъркал съм го, но и като го направя s[1] пак е същата работа. LSB first е подредбата в паметта. Нямам нищо против да си подрежда конвейра, въпроса е, защо в листинг файла не дава последователно инструкциите по нарастването на техните адреси, ами ми ги сортира по някакъв идиотски начин. Нали все пак ядрото ще следва потока от инструкции. Не знам дали се изразявам правилно, значи имам да речем 20 инструкции, започващи от адрес 0x0000_0000 и завърващи на адрес 0x0000_0014, нормално е както и да ги оптимизира в листинга да ми ги даде в техния естествен ред по адреси, а той ми листва на първи ред инструкция от адрес 0x0000_0000, след което на втори ред инструкцията от адрес 0x0000_0008, на трети ред от нам си кой друг адрес, и някъде по средата ми листва инструкцията от адрес 0x0000_0001, при положение, че няма никъде в тия 20 инструкции инструкция за преход. А аз бих искал в листинга да са ми така инструкциите: т.е. в техния естествен ред, както ще ги запише програматора във флаш паметта. Та казваш, няма опция, която да го накара да ми даде листинга в нормалния си вид ? Само при изключена оптимизация ги сортира по нормалния начин.
GCC на Microchip e 3.3.4 мисля.
_________________ Ето аз дишам, работя, живея и програми пиша тъй както умея, с проца под вежди се гледаме строго и боря се с него доколкото мога....
|
| Чет Апр 21, 2011 4:35 pm |
|
 |
|
woody
Ранг: Форумен бог
Регистриран на: Вто Юли 31, 2007 2:55 pm Мнения: 1792 Местоположение: София
|
При мен е Микрочепско 3.4.4, ама ги генерира едни "оптимизирани", та не съм сигурен дали не е от изтеклия evaluation срок.
Аз така или иначе бих тръгнал от:
http://www.codesourcery.com/sgpp/lite/m ... plate=lite
|
| Чет Апр 21, 2011 6:18 pm |
|
 |
|
miro_atc
Ранг: Форумен бог
Регистриран на: Нед Фев 26, 2006 6:52 pm Мнения: 11266 Местоположение: Добрич
|
Мда... 3.3 е ужасно стара версия. Не съм сигурен с коя почнах АРМ-те май беше 3.6 или 3.4, но със сигурност генерираше доста безсмислен код  Поне тогава като ги сравняваш с IAR на места беше 30-40% по-зле. Но после със всяка версия се подобряваше. На два пъти имаше генерални промени, последната революция е точно с 4.6.
Тъй де по отношение на "талаша" има надежда, че при смяна на версиите ще се изчисти, макар че част оптимизацията зависи и от таргета. Не знам дали МИПС се е развивал по същия начин като АРМ, но със сигурност голяма част от оптимизациите GCC ги прави на по-абстрактно ниво, тъй че подобрения ще има!
А пък за "разбъркването" не знам... май няма надежда  Има си го и при АРМ, аз затова дебъгвам с -O0 и сега имам ядове щото флаша ми изтъня та вече само малка част от проекта мога да пусна без оптимизации.
|
| Чет Апр 21, 2011 7:18 pm |
|
 |
|
¶
Ранг: Форумен бог
Регистриран на: Пет Фев 25, 2005 1:58 pm Мнения: 4585 Местоположение: US
|
Това го имам качено, както и Macragior GNU C/C++ for MIPS, проблема е, че PIC32 няма FPU unit, a тези версии си генерират
такива инструкции. Поне засега не съм копал какво трябва да им се подаде като MCU target параметър, така че да не ги генерират.
_________________ Ето аз дишам, работя, живея и програми пиша тъй както умея, с проца под вежди се гледаме строго и боря се с него доколкото мога....
|
| Чет Апр 21, 2011 7:31 pm |
|
 |
|
woody
Ранг: Форумен бог
Регистриран на: Вто Юли 31, 2007 2:55 pm Мнения: 1792 Местоположение: София
|
|
| Чет Апр 21, 2011 8:00 pm |
|
 |
|
miro_atc
Ранг: Форумен бог
Регистриран на: Нед Фев 26, 2006 6:52 pm Мнения: 11266 Местоположение: Добрич
|
може би -msoft-float
макар че по-правилно е да се сетне -march с правилната архитектура...
|
| Чет Апр 21, 2011 8:02 pm |
|
 |
|
¶
Ранг: Форумен бог
Регистриран на: Пет Фев 25, 2005 1:58 pm Мнения: 4585 Местоположение: US
|
Тцъ, не е това  , задал съм го, като разгледам листинга на MADD компилирано с Macragior/Sourcery си има floating point инструкции... И march=mips32r2 , каквото е уж ядрото на PIC32..., въпреки това горните две GCC версии генерират FPU инструкции...
Това изгълтах, за да мога да настроя Macragior/Sourcery GNU C/++ да компилира C++ код за PIC32, програмките са примерни, използвам header и library файловете на Microchip, преди това включвам един header в който съм дефинирал разни макроси, за да може да се използват Microchip файловете. Не съм се копал в дълбочина, но ще се занимая като имам време. Първо ще изпробвам дали с FPU инструкции ще заработи правилно програмата на PIC32 ядро  , може и да са спестили документация за наличие на FPU, което е малко вероятно, но все пак е възможно 
_________________ Ето аз дишам, работя, живея и програми пиша тъй както умея, с проца под вежди се гледаме строго и боря се с него доколкото мога....
|
| Чет Апр 21, 2011 10:09 pm |
|
 |
|
fan
Ранг: Почетен член
Регистриран на: Съб Окт 13, 2007 12:12 pm Мнения: 712
|
Ако ти се занимава, може да пробваш "свежак"-а на "клен" от electronix.ru.
Той е с GCC 4.6. Може да помогне...
mips mingw32
http://klen.org/Files/DevTools/kgp-mips ... 0110328.7z
п.с. Даже всъщност тази версия е 4.7 
|
| Чет Апр 21, 2011 10:42 pm |
|
 |
|
¶
Ранг: Форумен бог
Регистриран на: Пет Фев 25, 2005 1:58 pm Мнения: 4585 Местоположение: US
|
Интересно, Code Sourcery G++ Lite 4.4.1 не иска да компилира MADD инструкциите за MIPS, твърди:
error: impossible constraint in 'asm'
Същото казват Macraigor GNU C/C++ 4.4.3 и Klen's GNU C/C++ version 4.7.0.
Обаче Microchip GCC 3.4.4 я сдъвква правилно.
_________________ Ето аз дишам, работя, живея и програми пиша тъй както умея, с проца под вежди се гледаме строго и боря се с него доколкото мога....
|
| Нед Апр 24, 2011 4:06 pm |
|
 |
|
miro_atc
Ранг: Форумен бог
Регистриран на: Нед Фев 26, 2006 6:52 pm Мнения: 11266 Местоположение: Добрич
|
Аз боря един проблем с новото GCC (дебъгера нещо не може да намери дебъг информация за някои функции) та разглеждам опциите и случайно попаднах на някои промени в МИПС:
Това е за 4.4...
|
| Пон Апр 25, 2011 10:37 am |
|
|
Кой е на линия |
Потребители разглеждащи този форум: 0 регистрирани и 6 госта |
|
Вие не можете да пускате нови теми Вие не можете да отговаряте на теми Вие не можете да променяте собственото си мнение Вие не можете да изтривате собствените си мнения Вие не можете да прикачвате файл
|
|