SIL memory lifetime failure in @main: memory is not initialized, but should be

I’m having a spot of bother with this code…

var staticArray: InlineArray<3,UInt8> = [3,11,29]

var i = 0
var previous: UInt8 = 0

while(true) {
    if staticArray[i] == 29 {
        staticArray[i] = previous
        previous = previous &+ 2
    }

    previous = staticArray[i]

    i = i &+ 1
    i %= 2
}

…I’m compiling this with my own standard library (which is quite possibly the source of the issue) on the AVR platform with the command…

"/Users/carl/Desktop/S4A IDE Pro (beta).app/Contents/XPCServices/BuildEngine.xpc/Contents/MacOS/swiftc" -emit-ir -O -nostdimport -enforce-exclusivity=unchecked -no-link-objc-runtime -Xfrontend -disable-reflection-metadata -Xfrontend -disable-stack-protector -Xfrontend -disable-implicit-concurrency-module-import -Xfrontend -disable-implicit-string-processing-module-import -enable-experimental-feature Embedded -enable-experimental-feature SymbolLinkageMarkers -target avr-none-none-elf -whole-module-optimization -I "/Users/carl/Desktop/S4A IDE Pro (beta).app/Contents/XPCServices/BuildEngine.xpc/Contents/Resources/uSwift-AVR/Embedded" -I "/Users/carl/Desktop/S4A IDE Pro (beta).app/Contents/XPCServices/BuildEngine.xpc/Contents/Resources/uSwiftShims" -output-file-map build/outputMap.json -I "/Users/carl/Desktop/S4A IDE Pro (beta).app/Contents/XPCServices/BuildEngine.xpc/Contents/Resources/lib/avr-libc/include" -I "/Users/carl/Desktop/S4A IDE Pro (beta).app/Contents/XPCServices/BuildEngine.xpc/Contents/Resources/lib/avr-libgcc/include" -Xcc -DAVR_LIBC_DEFINED -Xcc -DLIBC_DEFINED -Xcc -D__AVR_ATmega328P__ -DAVR_LIBC_DEFINED_SWIFT -Xcc -DF_CPU=16000000 -Xcc -mmcu=atmega328p -I "/Users/carl/Library/Application Support/SwiftForArduino/Extensions/Modules/Embedded" -I "/Users/carl/Library/Application Support/SwiftForArduino/S4A/422/Modules/Embedded" -I /Users/carl/Documents/SwiftForArduino/Exports -module-name main main.swift -o /Users/carl/Documents/SwiftForArduino/6.2/build/main.ll

The compiler traps in what looks like the lib/SIL/Verifier/MemoryLifetimeVerifier.cpp

warning: Unable to locate libSwiftScan. Fallback to `swift-frontend` dependency scanner invocation.
SIL memory lifetime failure in @main: memory is not initialized, but should be
memory location:   %53 = alloc_stack $InlineArray<3, UInt8>        // users: %60, %57, %56, %54
at instruction:   %60 = mark_dependence [unresolved] %59 : $*UInt8 on %53 : $*InlineArray<3, UInt8> // user: %61

Abort: function reportError at MemoryLifetimeVerifier.cpp:265
in function:
// main
// Isolation: unspecified
sil [ossa] @main : $@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 {
bb0(%0 : $Int32, %1 : $UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>):
  alloc_global @$e4main11staticArrays06InlineC0Vy$2_s5UInt8VGvp // id: %2

Note, if I change var staticArray: InlineArray<3,UInt8> = [3,11,29] to let staticArray: InlineArray<3,UInt8> = [3,11,29] it compiles fine, but of course I can’t then change the contents of the inline array.

Also, I tried -emit-sil and even -emit-silgen but the compiler still seems to trap, so I’m guessing this pass runs before even raw SIL is emitted?

The compiler is forked from faad7c76585008cb7a5d0576fabc09a97c8c2c21 and is a modern compiler build (swift driver, swift-syntax, etc.)

I’m looking for advice how to track this down a bit, or anything obvious from a glance looking at the swift code. (The InlineArray in my stdlib is very little changed from normal.)

Thanks for any help and advice anyone can give!

Regards,

Carl

Note: if I move the code into a function, the compiler issue goes away…

import AVR

SetupSerial()

print("defining array shuffle")

func arrayShuffle() -> Never {
    var staticArray: InlineArray<3,UInt8> = [3,11,29]
    
    var i: Int = 0
    var previous: UInt8 = 0

    print(message: ".", addNewline: false)
    
    while mainLoopRunning {
        print(message: ".", addNewline: false)

        if staticArray[i] == 29 {
            staticArray[i] = previous
            previous = previous &+ 2
        }
    
        previous = staticArray[i]
    
        i = i &+ 1
        i %= 2
        
        delay(milliseconds: 100)
        print(message: ".", addNewline: false)
    }

    preconditionFailure()
}

print("about to start array shuffle")

arrayShuffle()

print("should never get here")

avrshutdown()

(the above compiles and runs fine, as expected)

…so it seems possibly related to having an mutable inline array at the top level?

Carl

1 Like

Unfortunately the implementation of top-level globals is still a bit wonky, because they're emitted differently from any other kind of variable, and they don't tend to be used as much.

Another workaround you might want to consider is to wrap your top-level statements in a do { ... } block:

do {
  var staticArray: InlineArray<3,UInt8> = [3,11,29]

  ...
}

This has the same effect as an immediately-called function.

(In fact, why don't we lower top-level globals as if everything was wrapped in an implicit do block? It's because top-level globals are also visible from other source files. Perhaps they shouldn't be, and if they weren't, a bunch of edge cases would disappear from the implementation. Perhaps one day we'll have an -enable-upcoming-feature for exactly this.)

Aside re: top-level symbols

Wouldn’t the edge cases still apply for any top-level variables explicitly declared internal or public?

One approach is to say that globals explicitly declared as public or internal are always lazily initialized even in script mode, while unannotated globals become internal lazy globals in a module, and eagerly initialized local variables in script mode. Or we could even repurpose the lazy keyword to mean something here, but that’s probably too silly.

Cool. This is all very illuminating, thanks guys!

I think for advice to my users, I’ll say “just be a tiny bit careful here, and we have easy work-arounds” … which is definitely good enough for anyone using IA types from our gang. It’s so much better than anything we’ve had to work with in the past already.

Cheers!

Carl