Я работаю над встроенным проектом и пытаюсь добавить больше структуры в некоторый код, который использует макросы для оптимизации доступа к регистрам для USART. Я хотел бы организовать препроцессор # define'd адреса регистров в структуры const. Если я определяю структуры как составные литералы в макросе и передаю их встроенным функциям, gcc достаточно умен, чтобы обойти указатель в сгенерированной сборке и жестко закодировать значения элементов структуры непосредственно в коде. E.g.:
С1:
struct uart {
volatile uint8_t * ucsra, * ucsrb, *ucsrc, * udr;
volitile uint16_t * ubrr;
};
#define M_UARTX(X) \
( (struct uart) { \
.ucsra = &UCSR##X##A, \
.ucsrb = &UCSR##X##B, \
.ucsrc = &UCSR##X##C, \
.ubrr = &UBRR##X, \
.udr = &UDR##X, \
} )
void inlined_func(const struct uart * p, other_args...) {
...
(*p->ucsra) = 0;
(*p->ucsrb) = 0;
(*p->ucsrc) = 0;
}
...
int main(){
...
inlined_func(&M_UART(0), other_parms...);
...
}
Здесь UCSR0A, UCSR0B, & c определяются как регистры uart как l-значения, например
#define UCSR0A (*(uint8_t*)0xFFFF)
gcc смог полностью исключить литерал структуры, и все назначения, подобные показанным в inlined_func (), записываются непосредственно в адрес регистра, без необходимости считывать адрес регистра в регистр компьютера и без косвенной адресации. :
A1:
movb $0, UCSR0A
movb $0, UCSR0B
movb $0, UCSR0C
Это записывает значения непосредственно в регистры USART, без необходимости загружать адреса в машинный регистр, и поэтому вообще не нужно генерировать литерал struct в объектном файле. Литерал структуры становится структурой времени компиляции без затрат в сгенерированном коде для абстракции.
Я хотел избавиться от использования макроса и попытался использовать статическую константу struct, определенную в заголовке:
С2:
#define M_UART0 M_UARTX(0)
#define M_UART1 M_UARTX(1)
static const struct uart * const uart[2] = { &M_UART0, &M_UART1 };
....
int main(){
...
inlined_func(uart[0], other_parms...);
...
}
Однако gcc не может полностью удалить структуру здесь:
A2
movl __compound_literal.0, %eax
movb $0, (%eax)
movl __compound_literal.0+4, %eax
movb $0, (%eax)
movl __compound_literal.0+8, %eax
movb $0, (%eax)
Это загружает адреса регистров в машинный регистр и использует косвенную адресацию для записи в регистр. Кто-нибудь знает в любом случае, я могу убедить gcc сгенерировать ассемблерный код A1 для кода C2 C? Я пробовал различные варианты использования модификатора __restrict, но безрезультатно.