Am 21.05.26 um 16:19 schrieb Paul IANNETTA:
Hi,
> Georg-Johann Lay wrote:
> IMO most important is that it doesn't break C++ code that doesn't
> use ASes. Issues with the AS feature (like name mangling) can be
> adjusted once the basic patch is upstream. For example, there
> should be a means to reject code that writes to an avr AS after
> load time, like
>
> int compute_x ();
> const __flash int x = compute_x ();
>
> Such code isn't possible in C (when compute_x () is not
> computable at load time), but C++ allows it.
I am not exactly sure what you mean here. Sure in C++, there are some
initializations which take
place before main, and the same can be done in C with
__attribute__(constructor) for example.
Not really, you cannot write to a const variable, neither in C nor
in C++. But what you can do in C++ but not in C is code like:
int volatile v;
const int var = v;
What the C++ compiler does is
1) Pop a static constructor that initializes var AFTER load time.
The constructor writes to var even though it is const.
In C++, this const means "cannot be changed by the user" rather
than read-only like in non-volatile memory.
2) Put var in some .data section instead of .rodata.
Now when var is __flash qualified, this also implies that var
is read-only in the non-volatile memory sense. The compiler must
not change the assigned section, which in avr-gcc is .progmem.data
(hence neither .data nor .rodata). Moreover, due to __flash the
compiler is obliged to use the requested address space; otherwise
you will run into all sorts of wrong-code bugs, for example when
you access __flash objects in inline asm.
But what do you mean, write to an address space after load time?
How do you do that in C, where there is no concept of
> load-time/pre-main initialization.
You cannot do it in C; the compiler will throw an error for code
like above, something like "v isn't computable at load time".
But it's valid in C++.
> Would you happen to know how avr on llvm address such problems?
It doesn't and generates garbage, instead of diagnosing. Example:
#define AS1 __attribute__((__address_space__(1)))
int volatile v;
const AS1 int var = v;
int read_as1 (const AS1 int *p) {
return *p;
}
int main () {
v = read_as1 (&var);
}
$ clang --target=avr -xc++ y.c -S -mmcu=atmega8 -Os -Wall
It generates no diagnostic, and code that
1) Initializes var after load time (in a static constructor).
2) Locates var in RAM (.local .comm), readable qua LDD / LDS,
and hence violates the AS1 request.
3) read_as1() correctly reads from flash using LPM instructions.
This code is broken. What clang (and avr-g++) should do is to error
on "const AS1 int var = v" since v is not computable at load time.
Similar to how avr-gcc would diagnose it (for any AS).
IMHO, an initial AS support in g++ need not address this, doing
"garbage in => garbage out". But eventually avr-g++ should do a proper
job and diagnose broken code. This will require a new target hook.
> Using the same mangling scheme as llvm does is clearly not a problem,
> and pretty easy to change.
> However, it would imply that the address spaces numbers are the
> same on both GCC and LLVM,
> so those numbers should probably be documented somewhere.
Clang accesses the n-th 64KiB flash segment as address-space n, e.g.
0x0000..0xffff = address-space 1. In avr-gcc, the address-space
numbers are only internals for 1=__flash, 2=__flash1, 3=__flash2, ...
While clang puts no limits on n and generates happily code for AS(100),
avr-gcc goes only up to 6=__flash5. 7=__flashx and 8=__memx are 24-bit
spaces that are not supported by clang.
Johann