Multiple stores generated on volatile packed structs

Hey.

I am trying to use packed structs to model memory mapped peripherals, but am getting some really weird results with the generated code. I am compiling for thumb-freestanding-none.

I have reproduced it here in godbolt. To me it looks like the compiler is generating a store for each bitfield within the packed struct.

I expected the packed structs backed by a u32 would hide this behavior?

I guess my questions are:

  1. Is this expected behavior? Is it just not possible to use volatile packed structs?
  2. What is the recommended way for modeling memory mapped peripherals? I was really hoping these bitfields would be a replacement for having separate enumerations/definitions for each bit.

Welcome to the @Lambosaurus!

That’s really interesting - I was just playing around with your example to see what other code we can generate just to try some different stuff. Probably won’t solve your problem, but I just wanted to play around with it.

I get very minimal assembly by casting the packed struct to a u32 first - you can also directly assign to that field with essentially the same results. I’m not saying the cast is a good idea, it’s just interesting. The struct assignment hits all of those fields. I think @andrewrk is probably the right person to look at this.

Thanks Andrew.

Good to know at least I’m not crazy.

For now I think I’m going to use a wrapper struct that provides inline functions to provide the typing. See the last example here. This generates the right instructions, but is a bit of a letdown for conciseness - especially in the read-modify-write scenario.

Let me know if anyone else has a smarter solution than this, (or a fix would be nice).

Have you tried removing -fstrip from your compile flags? If I change to ReleaseFast and remove -fstrip, here’s what I get:

store_by_struct:
        movw    r0, #4140
        movs    r1, #2
        movt    r0, #16386
        str     r1, [r0]
        bx      lr

store_by_u32:
        movw    r0, #4144
        movs    r1, #2
        movt    r0, #16386
        str     r1, [r0]
        bx      lr

store_by_register32:
        movw    r0, #4148
        movs    r1, #4
        movt    r0, #16386
        str     r1, [r0]
        bx      lr

Looks like it’s actually something to do with -fstrip and ReleaseSmall. I’m still getting the same results if I add -fstrip back to ReleaseFast, and on ReleaseSmall I get your original results either way.

Interesting find. Thanks for looking into this.

I suspect the correlation is because -fstrip automatically happens on ReleaseSmall.

Removing debug symbols is an absolute requirement for me. I cannot budge on -fstrip / ReleaseSmall. My targets have 8K flash, and I have a lot of functionality to jam in there.

Hopefully this helps narrow down the underlying issue at least.

To confirm the relationship between this issue and -fstrip. When optimizing for ReleaseSmall, the issue disappears when you set -fno-strip (which prevents the small release stripping symbols by default).

I think you have enough information at this point to open an issue on github. That’s the next place I would go now that things are narrowed down: Issues · ziglang/zig · GitHub

If you get a response, please share it back to the forum so we can help people in the future with this issue :slight_smile:

1 Like

As an update to anyone following this thread, @Lambosaurus created an issue on github and it was added to the 0.13.0 milestones (AKA: Resolve or postpone these issues before releasing 0.13.0).

It may be a bit before a decision is made on this, but it’s being investigated!

1 Like