ziglang / zig

General-purpose programming language and toolchain for maintaining robust, optimal, and reusable software.
https://ziglang.org
MIT License
32.36k stars 2.36k forks source link

Zig 0.11.0 regression around @bitCast() / @intCast() in non-debug mode on embedded Cortex-M4 #17882

Open marnix opened 8 months ago

marnix commented 8 months ago

Zig Version

0.11.0

Steps to Reproduce and Observed Behavior

When running Microzig on an STM32F3DISCOVERY board, so with -target thumb-freestanding-eabi -mcpu cortex_m4, but only in all 3 release modes, not in debug mode, I observed that

       pub inline fn read(addr: *volatile Self) PackedT {
           return @bitCast(addr.raw);
       }

does not work as before. From the outside it looks like the STM32 just crashes or halts, somewhere around that code.

And the following workaround makes it work again:

        pub inline fn read(addr: *volatile Self) PackedT {
            const result: PackedT = @bitCast(addr.raw);
            std.mem.doNotOptimizeAway(result);
            return result;
        }

I have seen this in three places in total:

And in all places the same workaround works: Make sure that the argument to @bitCast() / @intCast() is assigned to a local const, and call std.mem.doNotOptimizeAway() on that.

(If anyone has an STM32F3DISCOVERY board, run https://github.com/marnix/zig-stm32f3discovery-play/tree/b0648adb555a43eed4693b0eab1fed22cc9de6f3 on it to reproduce the issue.)

Expected Behavior

Things should have worked like before.

With Zig 0.11.0-dev.538+bf316e550, the older Microzig code worked fine.

Specifically the above 3 pieces of code then looked like this:

(If anyone has an STM32F3DISCOVERY board, run https://github.com/marnix/zig-stm32f3discovery-play/tree/80332369b48aec7b7b74e66f3f4f2d86ffb65614 on with Zig 0.11.0-dev.538+bf316e550 to see things working.)

mlugg commented 8 months ago

I'm unable to produce any difference in generated code on Godbolt between 0.10.0 and master (and the generated code looks fine) when writing a noinline function with a trivial exported wrapper. Perhaps the issue only presents itself when the function is called in a certain way (such as being inlined).

Unfortunately, I don't have the board in question, so can't reduce this issue. If you're able to find a minimal code example which triggers incorrect behavior, that would be incredibly useful.

bcrist commented 8 months ago

FWIW, I haven't noticed any bad behavior when compiling for armv6-thumb (CM0+) using my slightly different MMIO wrapper, where read looks like this:

pub inline fn read(self: *volatile Self) Type {
    return fromInt(Type, self.raw);
}

pub inline fn fromInt(comptime T: type, int_value: anytype) T {
    return switch (@typeInfo(T)) {
        .Enum => @enumFromInt(int_value),
        .Pointer => @ptrFromInt(int_value),
        else => @bitCast(int_value),
    };
}

I'm using zig 0.12.0-dev.694+937e8cb70 currently, not 0.11, though I'm not sure if that would matter.

marnix commented 8 months ago

@bcrist Thanks for that report!

@mlugg Thanks for trying to reproduce this on godbolt, I had also tried but couldn't find anything useful.

So I have uploaded some .bin files for you to study, and source code / build.zig, in https://github.com/marnix/ziglang-zig-17882-repro. I think this is the best I can currently do; let me know if I can do something else.

Thanks in advance for investigating!

aqrit commented 8 months ago

potentially related crash on x64 -> godbolt+ret_type+%7B%0A++++const+shuf+%3D+@Vector(8,+i32)+%7B0,1,2,3,4,5,6,7%7D%3B%0A++++const+low_half+%3D+@shuffle(u8,+a,+undefined,+shuf)%3B%0A++++const+r+:+@Vector(8,+u16)+%3D+@intCast(low_half)%3B%0A++++return+@bitCast(r)%3B%0A%7D%0A'),l:'5',n:'0',o:'Zig+source+%231',t:'0')),k:52.02676111767021,l:'4',n:'0',o:'',s:0,t:'0'),(g:!((h:compiler,i:(compiler:ztrunk,deviceViewOpen:'1',filters:(b:'0',binary:'1',binaryObject:'1',commentOnly:'0',debugCalls:'1',demangle:'0',directives:'0',execute:'1',intel:'0',libraryCode:'0',trim:'1'),flagsViewOpen:'1',fontScale:14,fontUsePx:'0',j:1,lang:zig,libs:!(),options:'-O+ReleaseFast+-target+x86_64-native+-mcpu+sandybridge',overrides:!(),selection:(endColumn:1,endLineNumber:1,positionColumn:1,positionLineNumber:1,selectionStartColumn:1,selectionStartLineNumber:1,startColumn:1,startLineNumber:1),source:1),l:'5',n:'0',o:'+zig+trunk+(Editor+%231)',t:'0')),k:22.135435346362346,l:'4',n:'0',o:'',s:0,t:'0'),(g:!((h:output,i:(compilerName:'zig+0.10.0',editorid:1,fontScale:14,fontUsePx:'0',j:1,wrap:'1'),l:'5',n:'0',o:'Output+of+zig+trunk+(Compiler+%231)',t:'0')),k:25.837803535967435,l:'4',n:'0',o:'',s:0,t:'0')),l:'2',n:'0',o:'',t:'0')),version:4)