goplus / llgo

A Go compiler based on LLVM in order to better integrate Go with the C ecosystem including Python
Apache License 2.0
365 stars 26 forks source link

Compile failed maybe related to defer #802

Open cpunion opened 2 months ago

cpunion commented 2 months ago

Description

Current behavior

Consider the following Go code:

var envs = []int{}

func Test() int {
    defer print(1)
    a := 1
    for _, env := range envs {
        if env != 1 {
            a = a + 1
        }
    }
    return a
}

This generates LLVM IR: (WRONG SAMPLE)

define i64 @main.Test() {
_llgo_0:
  %0 = load i32, ptr @__llgo_defer, align 4
  %1 = call ptr @pthread_getspecific(i32 %0)
  %2 = alloca i8, i64 196, align 1
  %3 = alloca i8, i64 40, align 1
  %4 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Defer", ptr %3, i32 0, i32 0
  store ptr %2, ptr %4, align 8
  %5 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Defer", ptr %3, i32 0, i32 1
  store i64 0, ptr %5, align 4
  %6 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Defer", ptr %3, i32 0, i32 2
  store ptr %1, ptr %6, align 8
  %7 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Defer", ptr %3, i32 0, i32 3
  store ptr blockaddress(@main.Test, %_llgo_6), ptr %7, align 8
  %8 = call i32 @pthread_setspecific(i32 %0, ptr %3)
  %9 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Defer", ptr %3, i32 0, i32 1
  %10 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Defer", ptr %3, i32 0, i32 3
  %11 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Defer", ptr %3, i32 0, i32 4
  %12 = call i32 @sigsetjmp(ptr %2, i32 0)
  %13 = icmp eq i32 %12, 0
  br i1 %13, label %_llgo_8, label %_llgo_9

_llgo_1:                                          ; preds = %_llgo_7
  ret i64 0

_llgo_2:                                          ; preds = %_llgo_5, %_llgo_3, %_llgo_8
  %14 = phi i64 [ 1, %_llgo_8 ], [ %14, %_llgo_3 ], [ %26, %_llgo_5 ]
  %15 = phi i64 [ -1, %_llgo_8 ], [ %16, %_llgo_3 ], [ %16, %_llgo_5 ]
  %16 = add i64 %15, 1
  %17 = icmp slt i64 %16, %33
  br i1 %17, label %_llgo_3, label %_llgo_4

_llgo_3:                                          ; preds = %_llgo_2
  %18 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %32, 0
  %19 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %32, 1
  %20 = icmp slt i64 %16, 0
  %21 = icmp sge i64 %16, %19
  %22 = or i1 %21, %20
  call void @"github.com/goplus/llgo/internal/runtime.AssertIndexRange"(i1 %22)
  %23 = getelementptr inbounds i64, ptr %18, i64 %16
  %24 = load i64, ptr %23, align 4
  %25 = icmp ne i64 %24, 1
  br i1 %25, label %_llgo_5, label %_llgo_2

_llgo_4:                                          ; preds = %_llgo_2
  store ptr blockaddress(@main.Test, %_llgo_10), ptr %11, align 8
  br label %_llgo_6

_llgo_5:                                          ; preds = %_llgo_3
  %26 = add i64 %14, 1
  br label %_llgo_2

_llgo_6:                                          ; preds = %_llgo_9, %_llgo_4
  store ptr blockaddress(@main.Test, %_llgo_7), ptr %10, align 8
  %27 = load i64, ptr %9, align 4
  call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 1)
  %28 = load %"github.com/goplus/llgo/internal/runtime.Defer", ptr %3, align 8
  %29 = extractvalue %"github.com/goplus/llgo/internal/runtime.Defer" %28, 2
  %30 = call i32 @pthread_setspecific(i32 %0, ptr %29)
  %31 = load ptr, ptr %11, align 8
  indirectbr ptr %31, [label %_llgo_7, label %_llgo_10]

_llgo_7:                                          ; preds = %_llgo_9, %_llgo_6
  call void @"github.com/goplus/llgo/internal/runtime.Rethrow"(ptr %1)
  br label %_llgo_1

_llgo_8:                                          ; preds = %_llgo_0
  %32 = load %"github.com/goplus/llgo/internal/runtime.Slice", ptr @main.envs, align 8
  %33 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %32, 1
  br label %_llgo_2

_llgo_9:                                          ; preds = %_llgo_0
  store ptr blockaddress(@main.Test, %_llgo_7), ptr %11, align 8
  %34 = load ptr, ptr %10, align 8
  indirectbr ptr %34, [label %_llgo_7, label %_llgo_6]

_llgo_10:                                         ; preds = %_llgo_6
  ret i64 %14
}

Compile it with llc:

$ /opt/homebrew/bin/llc llgo_autogen.ll
Instruction does not dominate all uses!
  %14 = phi i64 [ 1, %_llgo_8 ], [ %14, %_llgo_3 ], [ %26, %_llgo_5 ]
  ret i64 %14

But it can be compiled by clang:

/opt/homebrew/bin/clang -c llgo_autogen.ll
warning: overriding the module target triple with arm64-apple-macosx14.0.0 [-Woverride-module]
1 warning generated.

When generate code with debug info, the code almost same except debug info:

define i64 @main.Test() !dbg !22 {
_llgo_0:
  %0 = load i32, ptr @__llgo_defer, align 4, !dbg !25
  %1 = call ptr @pthread_getspecific(i32 %0), !dbg !25
  %2 = alloca i8, i64 196, align 1, !dbg !25
  %3 = alloca i8, i64 40, align 1, !dbg !25
  %4 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Defer", ptr %3, i32 0, i32 0, !dbg !25
  store ptr %2, ptr %4, align 8, !dbg !25
  %5 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Defer", ptr %3, i32 0, i32 1, !dbg !25
  store i64 0, ptr %5, align 4, !dbg !25
  %6 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Defer", ptr %3, i32 0, i32 2, !dbg !25
  store ptr %1, ptr %6, align 8, !dbg !25
  %7 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Defer", ptr %3, i32 0, i32 3, !dbg !25
  store ptr blockaddress(@main.Test, %_llgo_6), ptr %7, align 8, !dbg !25
  %8 = call i32 @pthread_setspecific(i32 %0, ptr %3), !dbg !25
  %9 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Defer", ptr %3, i32 0, i32 1, !dbg !25
  %10 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Defer", ptr %3, i32 0, i32 3, !dbg !25
  %11 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Defer", ptr %3, i32 0, i32 4, !dbg !25
  %12 = call i32 @sigsetjmp(ptr %2, i32 0), !dbg !25
  %13 = icmp eq i32 %12, 0, !dbg !25
  br i1 %13, label %_llgo_8, label %_llgo_9, !dbg !25

_llgo_1:                                          ; preds = %_llgo_7
  ret i64 0, !dbg !26

_llgo_2:                                          ; preds = %_llgo_5, %_llgo_3, %_llgo_8
  %14 = phi i64 [ 1, %_llgo_8 ], [ %14, %_llgo_3 ], [ %26, %_llgo_5 ], !dbg !25
  %15 = phi i64 [ -1, %_llgo_8 ], [ %16, %_llgo_3 ], [ %16, %_llgo_5 ], !dbg !25
  %16 = add i64 %15, 1, !dbg !26
  %17 = icmp slt i64 %16, %33, !dbg !26
  br i1 %17, label %_llgo_3, label %_llgo_4, !dbg !26

_llgo_3:                                          ; preds = %_llgo_2
  %18 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %32, 0, !dbg !27
  %19 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %32, 1, !dbg !27
  %20 = icmp slt i64 %16, 0, !dbg !27
  %21 = icmp sge i64 %16, %19, !dbg !27
  %22 = or i1 %21, %20, !dbg !27
  call void @"github.com/goplus/llgo/internal/runtime.AssertIndexRange"(i1 %22), !dbg !27
  %23 = getelementptr inbounds i64, ptr %18, i64 %16, !dbg !27
  %24 = load i64, ptr %23, align 4, !dbg !26
  call void @llvm.dbg.value(metadata i64 %24, metadata !28, metadata !DIExpression()), !dbg !29
  call void @llvm.dbg.value(metadata i64 %24, metadata !28, metadata !DIExpression()), !dbg !30
  %25 = icmp ne i64 %24, 1, !dbg !31
  br i1 %25, label %_llgo_5, label %_llgo_2, !dbg !31

_llgo_4:                                          ; preds = %_llgo_2
  call void @llvm.dbg.value(metadata i64 %14, metadata !32, metadata !DIExpression()), !dbg !33
  store ptr blockaddress(@main.Test, %_llgo_10), ptr %11, align 8, !dbg !34
  br label %_llgo_6, !dbg !34

_llgo_5:                                          ; preds = %_llgo_3
  call void @llvm.dbg.value(metadata i64 %14, metadata !32, metadata !DIExpression()), !dbg !35
  %26 = add i64 %14, 1, !dbg !34
  call void @llvm.dbg.value(metadata i64 %26, metadata !32, metadata !DIExpression()), !dbg !36
  br label %_llgo_2, !dbg !34

_llgo_6:                                          ; preds = %_llgo_9, %_llgo_4
  store ptr blockaddress(@main.Test, %_llgo_7), ptr %10, align 8, !dbg !34
  %27 = load i64, ptr %9, align 4, !dbg !34
  call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 1), !dbg !34
  %28 = load %"github.com/goplus/llgo/internal/runtime.Defer", ptr %3, align 8, !dbg !34
  %29 = extractvalue %"github.com/goplus/llgo/internal/runtime.Defer" %28, 2, !dbg !34
  %30 = call i32 @pthread_setspecific(i32 %0, ptr %29), !dbg !34
  %31 = load ptr, ptr %11, align 8, !dbg !34
  indirectbr ptr %31, [label %_llgo_7, label %_llgo_10], !dbg !34

_llgo_7:                                          ; preds = %_llgo_9, %_llgo_6
  call void @"github.com/goplus/llgo/internal/runtime.Rethrow"(ptr %1), !dbg !25
  br label %_llgo_1, !dbg !25

_llgo_8:                                          ; preds = %_llgo_0
  call void @llvm.dbg.value(metadata i64 1, metadata !32, metadata !DIExpression()), !dbg !37
  %32 = load %"github.com/goplus/llgo/internal/runtime.Slice", ptr @main.envs, align 8, !dbg !27
  call void @llvm.dbg.value(metadata %"github.com/goplus/llgo/internal/runtime.Slice" %32, metadata !38, metadata !DIExpression()), !dbg !27
  %33 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %32, 1, !dbg !26
  br label %_llgo_2, !dbg !26

_llgo_9:                                          ; preds = %_llgo_0
  store ptr blockaddress(@main.Test, %_llgo_7), ptr %11, align 8, !dbg !34
  %34 = load ptr, ptr %10, align 8, !dbg !34
  indirectbr ptr %34, [label %_llgo_7, label %_llgo_6], !dbg !34

_llgo_10:                                         ; preds = %_llgo_6
  ret i64 %14, !dbg !34
}

When remove the debug tokens and lines, it is no difference between them.

Compile it with llc:

$ /opt/homebrew/bin/llc llgo_autogen.ll
Instruction does not dominate all uses!
  %14 = phi i64 [ 1, %_llgo_8 ], [ %14, %_llgo_3 ], [ %26, %_llgo_5 ], !dbg !25
  ret i64 %14, !dbg !34
LLVM ERROR: Broken module found, compilation aborted!
PLEASE submit a bug report to https://github.com/Homebrew/homebrew-core/issues and include the crash backtrace.
Stack dump:
0.  Program arguments: /opt/homebrew/bin/llc llgo_autogen.ll
 #0 0x0000000111fe1d60 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/opt/homebrew/Cellar/llvm/18.1.8/lib/libLLVM.dylib+0x4695d60)
 #1 0x0000000111fe2134 SignalHandler(int) (/opt/homebrew/Cellar/llvm/18.1.8/lib/libLLVM.dylib+0x4696134)
 #2 0x00000001805f7584 (/usr/lib/system/libsystem_platform.dylib+0x180477584)
 #3 0x00000001805c6c20 (/usr/lib/system/libsystem_pthread.dylib+0x180446c20)
 #4 0x00000001804d3a20 (/usr/lib/system/libsystem_c.dylib+0x180353a20)
 #5 0x000000010d9e7da0 llvm::report_fatal_error(llvm::Twine const&, bool) (/opt/homebrew/Cellar/llvm/18.1.8/lib/libLLVM.dylib+0x9bda0)
 #6 0x0000000111fd4870 llvm::report_fatal_error(llvm::StringRef, bool) (/opt/homebrew/Cellar/llvm/18.1.8/lib/libLLVM.dylib+0x4688870)
 #7 0x000000010db08d10 llvm::UpgradeDebugInfo(llvm::Module&) (/opt/homebrew/Cellar/llvm/18.1.8/lib/libLLVM.dylib+0x1bcd10)
 #8 0x00000001119addd4 llvm::LLParser::validateEndOfModule(bool) (/opt/homebrew/Cellar/llvm/18.1.8/lib/libLLVM.dylib+0x4061dd4)
 #9 0x00000001119ac984 llvm::LLParser::Run(bool, llvm::function_ref<std::__1::optional<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>> (llvm::StringRef, llvm::StringRef)>) (/opt/homebrew/Cellar/llvm/18.1.8/lib/libLLVM.dylib+0x4060984)
#10 0x00000001119e7e90 parseAssemblyInto(llvm::MemoryBufferRef, llvm::Module*, llvm::ModuleSummaryIndex*, llvm::SMDiagnostic&, llvm::SlotMapping*, bool, llvm::function_ref<std::__1::optional<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>> (llvm::StringRef, llvm::StringRef)>) (/opt/homebrew/Cellar/llvm/18.1.8/lib/libLLVM.dylib+0x409be90)
#11 0x00000001119e8138 llvm::parseAssembly(llvm::MemoryBufferRef, llvm::SMDiagnostic&, llvm::LLVMContext&, llvm::SlotMapping*, llvm::function_ref<std::__1::optional<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>> (llvm::StringRef, llvm::StringRef)>) (/opt/homebrew/Cellar/llvm/18.1.8/lib/libLLVM.dylib+0x409c138)
#12 0x000000010dd877e8 llvm::parseIR(llvm::MemoryBufferRef, llvm::SMDiagnostic&, llvm::LLVMContext&, llvm::ParserCallbacks) (/opt/homebrew/Cellar/llvm/18.1.8/lib/libLLVM.dylib+0x43b7e8)
#13 0x000000010dd881e0 llvm::parseIRFile(llvm::StringRef, llvm::SMDiagnostic&, llvm::LLVMContext&, llvm::ParserCallbacks) (/opt/homebrew/Cellar/llvm/18.1.8/lib/libLLVM.dylib+0x43c1e0)
#14 0x00000001048b9428 compileModule(char**, llvm::LLVMContext&) (/opt/homebrew/Cellar/llvm/18.1.8/bin/llc+0x100005428)
#15 0x00000001048b84a8 main (/opt/homebrew/Cellar/llvm/18.1.8/bin/llc+0x1000044a8)
#16 0x000000018023e0e0
[1]    77142 abort      /opt/homebrew/bin/llc llgo_autogen.ll

Compile it with clang:

$ /opt/homebrew/bin/clang -c llgo_autogen.ll
Instruction does not dominate all uses!
  %14 = phi i64 [ 1, %_llgo_8 ], [ %14, %_llgo_3 ], [ %26, %_llgo_5 ], !dbg !25
  ret i64 %14, !dbg !34
fatal error: error in backend: Broken module found, compilation aborted!
PLEASE submit a bug report to https://github.com/Homebrew/homebrew-core/issues and include the crash backtrace, preprocessed source, and associated run script.
Stack dump:
0.  Program arguments: /opt/homebrew/bin/clang -c llgo_autogen.ll
 #0 0x000000011aeb9d60 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/opt/homebrew/Cellar/llvm/18.1.8/lib/libLLVM.dylib+0x4695d60)
 #1 0x0000000116979560 llvm::sys::CleanupOnSignal(unsigned long) (/opt/homebrew/Cellar/llvm/18.1.8/lib/libLLVM.dylib+0x155560)
 #2 0x000000011aeab718 (anonymous namespace)::CrashRecoveryContextImpl::HandleCrash(int, unsigned long) (/opt/homebrew/Cellar/llvm/18.1.8/lib/libLLVM.dylib+0x4687718)
 #3 0x000000011aeab6c8 llvm::CrashRecoveryContext::HandleExit(int) (/opt/homebrew/Cellar/llvm/18.1.8/lib/libLLVM.dylib+0x46876c8)
 #4 0x000000011aeb95b4 llvm::sys::Process::Exit(int, bool) (/opt/homebrew/Cellar/llvm/18.1.8/lib/libLLVM.dylib+0x46955b4)
 #5 0x0000000104323b8c LLVMErrorHandler(void*, char const*, bool) (/opt/homebrew/Cellar/llvm/18.1.8/bin/clang-18+0x100007b8c)
 #6 0x00000001168bfd74 llvm::report_fatal_error(llvm::Twine const&, bool) (/opt/homebrew/Cellar/llvm/18.1.8/lib/libLLVM.dylib+0x9bd74)
 #7 0x000000011aeac870 llvm::report_fatal_error(llvm::StringRef, bool) (/opt/homebrew/Cellar/llvm/18.1.8/lib/libLLVM.dylib+0x4688870)
 #8 0x00000001169e0d10 llvm::UpgradeDebugInfo(llvm::Module&) (/opt/homebrew/Cellar/llvm/18.1.8/lib/libLLVM.dylib+0x1bcd10)
 #9 0x000000011a885dd4 llvm::LLParser::validateEndOfModule(bool) (/opt/homebrew/Cellar/llvm/18.1.8/lib/libLLVM.dylib+0x4061dd4)
#10 0x000000011a884984 llvm::LLParser::Run(bool, llvm::function_ref<std::__1::optional<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>> (llvm::StringRef, llvm::StringRef)>) (/opt/homebrew/Cellar/llvm/18.1.8/lib/libLLVM.dylib+0x4060984)
#11 0x000000011a8bfe90 parseAssemblyInto(llvm::MemoryBufferRef, llvm::Module*, llvm::ModuleSummaryIndex*, llvm::SMDiagnostic&, llvm::SlotMapping*, bool, llvm::function_ref<std::__1::optional<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>> (llvm::StringRef, llvm::StringRef)>) (/opt/homebrew/Cellar/llvm/18.1.8/lib/libLLVM.dylib+0x409be90)
#12 0x000000011a8c0138 llvm::parseAssembly(llvm::MemoryBufferRef, llvm::SMDiagnostic&, llvm::LLVMContext&, llvm::SlotMapping*, llvm::function_ref<std::__1::optional<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>> (llvm::StringRef, llvm::StringRef)>) (/opt/homebrew/Cellar/llvm/18.1.8/lib/libLLVM.dylib+0x409c138)
#13 0x0000000116c5f7e8 llvm::parseIR(llvm::MemoryBufferRef, llvm::SMDiagnostic&, llvm::LLVMContext&, llvm::ParserCallbacks) (/opt/homebrew/Cellar/llvm/18.1.8/lib/libLLVM.dylib+0x43b7e8)
#14 0x000000010ab07730 clang::CodeGenAction::loadModule(llvm::MemoryBufferRef) (/opt/homebrew/Cellar/llvm/18.1.8/lib/libclang-cpp.dylib+0x193f730)
#15 0x000000010ab08774 clang::CodeGenAction::ExecuteAction() (/opt/homebrew/Cellar/llvm/18.1.8/lib/libclang-cpp.dylib+0x1940774)
#16 0x000000010b264dd4 clang::FrontendAction::Execute() (/opt/homebrew/Cellar/llvm/18.1.8/lib/libclang-cpp.dylib+0x209cdd4)
#17 0x000000010b1e7ad4 clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) (/opt/homebrew/Cellar/llvm/18.1.8/lib/libclang-cpp.dylib+0x201fad4)
#18 0x000000010b2b7c28 clang::ExecuteCompilerInvocation(clang::CompilerInstance*) (/opt/homebrew/Cellar/llvm/18.1.8/lib/libclang-cpp.dylib+0x20efc28)
#19 0x0000000104322b28 cc1_main(llvm::ArrayRef<char const*>, char const*, void*) (/opt/homebrew/Cellar/llvm/18.1.8/bin/clang-18+0x100006b28)
#20 0x0000000104321218 ExecuteCC1Tool(llvm::SmallVectorImpl<char const*>&, llvm::ToolContext const&) (/opt/homebrew/Cellar/llvm/18.1.8/bin/clang-18+0x100005218)
#21 0x000000010ae65d28 void llvm::function_ref<void ()>::callback_fn<clang::driver::CC1Command::Execute(llvm::ArrayRef<std::__1::optional<llvm::StringRef>>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>*, bool*) const::$_0>(long) (/opt/homebrew/Cellar/llvm/18.1.8/lib/libclang-cpp.dylib+0x1c9dd28)
#22 0x00000001168b0b48 llvm::CrashRecoveryContext::RunSafely(llvm::function_ref<void ()>) (/opt/homebrew/Cellar/llvm/18.1.8/lib/libLLVM.dylib+0x8cb48)
#23 0x000000010ae65524 clang::driver::CC1Command::Execute(llvm::ArrayRef<std::__1::optional<llvm::StringRef>>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>*, bool*) const (/opt/homebrew/Cellar/llvm/18.1.8/lib/libclang-cpp.dylib+0x1c9d524)
#24 0x000000010ae26190 clang::driver::Compilation::ExecuteCommand(clang::driver::Command const&, clang::driver::Command const*&, bool) const (/opt/homebrew/Cellar/llvm/18.1.8/lib/libclang-cpp.dylib+0x1c5e190)
#25 0x000000010ae46e00 clang::driver::Driver::ExecuteCompilation(clang::driver::Compilation&, llvm::SmallVectorImpl<std::__1::pair<int, clang::driver::Command const*>>&) (/opt/homebrew/Cellar/llvm/18.1.8/lib/libclang-cpp.dylib+0x1c7ee00)
#26 0x000000010431fd44 clang_main(int, char**, llvm::ToolContext const&) (/opt/homebrew/Cellar/llvm/18.1.8/bin/clang-18+0x100003d44)
#27 0x000000010432ce38 main (/opt/homebrew/Cellar/llvm/18.1.8/bin/clang-18+0x100010e38)
#28 0x000000018023e0e0
clang: error: clang frontend command failed with exit code 70 (use -v to see invocation)
Homebrew clang version 18.1.8
Target: arm64-apple-darwin23.4.0
Thread model: posix
InstalledDir: /opt/homebrew/bin
clang: note: diagnostic msg: Error generating preprocessed source(s) - no preprocessable inputs.

When remove the defer statement, it compile passed. The code generated:

define i64 @main.Test() !dbg !22 {
_llgo_0:
  call void @llvm.dbg.value(metadata i64 1, metadata !25, metadata !DIExpression()), !dbg !26
  %0 = load %"github.com/goplus/llgo/internal/runtime.Slice", ptr @main.envs, align 8, !dbg !27
  call void @llvm.dbg.value(metadata %"github.com/goplus/llgo/internal/runtime.Slice" %0, metadata !28, metadata !DIExpression()), !dbg !27
  %1 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %0, 1, !dbg !29
  br label %_llgo_1, !dbg !29

_llgo_1:                                          ; preds = %_llgo_4, %_llgo_2, %_llgo_0
  %2 = phi i64 [ 1, %_llgo_0 ], [ %2, %_llgo_2 ], [ %14, %_llgo_4 ], !dbg !30
  %3 = phi i64 [ -1, %_llgo_0 ], [ %4, %_llgo_2 ], [ %4, %_llgo_4 ], !dbg !30
  %4 = add i64 %3, 1, !dbg !29
  %5 = icmp slt i64 %4, %1, !dbg !29
  br i1 %5, label %_llgo_2, label %_llgo_3, !dbg !29

_llgo_2:                                          ; preds = %_llgo_1
  %6 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %0, 0, !dbg !27
  %7 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %0, 1, !dbg !27
  %8 = icmp slt i64 %4, 0, !dbg !27
  %9 = icmp sge i64 %4, %7, !dbg !27
  %10 = or i1 %9, %8, !dbg !27
  call void @"github.com/goplus/llgo/internal/runtime.AssertIndexRange"(i1 %10), !dbg !27
  %11 = getelementptr inbounds i64, ptr %6, i64 %4, !dbg !27
  %12 = load i64, ptr %11, align 4, !dbg !29
  call void @llvm.dbg.value(metadata i64 %12, metadata !31, metadata !DIExpression()), !dbg !32
  call void @llvm.dbg.value(metadata i64 %12, metadata !31, metadata !DIExpression()), !dbg !33
  %13 = icmp ne i64 %12, 1, !dbg !34
  br i1 %13, label %_llgo_4, label %_llgo_1, !dbg !34

_llgo_3:                                          ; preds = %_llgo_1
  call void @llvm.dbg.value(metadata i64 %2, metadata !25, metadata !DIExpression()), !dbg !35
  ret i64 %2, !dbg !36

_llgo_4:                                          ; preds = %_llgo_2
  call void @llvm.dbg.value(metadata i64 %2, metadata !25, metadata !DIExpression()), !dbg !37
  %14 = add i64 %2, 1, !dbg !36
  call void @llvm.dbg.value(metadata i64 %14, metadata !25, metadata !DIExpression()), !dbg !38
  br label %_llgo_1, !dbg !36
}

The flow graph of code block WRONG SAMPLE

image

There was a wrong path from _llgo_0 to _llgo_10 that didn't through _llgo_2, and the return value is allocated in _llgo_2. Maybe it's jumping correctly by the blockaddress, but it can't pass the compiling.

It led to this issue: https://github.com/goplus/llgo/actions/runs/10971740620/job/30467224448?pr=794

Below is the right path, the _llgo_1 (same as _llgo_2 in the defer version) is always executed.

image