Bitove polia a optimalizacia kody Was: STM32F051K6U7 ma USART2 ?

Miroslav Mraz mraz na seznam.cz
Pondělí Březen 16 15:15:19 CET 2015


Tak jsem chvíli zkoumal a přišel jsem na 2 podmínky, aby se to chovalo 
rozumně:

/* 32. bitový přístup - příklad. 16.bit přístup s uint16_t
  * bude taky fungovat, když se vyhodí položka xbu.un */
typedef uint32_t bit_type;

union xbu {
   struct {
     bit_type b1:1;
     bit_type b2:6;
     bit_type b3:1;
     bit_type b4:1;
     bit_type b5:6;
     bit_type b6:1;
     bit_type un:16;	/* 1. nutno zarovnat na 32.bit
     Pokud není zarovnáno, může se to chovat neočekávaně. */
   } b;
   bit_type w;
};
/* 2. musí být volatile, což je u registrů běžné. Pokud tomu
  * tak není, optimalizace může udělat i bytový přístup. Což zase
  * tak moc divné není. Ale napoprvé mě to trochu zmátlo. */
static volatile xbu b;
/* Zde je volatile použito jen kvůli tomu, aby to optimalizace nevyhodila
  * z výsledného elf a objdump umožnil podívat se na disassemblovaný kód. */
volatile void test1 (void) {
   b.b.b1=1;	/* Zase tak překvapivé to není. Překladači říkáme,
   že má nastavit 0.bit na 1, což on provede úplně stejně jako b.w |= 1 */
   b.b.b2=1;	/* a protože b je volatilní, zde opakuje ldr, str,
   to, že to od něj nechceme mu musíme nějak sdělit, viz dále */
}
/* Ruční optimalizace - pokud se nastavuje a nuluje víc položek
  * je to dokonce efektivnější než b.w &= ~X, b.w |= Y. Zas tak moc 
psaní navíc to není */
volatile void test2 (void) {
   register xbu t;	/* Pokud je ta struktura nevolatilní   */
   t.w = b.w;		/* pak se zde provede ldr,             */
   t.b.b1 = 1;		/* překladač nějak spojí tuto          */
   t.b.b5 = 1;		/* a tuto instrukci (a případné další) */
   b.w = t.w;		/* nakonec to uloží str                */
}
/* Testováno na gcc version 4.9.3 20141119 a clang 3.5, opt. -Os
  * Obojí se chová podobně (z hlediska ldr, str), obě svrchu uvedené
  * podmínky musí být splněny. Vnitřek - to vlastní nastavování bitů
  * se dost různí, těžko říct co je lepší. Ale obojí funguje.
  */

   b.w = 0xFFFF0000U;
   test1();
   test2();
/* Výsledek :
debug: > p/x b
$1 = {b = {b1 = 0x1, b2 = 0x1, b3 = 0x0, b4 = 0x0, b5 = 0x1, b6 = 0x0,
     un = 0xffff}, w = 0xffff0203}
*/

Vypadá to docela použitelně, ale chtělo by to otestovat i jinými překladači.

Mrazík




Další informace o konferenci Hw-list