SDCC : pic16/pic14 3.0.4 #6726 (Aug 9 2011) (Linux)
There is problem in logical function where i use bit variables .
Here is the two tipical syntax, first whithout else:
if ( condition ) {
expr_set1;
}
And with else:
if ( condition ) {
expr_set1;
}
else {
expr_set2;
}
If I use "if" with "else" the compiled code is correct. If I don't use "else" the compiled code doesn't follow the original logic.
I attached an example which will show clearly the differece.
I wanted to make logical OR function but this compiled code doesen't follow it:
.line 39; "logical_test.c" if( B0 && B2 )
BTFSS _b,0
GOTO _00118_DS_
BTFSS _b,2
.line 41; "logical_test.c" if( !B1 || !B3 ) B4 = 1;
GOTO _00118_DS_
BTFSC _b,1
BTFSS _b,3
BSF _b,4
_00118_DS_
And the well working result with "else":
.line 31; "logical_test.c" if( B0 && B2 )
BTFSS _b,0
GOTO _00109_DS_
BTFSS _b,2
GOTO _00109_DS_
BTFSS _b,1
GOTO _00105_DS_
BTFSC _b,3
GOTO _00110_DS_
_00105_DS_
BANKSEL _b
BSF _b,4
GOTO _00110_DS_
_00109_DS_
.line 35; "logical_test.c" else B4 = 0;
BANKSEL _b
BCF _b,4
_00110_DS_
.line 38; "logical_test.c" B4 = 0;
BANKSEL _b
BCF _b,4
Sorry for confusion. I wasn't enough attentive and I complained about a well working code. So here is the problematic code:
.line 23; "logical_test.c" b.common_byte = 0x0B;
MOVLW 0x0b
BANKSEL _b
MOVWF (_b + 0)
.line 25; "logical_test.c" b.B4 = 0;
BCF _b,4
.line 26; "logical_test.c" if( b.B0 && b.B1 )
BTFSS _b,0
GOTO _00001_DS_
BTFSS _b,1
.line 28; "logical_test.c" if( !b.B2 || !b.B3 ) c.B0 = 1;
GOTO _00001_DS_
BTFSC _b,2
BTFSC _b,3
GOTO _00001_DS_
BANKSEL _c
BSF _c,0
_00001_DS_
RETURN
And I attached the source of it. I tested it by GPsim whith the following inputs in "b":
0x03 -> result: c = 0 ( it should be 1 )
0x07 -> result: c = 1
0x0B -> result: c = 0 ( it should be 1 )
0x0F -> result: c = 1 ( it should be 0 )
If I uncomment the "else NOP" line I get the correct result for these inputs.
I made the simpliest test for showing the problem, which consist one if() statement. This code show, how can avoid this this type of bugs with an empty inline assembly definition. Using it in the else branch eliminate the problem.
The file name is: logical_test_small.c
simpliest example
Short story: This is a bug in the BANKSEL insertion algorithm, which is
triggered in conjunction with peephole optimizations.
As a workaround, use --no-peep for now.
Long story:
if (b.B0 || b.B1) c.B0 = 1;
is correctly compiled into
BTFSC b,0
GOTO Ltrue
BTFSS b,1
GOTO Lfalse
Ltrue: BSF c,0
Lfalse:
This is twice optimized by peephole rules, first to
BTFSC b,0
GOTO Ltrue
BTFSC b,1
Ltrue: BSF c,0
Lfalse:
and then to
BTFSS b,0
BTFSC b,1
Ltrue: BSF c,0
Lfalse:
All of this is perfectly fine. Now we need to insert a BANKSEL instruction for
accessing c.
BTFSC b,1
BSF c,0
is transformed into
BTFSS b,1
GOTO Lskip
BANKSEL c
BSF c,0
Lskip:
which is correct if (and only if) the fragment is not preceded by another SKIP
instruction. Unfortunately, the peephole optimizations created such a series
of SKIP instructions ...
BTFSS b,0
BTFSC b,1
Ltrue: BSF c,0
Lfalse:
should be transformed first into
BTFSS b,0 /* FIXME */
BTFSS b,1
GOTO Lskip
BANKSEL c
BSF c,0
Lskip:
and then further into
BTFSC b,0
GOTO Ldo
BTFSS b,1
GOTO Lskip
Ldo: BANKSEL c
BSF c,0
Lskip:
because the first SKIP instruction must now skip 2 instructions.
Of course, in this case, the resulting code fragment is exactly what had been
generated in the first place and all the peephole optimizations have been in
vain. Generally, however, the optimizations are both useful.
An alternative solution, inserting BANKSELs before the peephole optimizations,
would yield correct results (as code generation never (?) produces chained
SKIPs), but also reduces the effectiveness of the peephole optimizations.
I'll report back once BANKSEL insertion has been fixed for the
multiple-skip-case.
Thanks for the explanation. That is an additional information for me to handle this situation.