Compound literals efficiency

  • Thread starter Marcus Harnisch
  • Start date
M

Marcus Harnisch

Hi all

Reading ISO/IEC 9899:TC3 "6.5.2.5 Compound literals", §4, I can almost
answer my own question. When using a compound literal, does the
compiler *absolutely have to* allocate an unnamed object?

Looking at assembler level, this requires extra memory access in cases
where the value could fit into an immediate.

,----
| struct s
| {
| int i;
| } S;
|
| void setS()
| {
| S = (const struct s) { // const doesn't make a difference here
| 37
| };
| }
`----

In this kind of pointless example the processor assigns S.i a value
loaded from a constant data section. Since a register is used to
(temporarily) hold S.i the actual value "37" could be implemented as
immediate value making the entire operation extrememly efficient.

Bitfield structures in particular could benefit in that case.

Thanks
Marcus
 
J

jacob navia

Marcus said:
Hi all

Reading ISO/IEC 9899:TC3 "6.5.2.5 Compound literals", §4, I can almost
answer my own question. When using a compound literal, does the
compiler *absolutely have to* allocate an unnamed object?

Looking at assembler level, this requires extra memory access in cases
where the value could fit into an immediate.

,----
| struct s
| {
| int i;
| } S;
|
| void setS()
| {
| S = (const struct s) { // const doesn't make a difference here
| 37
| };
| }
`----

In this kind of pointless example the processor assigns S.i a value
loaded from a constant data section. Since a register is used to
(temporarily) hold S.i the actual value "37" could be implemented as
immediate value making the entire operation extrememly efficient.

Bitfield structures in particular could benefit in that case.

Thanks
Marcus

Problem is, those structures should be writable. If you put it in the
text section, they would not be writable. Now, a clever compiler could
determine that nowhere is the structure address taken, etc etc, but
is it worth the trouble?

I do not think so
 
B

Bartc

jacob navia said:
Problem is, those structures should be writable. If you put it in the
text section, they would not be writable. Now, a clever compiler could
determine that nowhere is the structure address taken, etc etc, but
is it worth the trouble?

I think he's talking about the case where the literal value for a struct
might fit into a 32- or 64-bit immediate field.

And when initialising local variables (although his code didn't make much
sense). So the data is copied from an immediate field in code memory to the
struct variable, rather than come from data memory.

Then he has a point.
 
M

Marcus Harnisch

Bartc said:
I think he's talking about the case where the literal value for a
struct might fit into a 32- or 64-bit immediate field.

I think you are correct.
And when initialising local variables (although his code didn't make
much sense). So the data is copied from an immediate field in code
memory to the struct variable, rather than come from data memory.

Right. Think: Initialization of memory mapped hardware registers.
Then he has a point.

Thanks.
 
M

Marcus Harnisch

Hi Jacob

I am fairly sure that there is a misunderstanding.

jacob navia said:
Problem is, those structures should be writable. If you put it in the
text section, they would not be writable.

How would you write to the implicit structure created by the compound
literal, anyway? You don't have a handle.
Now, a clever compiler could determine that nowhere is the structure
address taken, etc etc, but is it worth the trouble?

How would you obtain the address of the literal? See above.

I kept the example deliberately simple (yet complete) in an attempt to
abstract from any specific situation. In my case that would be memory
mapped hardware registers, implemented as bitfield structures. I am
looking for an efficient way to initialize them efficiently using
standard C language.

Another example:

,----
| struct r {
| int bit0: 1; // order defined by ABI
| int : 1;
| int bit2: 1;
| int : 2;
| int bit5: 1;
| int : 26;
| } R;
|
| void initR()
| {
| R = (struct r) { .bit0 = 1, .bit2 = 1, .bit5 = 1 };
| }
`----

Looking at the structure definition, the value written is still 37,
which in my architecture could be encoded as immediate value. The
extra memory access wouldn't kill me, but I wouldn't mind if there
were a better way.

Kind regards
Marcus
 
B

Ben Pfaff

Marcus Harnisch said:
How would you write to the implicit structure created by the compound
literal, anyway? You don't have a handle.

A compound literal is an lvalue, so you can use the & operator.
 
J

jacob navia

Marcus said:
Hi Jacob

I am fairly sure that there is a misunderstanding.



How would you write to the implicit structure created by the compound
literal, anyway? You don't have a handle.


How would you obtain the address of the literal? See above.

struct r * f = {37};

Now, the pointer f contains the address of that structure.
 
J

jameskuyper

Ben said:
A compound literal is an lvalue, so you can use the & operator.

Yes, but unlike many other kinds of lvalues, you get only one
opportunity to apply it. If you don't collect the address of the
compound literal in the place where it actually occurs (as, for
example, in this case), then there's no way to obtain that address
anywhere else in the program. Any such compound literal doesn't have
to have it's own location in memory, because of the as-if rule.
 
K

Keith Thompson

Ben Pfaff said:
A compound literal is an lvalue, so you can use the & operator.

I've always assumed that the anonymous object specified by a compound
literal is implicitly const (like string literals, but done right).
In fact, now that I take a close look at C99 6.5.2.5, I see that it
isn't, unless the type is explicitly const. For example, this
program:

#include <stdio.h>
int main(void)
{
struct foo {
int i;
double d;
};
struct foo *ptr;
ptr = &(struct foo){1, 2.3};
printf("ptr->i = %d, ptr->d = %g\n", ptr->i, ptr->d);
ptr->i ++;
ptr->d --;
printf("ptr->i = %d, ptr->d = %g\n", ptr->i, ptr->d);
return 0;
}

compiles with no diagnostics and produces this output:

ptr->i = 1, ptr->d = 2.3
ptr->i = 2, ptr->d = 1.3

Another difference between string literals and compound literals is
that, if a compound literal appears within a function, the anonymous
object has automatic storage duration associated with the enclosing
block. So returning the address of a string literal is ok, but
returning the address of a compound literal is not.
 
K

Keith Thompson

jacob navia said:
struct r * f = {37};

Now, the pointer f contains the address of that structure.

No, I believe that's a constraint violation. The initializer {37}
(which is an ordinary initializer, not a compound literal) is
appropriate for an object of type struct r, assuming struct r is
defined appropriately. When I compile something similar, I get:

c.c:8: warning: initialization makes pointer from integer without a cast
c.c:8: warning: excess elements in scalar initializer

Note that both warnings refer to constraint violations.

I think the example you're looking for is:

struct r *f = &(struct r){37};

which is legal and even lets you modify the value of *f.
 
M

Marcus Harnisch

Marcus Harnisch said:
,----
| struct s
| {
| int i;
| } S;
|
| void setS()
| {
| S = (const struct s) { // const doesn't make a difference here
| 37
| };
| }
`----

In this kind of pointless example the processor assigns S.i a value
loaded from a constant data section. Since a register is used to
(temporarily) hold S.i the actual value "37" could be implemented as
immediate value making the entire operation extrememly efficient.

FWIW, one compiler (Sourcery G++ Lite 2008q3-66, GCC 4.3.2) I tried
does in fact use immediates in this case:

,----
| setS:
| @ Function supports interworking.
| @ args = 0, pretend = 0, frame = 0
| @ frame_needed = 1, uses_anonymous_args = 0
| @ link register save eliminated.
| str fp, [sp, #-4]!
| add fp, sp, #0
| ldr r2, .L11
| mov r3, #37 @ <<<<<<<<<<<<<<<<<<<<<<<<<<<<
| str r3, [r2, #0]
| add sp, fp, #0
| ldmfd sp!, {fp}
| bx lr
`----

At least I wasn't entirely off-track.

Regards
Marcus
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,013
Latest member
KatriceSwa

Latest Threads

Top