SourceForge has been redesigned. Learn more.
Close

#1735 Near pointers broken

closed-fixed
5
2013-05-25
2011-01-01
No

It appears that near pointers are broken after snap 5559.

$ cat test3.c
#include <stdio.h>

typedef unsigned char uint8;
typedef unsigned int uint16;
#define REGS_IN_TCB 7

typedef uint8 tid;

typedef __pdata struct tcb_st { // [offset:size]
__idata uint8 *sp; // stack pointer [0:1]
uint8 b; // B register [1:1]
uint8 dpl, dph; // DPTR register [2:2]
uint8 dps; // DPS register [4:1]
__idata uint8 *bp; // frame register [5:1]
uint8 r[REGS_IN_TCB]; // registers [6:7]
tid id; // task ID [13:1]
#define MAX_TASKS 5
uint8 state; // task state [14:1]
uint8 priority; // task priority [15:1]
uint8 event; // event number to wait for [16:1]
uint16 timer; // timer variable [17:2]
__pdata struct tcb_st *next; // next tcb in queue [19:1]
__xdata uint8 *stack; // stack in xdata [20:2]
uint8 stack_size; // stack size [22:1]

} tcb_type;

typedef __xdata struct msg_struct {
uint8 id; // message id [0:1]
__xdata void *ptr; // pointer to message [1:2]
__xdata struct msg_struct *next; // next message in the queue [3:
2]
} msg_type;

msg_type *msg_queue[MAX_TASKS];
msg_type *msg_queue_end[MAX_TASKS];

volatile tcb_type * __data ready_queue;

main()
{
uint8 a;

ready_queue = NULL;

if (ready_queue == NULL) {
a = 0;
} else {
a = 1;
}
return 0;
}

On 2.9.0 all is well:

$ "/cygdrive/c/program files/SDCC2_9_0"/bin/sdcc -v
SDCC : mcs51/gbz80/z80/avr/ds390/pic16/pic14/TININative/xa51/ds400/hc08 2.9.0 #5
416 (Mar 22 2009) (MINGW32)

$ "/cygdrive/c/program files/SDCC2_9_0"/bin/sdcc test3.c
test3.c:47: warning 110: conditional flow changed by optimizer: so said EVELYN t
he modified DOG

$ cat test3.rst
...
141 ; test3.c:45: ready_queue = NULL;
0064 75 1C 00 142 mov _ready_queue,#0x00
143 ; test3.c:47: if (ready_queue == NULL) {
0067 E5 1C 144 mov a,_ready_queue
0069 70 04 145 jnz 00107$
006B 74 01 146 mov a,#0x01
006D 80 01 147 sjmp 00108$
006F 148 00107$:
006F E4 149 clr a
0070 150 00108$:
151 ; test3.c:52: return 0;
0070 90 00 00 152 mov dptr,#0x0000
0073 22 153 ret

on snap 5560 and later its broken in that the "pointer" will never be NULL:

$ "/cygdrive/c/program files/SDCC3_0_1"/bin/sdcc -v
SDCC : mcs51/gbz80/z80/ds390/pic16/pic14/TININative/ds400/hc08 3.0.1 #6066 (Nov
26 2010) (MINGW32)

$ "/cygdrive/c/program files/SDCC3_0_1"/bin/sdcc test3.c
test3.c:47: warning 110: conditional flow changed by optimizer: so said EVELYN t
he modified DOG

$ cat test3.rst
...
143 ; test3.c:45: ready_queue = NULL;
0064 75 1C 00 144 mov _ready_queue,#0x00
145 ; test3.c:47: if (ready_queue == NULL) {
0067 7A 00 146 mov r2,#0x00
0069 7B 00 147 mov r3,#0x00
006B 7C 60 148 mov r4,#0x60
006D E4 149 clr a
006E BA 00 07 150 cjne r2,#0x00,00107$
0071 BB 00 04 151 cjne r3,#0x00,00107$
0074 BC 00 01 152 cjne r4,#0x00,00107$
0077 04 153 inc a
0078 154 00107$:
155 ; test3.c:52: return 0;
0078 90 00 00 156 mov dptr,#0x0000
007B 22 157 ret

The code is much larger (which may be necessary for other reasons, if undesirable)
but more importantly is wrong in that with r4 set to 0x60 a NULL pointer will never be
recognized.

Peter Van Epp

Discussion

  • Maarten Brock

    Maarten Brock - 2011-01-01

    What's happening here is that you compare a pdata-pointer to a generic-pointer. So the compiler upcasts the pdata-pointer to a generic pointer and adds the memory type indicator 0x60. It has to compare all bytes as otherwise code-pointer 0x0001 would equal pdata-pointer 0x01.

    To solve this the compiler would have to generate code that checks either value to be zero (null-pointer) and then ignore the memory type indicator. For constants like NULL this can be done at compile time.

    In the meantime I think you're better off comparing against (__pdata void *)0

    #define PNULL (__pdata void *)0
    if (ready_queue == PNULL)

    Happy New Year,
    Maarten

     
  • Peter  Van Epp

    Peter Van Epp - 2011-01-02

    Thanks! The addition of PNULL indeed fixes the problem for me with the
    added advantage of reducing the code size back to what it was. Since a cast
    inline does the same:

    1232 ; m7100os.c:356: if (ready_queue == (__pdata void *) NULL) {
    07D3 E4 1233 clr a
    07D4 B5 12 04 1234 cjne a,_ready_queue,00102$
    1235 ; m7100os.c:359: DEBUG1 = 0;
    07D7 C2 B7 1236 clr _P3_7

    that set me to thinking (always a dangerous pastime!) if it is permitted (its obviously possible) at compile time in the case of a literal (which needs to be a generic pointer) at least to insert the cast to the type of the variable rather than cast the variable to a generic pointer. In this case (and I expect most cases) there is an advantage in code size which would make it a desirable optimization.

    Peter Van Epp

     
  • Maarten Brock

    Maarten Brock - 2011-08-12
    • milestone: --> fixed
    • assigned_to: nobody --> maartenbrock
    • status: open --> closed-fixed
     
  • Maarten Brock

    Maarten Brock - 2011-08-12

    It is not possible to cast a literal generic pointer to the type of the other operand unless it has value 0 which always equals the NULL pointer. SDCC 3.0.4 #6731 now uses this optimization and changes p==NULL to !p internally. Other generic pointer comparisons are now handled by a library function __gptr_cmp which considers all null pointers equal.

     
  • Peter  Van Epp

    Peter Van Epp - 2011-09-12

    Maarten:
    Once I managed to start compiling with a current snap (I have several versions around and install put the latest in an unexpected place, thank god for the -v option :-)) my problem code now compiles without the cast. Thanks!

    Peter Van Epp

     

Log in to post a comment.