Jump to content
43oh

Simple BIS/BIC macros for GCC


Recommended Posts

I know about the BIS/BIC macros for manipulating the SR register, but I didn't see anything for general purpose use with memory variables/SFRs and such so I decided to create these:

 

#ifdef __GNUC__
#define BIC(sfr, val) asm("bic %[src], %[dest]" : [dest] "=m" (sfr) : [src] "i" (val))
#define BIS(sfr, val) asm("bis %[src], %[dest]" : [dest] "=m" (sfr) : [src] "i" (val))
#define BIC_B(sfr, val) asm("bic.b %[src], %[dest]" : [dest] "=m" (sfr) : [src] "i" (val))
#define BIS_B(sfr, val) asm("bis.b %[src], %[dest]" : [dest] "=m" (sfr) : [src] "i" (val))
#else
#define BIC(sfr, val) sfr &= ~val
#define BIS(sfr, val) sfr |= val
#define BIC_B(sfr, val) sfr &= ~val
#define BIS_B(sfr, val) sfr |= val
#endif

 

Non-GCC compilers will simply use the conventional syntax for it. If someone could supply comparable inline-ASM code for IAR and CCS that would be cool! It seems to have shaved off a little size from my code, maybe 40-50 bytes or so for about 50 uses of that operation in my current project. (On a G2231 running close to 2K flash use, everything counts!)

Link to post
Share on other sites

Weird, I always use -Os with my compiles.

 

Looks like the code difference is 2 bytes saved in the BIC.B vs AND.B when clearing bits.

 

Using my BIS/BIC macros, a P1_IRQ ISR:

 

C:
#pragma vector = PORT1_VECTOR
__interrupt void P1_IRQ (void){
       if(P1IFG & nrfIRQpin){
               __bic_SR_register_on_exit(LPM4_bits);
               BIS_B(rf_irq, 0x80);
               //rf_irq |= 0x80;
               BIC_B(P1IFG, nrfIRQpin);
               //P1IFG &= ~nrfIRQpin;
       }
}

Disassembled machine code in mspdebug:
P1_IRQ:
   0fd5e: 0f 12                     PUSH    R15
   0fd60: 5f 42 23 00               MOV.B   &0x0023, R15
   0fd64: 1f f3                     AND     #0x0001, R15
   0fd66: 08 24                     JZ      P1_IRQ+0x1a
   0fd68: b1 c0 f0 00 02 00         BIC     #0x00f0, 0x0002(SP)
   0fd6e: f2 d0 80 00 0a 02         BIS.B   #0x0080, &rf_irq
   0fd74: d2 c3 23 00               BIC.B   #0x0001, &0x0023    <-- NOTE SIZE, 4 bytes
   0fd78: 3f 41                     POP     R15
   0fd7a: 00 13                     RETI    

 

Using |= and &= instead:

 

C:
#pragma vector = PORT1_VECTOR
__interrupt void P1_IRQ (void){
       if(P1IFG & nrfIRQpin){
               __bic_SR_register_on_exit(LPM4_bits);
               //BIS_B(rf_irq, 0x80);
               rf_irq |= 0x80;
               //BIC_B(P1IFG, nrfIRQpin);
               P1IFG &= ~nrfIRQpin;
       }
}

Disassembled machine code in mspdebug:
P1_IRQ:
   0fd5e: 0f 12                     PUSH    R15
   0fd60: 5f 42 23 00               MOV.B   &0x0023, R15
   0fd64: 1f f3                     AND     #0x0001, R15
   0fd66: 09 24                     JZ      P1_IRQ+0x1c
   0fd68: b1 c0 f0 00 02 00         BIC     #0x00f0, 0x0002(SP)
   0fd6e: f2 d0 80 ff 0a 02         BIS.B   #0x0080, &rf_irq
   0fd74: f2 f0 fe ff 23 00         AND.B   #0x00fe, &0x0023    <-- NOTE SIZE, 6 bytes
   0fd7a: 3f 41                     POP     R15
   0fd7c: 00 13                     RETI    

Link to post
Share on other sites

I'm thinking the BIC is using one of the constant generators, while the AND.B is not. Page 58 in the user's guide mentions how immediate mode can be 2 or 3 words depending on whether CG1/CG2 can be used.

 

Another example with a more complex operand for the BIC yields 3 words:

USI_TXRX:
   0fd50: f2 c0 11 00 79 00         BIC.B   #0x0011, &0x0079
   0fd56: b1 c0 10 00 00 00         BIC     #0x0010, 0x0000(SP)
   0fd5c: 00 13                     RETI    

 

Ok, so a very minor (nearly insignificant) optimization.

Link to post
Share on other sites
I'm thinking the BIC is using one of the constant generators, while the AND.B is not.

 

Yes; gcc is not detecting that AND #-2 can be converted to BIC 1. It does detect and use BIC for AND of inverted constant in other cases. This qualifies as a missed optimization bug. If you report it on the mspgcc tracker I'll add it to the queue to look at for a future release.

 

You may find that using inline assembly introduces other optimization problems because gcc can't tell what you're doing in those instructions. It will sometimes have to spill a register to memory to preserve it, where that would be avoided if the operation were left in a form where gcc understands the effect of the operation.

Link to post
Share on other sites

I've added a peephole optimization for the case of AND #X, DST into BIC #-X, DST where -X can be expressed by the constant generator. The fix will be in mspgcc version following 20120627, and will be out sometime next week. (I won't add the fix to the LTS release series as it's not actually wrong, just sub-optimal.)

 

Thanks for the report. If you encounter other cases where the obvious code in C doesn't do the right thing, please create new tracker tickets so those can be fixed too.

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...