From: Meindert Sprang on
Unbelievable.....

I'm playing around with the Microchip C18 compiler after a hair-splitting
experience with CCS. Apparently the optimizer of C18 is not that good. For
instance: LATF = addr >> 16; where addr is an uint32, is compiled into a
loop where 4 registers really get shifted 16 times in a loop. Any decent
compiler should recognise that a shift by 16, stored to an 8 bit port could
easily be done by simply accessing the 3rd byte.... sheesh....

Meindert


From: D Yuniskis on
Hi Meindert,

Meindert Sprang wrote:
> Unbelievable.....
>
> I'm playing around with the Microchip C18 compiler after a hair-splitting
> experience with CCS. Apparently the optimizer of C18 is not that good. For
> instance: LATF = addr >> 16; where addr is an uint32, is compiled into a
> loop where 4 registers really get shifted 16 times in a loop. Any decent
> compiler should recognise that a shift by 16, stored to an 8 bit port could
> easily be done by simply accessing the 3rd byte.... sheesh....

Is LATF *defined* as a uint8_t? (i.e., does the compiler *know* it
can discard all but the lowest 8 bits?)

Is uuint32_t *really* unsigned (and not a cheap hack to "long int")?
I.e., can the compiler be confused (by the definition) to thinking
it is signed and opting for a sign-preserving shift?

How about:

uint8_t pointer;

pointer = (uint8_t *) &addr;
LATF = pointer[2];

Clumsy, admittedly, but perhaps more obvious what's going on?
(I would have added that this would be easy for an optimizer
to reduce to an "addressing operation" but I also would have
expected your shift to be recognized as an easy optimization!)
From: D Yuniskis on
D Yuniskis wrote:
> Hi Meindert,
>
> Meindert Sprang wrote:
>> Unbelievable.....
>>
>> I'm playing around with the Microchip C18 compiler after a hair-splitting
>> experience with CCS. Apparently the optimizer of C18 is not that good.
>> For
>> instance: LATF = addr >> 16; where addr is an uint32, is compiled into a
>> loop where 4 registers really get shifted 16 times in a loop. Any decent
>> compiler should recognise that a shift by 16, stored to an 8 bit port
>> could
>> easily be done by simply accessing the 3rd byte.... sheesh....
>
> Is LATF *defined* as a uint8_t? (i.e., does the compiler *know* it
> can discard all but the lowest 8 bits?)
>
> Is uuint32_t *really* unsigned (and not a cheap hack to "long int")?
> I.e., can the compiler be confused (by the definition) to thinking
> it is signed and opting for a sign-preserving shift?
>
> How about:
>
> uint8_t pointer;

uint8_t *pointer;

(sorry, too early in the morning to be writing code :> )

> pointer = (uint8_t *) &addr;
> LATF = pointer[2];
>
> Clumsy, admittedly, but perhaps more obvious what's going on?
> (I would have added that this would be easy for an optimizer
> to reduce to an "addressing operation" but I also would have
> expected your shift to be recognized as an easy optimization!)
From: Joe Chisolm on
On Mon, 07 Jun 2010 11:17:34 +0200, Meindert Sprang wrote:

> Unbelievable.....
>
> I'm playing around with the Microchip C18 compiler after a
> hair-splitting experience with CCS. Apparently the optimizer of C18 is
> not that good. For instance: LATF = addr >> 16; where addr is an
> uint32, is compiled into a loop where 4 registers really get shifted 16
> times in a loop. Any decent compiler should recognise that a shift by
> 16, stored to an 8 bit port could easily be done by simply accessing the
> 3rd byte.... sheesh....
>
> Meindert

From the Microchip supplied USB code

POINTER addr;

LATF = addr.bHigh; //simple and to the point


If addr is static this will probably compile to a simple movff. If addr
is on the stack it gets a little more complicated.


#ifndef TYPEDEFS_H
#define TYPEDEFS_H

typedef unsigned char byte; // 8-bit
typedef unsigned int word; // 16-bit
typedef unsigned long dword; // 32-bit

typedef union _BYTE
{
byte _byte;
struct
{
unsigned b0:1;
unsigned b1:1;
unsigned b2:1;
unsigned b3:1;
unsigned b4:1;
unsigned b5:1;
unsigned b6:1;
unsigned b7:1;
};
} BYTE;

typedef union _WORD
{
word _word;
struct
{
byte byte0;
byte byte1;
};
struct
{
BYTE Byte0;
BYTE Byte1;
};
struct
{
BYTE LowB;
BYTE HighB;
};
struct
{
byte v[2];
};
} WORD;
#define LSB(a) ((a).v[0])
#define MSB(a) ((a).v[1])

typedef union _DWORD
{
dword _dword;
struct
{
byte byte0;
byte byte1;
byte byte2;
byte byte3;
};
struct
{
word word0;
word word1;
};
struct
{
BYTE Byte0;
BYTE Byte1;
BYTE Byte2;
BYTE Byte3;
};
struct
{
WORD Word0;
WORD Word1;
};
struct
{
byte v[4];
};
} DWORD;
#define LOWER_LSB(a) ((a).v[0])
#define LOWER_MSB(a) ((a).v[1])
#define UPPER_LSB(a) ((a).v[2])
#define UPPER_MSB(a) ((a).v[3])

typedef void(*pFunc)(void);

typedef union _POINTER
{
struct
{
byte bLow;
byte bHigh;
};
word _word; // bLow & bHigh
byte* bRam; // Ram byte pointer: 2 bytes pointer pointing
// to 1 byte of data
word* wRam; // Ram word poitner: 2 bytes poitner pointing
// to 2 bytes of data

rom byte* bRom; // Size depends on compiler setting
rom word* wRom;
} POINTER;

typedef enum _BOOL { FALSE = 0, TRUE } BOOL;

#define OK TRUE
#define FAIL FALSE

#endif //TYPEDEFS_H

--
Joe Chisolm
Marble Falls, Tx.
From: George Neuner on
On Mon, 7 Jun 2010 11:17:34 +0200, "Meindert Sprang"
<ms(a)NOJUNKcustomORSPAMware.nl> wrote:

>Unbelievable.....
>
>I'm playing around with the Microchip C18 compiler after a hair-splitting
>experience with CCS. Apparently the optimizer of C18 is not that good. For
>instance: LATF = addr >> 16; where addr is an uint32, is compiled into a
>loop where 4 registers really get shifted 16 times in a loop. Any decent
>compiler should recognise that a shift by 16, stored to an 8 bit port could
>easily be done by simply accessing the 3rd byte.... sheesh....
>
>Meindert

You're asking a lot.

I've been programming since 1977 and I have never seen any compiler
turn a long word shift (and/or mask) into a corresponding short word
or byte access. Every compiler I have ever worked with would perform
the shift.

That said, something is wrong if it takes 4 registers. I don't know
the PIC18, but I never encountered any chip that required more than 2
registers to shift a value. Many chips have only a 1-bit shifter and
require a loop to do larger shifts - but many such chips microcode the
shift loop so the programmer sees only a simple instruction. But,
occasionally, you do run into oddballs that need large shifts spelled
out.

Most likely you're somehow reading the (dis)assembly incorrectly: 4
temporaries that are really mapped into the same register. If the
compiler (or chip) really does need 4 registers to do a shift, then
it's a piece of sh*t.

George