Odin icon indicating copy to clipboard operation
Odin copied to clipboard

Error slicing a list of procedures

Open tsillus opened this issue 1 year ago • 1 comments

Context

I wanted to pass a list of procedures to another procedure, but pass it as a slice:

package scratch

proc_type :: #type proc() -> (int, bool);

foos ::proc(callables: []proc_type) -> (n:int) {

    is_valid : bool

    for i in 0..<len(callables) {
        n, is_valid = callables[i]()
    }

    if is_valid {
        return n
    }
    
    return -1    
}

bar : proc_type : proc() -> (n:int, is_valid:bool) {
    return 1, true
}

main :: proc() {
    
    procs := [3]proc_type{bar, bar, bar}

    foos(procs[:])  // this causes the error
}


  • Operating System & Odin Version:

    • Windows 11,
    • odin version dev-2023-04:70b0ade8
  • Please paste odin report output: Odin: dev-2023-04:70b0ade8 OS: Windows 11 Home Basic (version: 22H2), build 22621.1555 CPU: Intel(R) Core(TM) i7-9700K CPU @ 3.60GHz RAM: 16301 MiB

Expected Behavior

I expected my code to either compile or give me a proper error message explaining why or that I can't slice a list of procedures.

Current Behavior

The compiler crashes.

Failure Information (for bugs)

D:\projects\odin\scratch>odin build . 
LLVM CODE GEN FAILED FOR PROCEDURE: scratch.main
define internal void @scratch.main(i8* noalias nocapture nonnull %__.context_ptr) {
decls:
  %0 = alloca [3 x void ({ i64, i8 }*, i8*)*], align 8
  %1 = alloca [3 x void ({ i64, i8 }*, i8*)*], align 8
  %2 = alloca { void ({ i64, i8 }*, i8*)**, i64 }, align 8
  br label %entry

entry:                                            ; preds = %decls
  %3 = bitcast i8* %__.context_ptr to %runtime.Context*
  %4 = bitcast [3 x void ({ i64, i8 }*, i8*)*]* %1 to i8*
  call void @llvm.memset.p0i8.i64(i8* %4, i8 0, i64 24, i1 false)
  %5 = bitcast [3 x void ({ i64, i8 }*, i8*)*]* %1 to i8**
  store i8* bitcast ([3 x void ({ i64, i8 }*, i8*)*] [void ({ i64, i8 }*, i8*)* @scratch.bar, void ({ i64, i8 }*, i8*)* @scratch.bar, void ({ i64, i8 }*, i8*)* @
scratch.bar] to i8*), i8** %5, align 8
  %6 = load [3 x void ({ i64, i8 }*, i8*)*], [3 x void ({ i64, i8 }*, i8*)*]* %1, align 8
  %7 = bitcast [3 x void ({ i64, i8 }*, i8*)*]* %0 to i8**
  %8 = bitcast [3 x void ({ i64, i8 }*, i8*)*] %6 to i8*
  store i8* %8, i8** %7, align 8
  %9 = load [3 x void ({ i64, i8 }*, i8*)*], [3 x void ({ i64, i8 }*, i8*)*]* %0, align 8
  %10 = getelementptr [3 x void ({ i64, i8 }*, i8*)*], [3 x void ({ i64, i8 }*, i8*)*]* %0, i64 0, i64 0
  %11 = getelementptr void ({ i64, i8 }*, i8*)*, void ({ i64, i8 }*, i8*)** %10, i64 0
  %12 = getelementptr inbounds { void ({ i64, i8 }*, i8*)**, i64 }, { void ({ i64, i8 }*, i8*)**, i64 }* %2, i32 0, i32 0
  %13 = bitcast void ({ i64, i8 }*, i8*)*** %12 to i8**
  %14 = bitcast void ({ i64, i8 }*, i8*)** %11 to i8*
  store i8* %14, i8** %13, align 8
  %15 = getelementptr inbounds { void ({ i64, i8 }*, i8*)**, i64 }, { void ({ i64, i8 }*, i8*)**, i64 }* %2, i32 0, i32 1
  store i64 3, i64* %15, align 8
  %16 = load { void ({ i64, i8 }*, i8*)**, i64 }, { void ({ i64, i8 }*, i8*)**, i64 }* %2, align 8
  %17 = bitcast %runtime.Context* %3 to i8*
  %18 = call i64 @scratch.foos({ void ({ i64, i8 }*, i8*)**, i64 }* %2, i8* %17)
  ret void
}

Invalid bitcast
i8* bitcast ([3 x void ({ i64, i8 }*, i8*)*] [void ({ i64, i8 }*, i8*)* @scratch.bar, void ({ i64, i8 }*, i8*)* @scratch.bar, void ({ i64, i8 }*, i8*)* @scratch.
bar] to i8*)
Invalid bitcast
  %8 = bitcast [3 x void ({ i64, i8 }*, i8*)*] %6 to i8*


Steps to Reproduce

This error happens at compile time when compiling the code above.

Failure Logs

The error message above is all I got.

tsillus avatar Apr 22 '23 01:04 tsillus

After playing around with this a bit more, wrapping each procedure into a struct does not cause that LLVM error:

proc_type :: #type proc() -> (int, bool);

dyn_procs :: struct {
    f: proc_type,
}

foos ::proc(callables: []dyn_procs) -> (int) {

    // ...
}

bar : proc_type = proc() -> (int, bool) {
    return 1, true
}

main :: proc() {

    procs := [3]dyn_procs{
        dyn_procs{bar},
        dyn_procs{bar},
        dyn_procs{bar},
    }

    foos(procs[:])
}

So the error seems to be related to arrays of procedure types and arrays of pointers to procedure types.

tsillus avatar Apr 22 '23 03:04 tsillus

I cannot replicate this bug any more.

gingerBill avatar May 18 '23 10:05 gingerBill