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