我正在编写一个针对ARM的Linux内核驱动程序,并且在中断处理程序中需要检查中断位。
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))
则无法。此外,在循环中会有整数比较和加法。
由于这是一个中断处理程序,必须在最短的时间内完成工作。这让我想到是否需要稍微优化一下它。
可能的方法?
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编译器展开特定循环的方法,但根据我的搜索似乎不可能...