我正在编写一个 Linux 内核驱动程序(用于 ARM),并且在一个 irq 处理程序中我需要检查中断位。
bit
0/16 End point 0 In/Out interrupt
(very likely, while In is more likely)
1/17 End point 1 In/Out interrupt
...
15/31 End point 15 In/Out interrupt
请注意,一次可以设置多个位。
所以这是代码:
int i;
u32 intr = read_interrupt_register();
/* ep0 IN */
if(likely(intr & (1 << 0))){
handle_ep0_in();
}
/* ep0 OUT */
if(likely(intr & (1 << 16))){
handle_ep0_out();
}
for(i=1;i<16;++i){
if(unlikely(intr & (1 << i))){
handle_ep_in(i);
}
if(unlikely(intr & (1 << (i + 16)))){
handle_ep_out(i);
}
}
(1 << 0)
并且(1 << 16)
会在编译时计算,但是(1 << i)
不会(1 << (i + 16))
。循环中也会有积分比较和加法。
因为它是一个 irq 处理程序,所以应该在最短的时间内完成工作。这让我想我是否需要对其进行一些优化。
可能的方法?
1.拆分循环,好像没什么区别...
/* ep0 IN */
if(likely(intr & (1 << 0))){
handle_ep0_in();
}
/* ep0 OUT */
if(likely(intr & (1 << 16))){
handle_ep0_out();
}
for(i=1;i<16;++i){
if(unlikely(intr & (1 << i))){
handle_ep_in(i);
}
}
for(i=17;i<32;++i){
if(unlikely(intr & (1 << i))){
handle_ep_out(i - 16);
}
}
2.移位intr
而不是要比较的值?
/* ep0 IN */
if(likely(intr & (1 << 0))){
handle_ep0_in();
}
/* ep0 OUT */
if(likely(intr & (1 << 16))){
handle_ep0_out();
}
for(i=1;i<16;++i){
intr >>= 1;
if(unlikely(intr & 1)){
handle_ep_in(i);
}
}
intr >>= 1;
for(i=1;i<16;++i){
intr >>= 1;
if(unlikely(intr & 1)){
handle_ep_out(i);
}
}
3.完全展开循环(未显示)。这会使代码有点混乱。
4.还有其他更好的方法吗?
5.还是编译器实际上会生成最优化的方式?
编辑:我正在寻找一种方法来告诉 gcc 编译器展开该特定循环,但根据我的搜索似乎不可能......