View previous topic :: View next topic |
Author |
Message |
kda406
Joined: 17 Sep 2003 Posts: 97 Location: Atlanta, GA, USA
|
if vs Ternary vs Direct Assignment |
Posted: Tue Apr 30, 2019 9:16 am |
|
|
This is just a report, not a complaint or request. But if someone has a suggestion, I am open to other options too.
I have to test a bit in a UINT8 (aka short int or char) and save off the result into a BOOL for use elsewhere. I tried 3 approaches and what I found in the LST file was intriguing.
IF method uses 12 bytes of program memory:
Code: | if(gsPacket.iData[2] & 0x08) gLEDStatus.condensate = true; else gLEDStatus.condensate = false;
02148: BTFSS x73.3
0214A: BRA 2152
0214C: MOVLW 01
0214E: MOVWF xBC
02150: BRA 2154
02152: CLRF xBC |
But the "then" portion above only assigns a value to one single variable, so I can easily use...
Ternary method uses 12 bytes of program memory:
Code: | gLEDStatus.condensate = (gsPacket.iData[2] & 0x08) ? true : false;
02154: BTFSS x73.3
02156: BRA 215C
02158: MOVLW 01
0215A: BRA 215E
0215C: MOVLW 00
0215E: MOVWF xBC |
But the value I am assigning is only true or false, which appears redundant in the ternary operation. It seems simplest to use...
Direct Assignment method uses 14 bytes of program memory:
Code: | gLEDStatus.condensate = ((gsPacket.iData[2] & 0x08) != 0);
02160: MOVF x73,W
02162: ANDLW 08
02164: BNZ 216A
02166: MOVLW 00
02168: BRA 216C
0216A: MOVLW 01
0216C: MOVWF xBC |
You can see from the assembly that the three operations accomplish the same goal in three different ways. This is not unexpected. The most fascinating part to me was that the tightest C code produced the largest assembly code. I felt compelled to share this with the community.
-Kyle
Last edited by kda406 on Tue Apr 30, 2019 9:45 am; edited 1 time in total |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Apr 30, 2019 9:29 am |
|
|
How about this one ?
Code: |
..... gLEDStatus.condensate = bit_test(gsPacket.iData[2], 3);
00036: CLRF 05
00038: BTFSC 08.3
0003A: INCF 05,F
|
Test program:
Code: | #include <18F87K22.h>
#fuses NOWDT
#use delay(internal=4M)
#use rs232(UART1, baud=9600, errors)
struct
{
int8 condensate;
}gLEDStatus;
struct
{
int8 iData[10];
}gsPacket;
//==========================
void main()
{
gLEDStatus.condensate = bit_test(gsPacket.iData[2], 3);
while(TRUE);
} |
|
|
|
kda406
Joined: 17 Sep 2003 Posts: 97 Location: Atlanta, GA, USA
|
|
Posted: Tue Apr 30, 2019 9:44 am |
|
|
Sweet. I generally stick with portable code, but this is fantastic and needs to be included in the thread.
CCS bit_test() uses 6 bytes of program memory:
Code: | gLEDStatus.condensate = bit_test(gsPacket.iData[2],3);
0216E: CLRF xBC
02170: BTFSC x73.3
02172: INCF xBC,F |
Thanks PCM programmer for reminding me about this one. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19549
|
|
Posted: Tue Apr 30, 2019 10:36 am |
|
|
Generally, ternary operations are not optimised in CCS. They don't skip
evaluation of the 'false' route for example, so I'm not surprised that
there is no gain from using these.
However the key point about 'bit_test', is it takes advantage of the processors
instruction set. The PIC has a fixed location 'bit test' instruction. With a
fixed bit, this can be used instead of having to mask out the required bit
and test this. Much more efficient as you have seen.
If you want to be portable, then code a macro, that when compiled on
CCS, uses the bit_test operation, but otherwise generates the mask and
does the logical test this way. |
|
|
kda406
Joined: 17 Sep 2003 Posts: 97 Location: Atlanta, GA, USA
|
|
Posted: Tue Apr 30, 2019 12:02 pm |
|
|
Just for completeness, my tests were with V5.085 compiled for a PIC18F67K40.
Ttelmah you make several great points, and I agree completely on the use of macros for portability. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9245 Location: Greensville,Ontario
|
|
Posted: Tue Apr 30, 2019 5:08 pm |
|
|
hmm...
this..
wonder why CCS didn't use the BSF instruction ? After all they're testing a bit...seems to me logical to set a bit ?? No saving in time, both are 1 cycle.
just curious...
Jay |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19549
|
|
Posted: Wed May 01, 2019 1:21 am |
|
|
I wondered the same. I suspect the reason is so that the status bit for
non zero will be set. Hence if the result is used in the same C instruction
in a test (so where you do an assignment inside a test), this ensures the
status is set without having to test again. BSF, does not update the
status, while INCF does. |
|
|
pmuldoon
Joined: 26 Sep 2003 Posts: 218 Location: Northern Indiana
|
|
Posted: Tue Jun 11, 2019 5:26 am |
|
|
Could it be because the operand is an int8 and not an int1?
Just taking a short break from work and stumbled across this cool thread. |
|
|
|