Ulrich Weigand schrieb:
Georg-Johann Lay wrote:

Ulrich Weigand wrote:

This is pretty much working as expected.  "pallo" is a string literal
which (always) resides in the default address space.  According to the
named address space specification (TR 18037) there are no string literals
in non-default address spaces ...

The intension of TR 18037 to supply "Extension to Support Embedded Systems"
and these are systems where every byte counts -- and it counts *where* the
byte will be placed.

Basically named AS provide something like target specific qualifiers, and
if GCC, maybe under the umbrella of GNU-C, would actually implement a feature
like target specific qualifiers, that would be a great gain and much more
appreciated than -- users will perceive it that way -- being more catholic
than the pope ;-)

The problem with all language extensions is that you really need to be careful
that the new feature you want to add is fully specified, in all its potential
interactions with the rest of the (existing) language features.  If you don't,
some of those ambiguities are certain to be causing you problems later on --
in fact, that's just what has happened time and again with GCC extensions
that were added early on ...  This is why these days, extensions usually are
accepted only if they *are* fully specified (which usually means providing
a "diff" to the C standard text that would add the feature to the standard).

This is a non-trivial task.  One of the reasons why we decided to follow the
TR 18037 spec when implementing the __ea extension for SPU is that this task
had already been done for us.  If you want to deviate from that existing spec,
you're back to doing this work yourself.


For example, you can have any combination of qualifiers like const, restrict
or volatile, but it is not possible for named AS.  That's clear as long as
named AS is as strict as TR 18037.  However, users want features to write
down their code an a comfortable, type-safe way and not as it is at the moment,
i.e. by means of dreaded inline assembler macros (for my specific case).

A named AS qualifier *can* be combined with other qualifiers like const.
It cannot be combined with *other* named AS qualifiers, because that doesn't
make sense in the semantics underlying the address space concept of TR 18037.
What would you expect a combination of two AS qualifiers to mean?

Not two AS qualifiers, but two or more qualifiers, some of which might be target specific. You cannot use AS qualifiers and "abuse" them to implement a feature like target specific qualifiers.

The assignment above would therefore need to convert a pointer to the
string literal in the default space to a pointer to the __pgm address
space.  This might be impossible (depending on whether __pgm encloses
the generic space), and even if it is possible, it is not guaranteed
that the conversion can be done as a constant expression at compile time.

The backend can tell. It likes to implement features to help users.
It knows about the semantic and if it's legal or not.

And even if it's all strict under TR 18037, the resulting error messages
are *really* confusing to users because to them, a string literal's address
is known.

It would be possible to the extend named AS implementation to allow AS pointer
conversions in initializers in those cases where the back-end knows this can
be done at load time.  (Since this is all implementation-defined anyway, it
would cause no issues with the standard.  We simply didn't do it because on
the SPU, it is not easily possible.)

Of course, that still wouldn't place the string literal into the non-generic
address space, it just would convert its address.

What I'd do to get a string placed into the __pgm space is to explicitly
initialize an *array* in __pgm space, e.g. like so:

const __pgm char pallo[] = "pallo";

This is defined to work according to TR 18037, and it does actually
work for me on spu-elf.

Ya, but it different to the line above.

Sure, because it allocates only the string data, and not in addition a
pointer to it as your code did ...


Was just starting with the work and
it worked some time ago, so I wondered.

I think some time in the past, there was a bug where initalizers like in
you original line were silently accepted but then incorrect code was
generated (i.e. the pointer would just be initialized to an address in
the generic address space, without any conversion).

And I must admit I am not familiar
will all the dreaded restriction TR 18037 imposes to render it less functional 
:-(

It's not a restriction so much, it's simply that TR 18037 does not say anything
about string literals at all, so they keep working as they do in standard C.

Take the following bit more elaborate example where you want to describe a menu:

typedef struct
{
    int id;
    const char * labels[];
} menu1_t;

const menu1_t menu1  =
{
    1,
    {
        "Yes",
        "No",
        "Don't really know and will decide later",
    }
};

That's fine in generic AS, but suppose you want the strings in some other AS (like in out Harvard example in flash memory):

typedef struct
{
    int id;
    const char __as * labels[];
} menu1_t;

That won't work. Notice that the *only* reasonable place to put the literals is __as because labels[] is the *only* object that holds references to the literals. It makes absolute no sense to put these literals into generic AS (supplied no error was emit).

Changing to

typedef struct
{
    int id;
    const char __as labels[][40];
} menu2_t;

and a similar initializer like above will work but waste you bunch of valuable memory. Thus you have no alternative and have to use menu1_t:

const char __as STR_YES[] = "Yes";
const char __as STR_NO[]  = "No";
const char __as STR_DUNNO[] = "Don't really know and will decide later";

const menu1_t menu3 =
{
    1,
    {
        STR_YES,
        STR_NO,
        STR_DUNNO
    }
};

With some menues you soon end up with dozens of unnecessary variables just because TR 18037 has a blank area on it's map.

This means that a line like
   const __as char * pallo = "pallo";
can be very useful and that there is exactly one meaning that makes sense: put "pallo" in __as because otherwise you won't be able to reference that string.

The point has obviously been overseen by the spec guys...

Anyway, an error message for
   const __as char * pallo = "pallo";
is very much preferred over completely useless and nonsensical putting "pallo" in generic AS, even if it was possible for the target.

Even more preferred would be to assign the only sensible meaning (provided a target allows it), which should be legal as that extension is implementation defined, anyway.

Johann

Bye,
Ulrich

Reply via email to