diff --git a/cl/_testrt/qsortfn/in.go b/cl/_testrt/qsortfn/in.go new file mode 100644 index 00000000..fb527a04 --- /dev/null +++ b/cl/_testrt/qsortfn/in.go @@ -0,0 +1,150 @@ +package main + +import ( + "unsafe" + + "github.com/goplus/llgo/c" + q "github.com/goplus/llgo/cl/internal/qsort" +) + +// llgo:type C +type Comp func(a, b c.Pointer) c.Int + +//go:linkname qsort C.qsort +func qsort(base c.Pointer, count, elem uintptr, compar Comp) + +//go:linkname qsort2 C.qsort +func qsort2(base c.Pointer, count, elem uintptr, compar func(a, b c.Pointer) c.Int) + +func main() { + sort1a() + sort1b() + sort2a() + sort2b() + sort3a() + sort3b() + sort4a() + sort4b() + sort5a() + sort5b() +} + +func sort1a() { + c.Printf(c.Str("Comp => Comp\n")) + a := [...]int{100, 8, 23, 2, 7} + var fn Comp = func(a, b c.Pointer) c.Int { + return c.Int(*(*int)(a) - *(*int)(b)) + } + qsort(c.Pointer(&a[0]), 5, unsafe.Sizeof(0), fn) + for _, v := range a { + c.Printf(c.Str("%d\n"), v) + } +} + +func sort1b() { + c.Printf(c.Str("fn => Comp\n")) + a := [...]int{100, 8, 23, 2, 7} + var fn = func(a, b c.Pointer) c.Int { + return c.Int(*(*int)(a) - *(*int)(b)) + } + qsort(c.Pointer(&a[0]), 5, unsafe.Sizeof(0), fn) + for _, v := range a { + c.Printf(c.Str("%d\n"), v) + } +} + +func sort2a() { + c.Printf(c.Str("Comp => fn\n")) + a := [...]int{100, 8, 23, 2, 7} + var fn Comp = func(a, b c.Pointer) c.Int { + return c.Int(*(*int)(a) - *(*int)(b)) + } + qsort2(c.Pointer(&a[0]), 5, unsafe.Sizeof(0), fn) + for _, v := range a { + c.Printf(c.Str("%d\n"), v) + } +} + +func sort2b() { + c.Printf(c.Str("fn => fn\n")) + a := [...]int{100, 8, 23, 2, 7} + var fn = func(a, b c.Pointer) c.Int { + return c.Int(*(*int)(a) - *(*int)(b)) + } + qsort2(c.Pointer(&a[0]), 5, unsafe.Sizeof(0), fn) + for _, v := range a { + c.Printf(c.Str("%d\n"), v) + } +} + +func sort3a() { + c.Printf(c.Str("qsort.Comp => qsort.Comp\n")) + a := [...]int{100, 8, 23, 2, 7} + var fn q.Comp = func(a, b c.Pointer) c.Int { + return c.Int(*(*int)(a) - *(*int)(b)) + } + q.Qsort(c.Pointer(&a[0]), 5, unsafe.Sizeof(0), fn) + for _, v := range a { + c.Printf(c.Str("%d\n"), v) + } +} + +func sort3b() { + c.Printf(c.Str("fn => qsort.Comp\n")) + a := [...]int{100, 8, 23, 2, 7} + var fn = func(a, b c.Pointer) c.Int { + return c.Int(*(*int)(a) - *(*int)(b)) + } + q.Qsort(c.Pointer(&a[0]), 5, unsafe.Sizeof(0), fn) + for _, v := range a { + c.Printf(c.Str("%d\n"), v) + } +} + +func sort4a() { + c.Printf(c.Str("qsort.Comp => fn\n")) + a := [...]int{100, 8, 23, 2, 7} + var fn q.Comp = func(a, b c.Pointer) c.Int { + return c.Int(*(*int)(a) - *(*int)(b)) + } + qsort2(c.Pointer(&a[0]), 5, unsafe.Sizeof(0), fn) + for _, v := range a { + c.Printf(c.Str("%d\n"), v) + } +} + +func sort4b() { + c.Printf(c.Str("Comp => qsort.fn\n")) + a := [...]int{100, 8, 23, 2, 7} + var fn Comp = func(a, b c.Pointer) c.Int { + return c.Int(*(*int)(a) - *(*int)(b)) + } + q.Qsort2(c.Pointer(&a[0]), 5, unsafe.Sizeof(0), fn) + for _, v := range a { + c.Printf(c.Str("%d\n"), v) + } +} + +func sort5a() { + c.Printf(c.Str("qsort.Comp => Comp()\n")) + a := [...]int{100, 8, 23, 2, 7} + var fn q.Comp = func(a, b c.Pointer) c.Int { + return c.Int(*(*int)(a) - *(*int)(b)) + } + qsort(c.Pointer(&a[0]), 5, unsafe.Sizeof(0), Comp(fn)) + for _, v := range a { + c.Printf(c.Str("%d\n"), v) + } +} + +func sort5b() { + c.Printf(c.Str("Comp => qsort.Comp()\n")) + a := [...]int{100, 8, 23, 2, 7} + var fn Comp = func(a, b c.Pointer) c.Int { + return c.Int(*(*int)(a) - *(*int)(b)) + } + q.Qsort(c.Pointer(&a[0]), 5, unsafe.Sizeof(0), q.Comp(fn)) + for _, v := range a { + c.Printf(c.Str("%d\n"), v) + } +} diff --git a/cl/_testrt/qsortfn/out.ll b/cl/_testrt/qsortfn/out.ll new file mode 100644 index 00000000..50d3b69e --- /dev/null +++ b/cl/_testrt/qsortfn/out.ll @@ -0,0 +1,596 @@ +; ModuleID = 'main' +source_filename = "main" + +@"main.init$guard" = global i1 false, align 1 +@__llgo_argc = global i32 0, align 4 +@__llgo_argv = global ptr null, align 8 +@0 = private unnamed_addr constant [14 x i8] c"Comp => Comp\0A\00", align 1 +@1 = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 +@2 = private unnamed_addr constant [12 x i8] c"fn => Comp\0A\00", align 1 +@3 = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 +@4 = private unnamed_addr constant [12 x i8] c"Comp => fn\0A\00", align 1 +@5 = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 +@6 = private unnamed_addr constant [10 x i8] c"fn => fn\0A\00", align 1 +@7 = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 +@8 = private unnamed_addr constant [26 x i8] c"qsort.Comp => qsort.Comp\0A\00", align 1 +@9 = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 +@10 = private unnamed_addr constant [18 x i8] c"fn => qsort.Comp\0A\00", align 1 +@11 = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 +@12 = private unnamed_addr constant [18 x i8] c"qsort.Comp => fn\0A\00", align 1 +@13 = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 +@14 = private unnamed_addr constant [18 x i8] c"Comp => qsort.fn\0A\00", align 1 +@15 = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 +@16 = private unnamed_addr constant [22 x i8] c"qsort.Comp => Comp()\0A\00", align 1 +@17 = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 +@18 = private unnamed_addr constant [22 x i8] c"Comp => qsort.Comp()\0A\00", align 1 +@19 = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 + +define void @main.init() { +_llgo_0: + %0 = load i1, ptr @"main.init$guard", align 1 + br i1 %0, label %_llgo_2, label %_llgo_1 + +_llgo_1: ; preds = %_llgo_0 + store i1 true, ptr @"main.init$guard", align 1 + br label %_llgo_2 + +_llgo_2: ; preds = %_llgo_1, %_llgo_0 + ret void +} + +define i32 @main(i32 %0, ptr %1) { +_llgo_0: + store i32 %0, ptr @__llgo_argc, align 4 + store ptr %1, ptr @__llgo_argv, align 8 + call void @"github.com/goplus/llgo/internal/runtime.init"() + call void @main.init() + call void @main.sort1a() + call void @main.sort1b() + call void @main.sort2a() + call void @main.sort2b() + call void @main.sort3a() + call void @main.sort3b() + call void @main.sort4a() + call void @main.sort4b() + call void @main.sort5a() + call void @main.sort5b() + ret i32 0 +} + +define void @main.sort1a() { +_llgo_0: + %0 = call i32 (ptr, ...) @printf(ptr @0) + %1 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 40) + %2 = getelementptr inbounds i64, ptr %1, i64 0 + %3 = getelementptr inbounds i64, ptr %1, i64 1 + %4 = getelementptr inbounds i64, ptr %1, i64 2 + %5 = getelementptr inbounds i64, ptr %1, i64 3 + %6 = getelementptr inbounds i64, ptr %1, i64 4 + store i64 100, ptr %2, align 4 + store i64 8, ptr %3, align 4 + store i64 23, ptr %4, align 4 + store i64 2, ptr %5, align 4 + store i64 7, ptr %6, align 4 + %7 = getelementptr inbounds i64, ptr %1, i64 0 + call void @qsort(ptr %7, i64 5, i64 8, ptr @"main.sort1a$1") + %8 = load [5 x i64], ptr %1, align 4 + br label %_llgo_1 + +_llgo_1: ; preds = %_llgo_2, %_llgo_0 + %9 = phi i64 [ -1, %_llgo_0 ], [ %10, %_llgo_2 ] + %10 = add i64 %9, 1 + %11 = icmp slt i64 %10, 5 + br i1 %11, label %_llgo_2, label %_llgo_3 + +_llgo_2: ; preds = %_llgo_1 + %12 = icmp slt i64 %10, 0 + %13 = icmp sge i64 %10, 5 + %14 = or i1 %13, %12 + call void @"github.com/goplus/llgo/internal/runtime.AssertIndexRange"(i1 %14) + %15 = getelementptr inbounds i64, ptr %1, i64 %10 + %16 = load i64, ptr %15, align 4 + %17 = call i32 (ptr, ...) @printf(ptr @1, i64 %16) + br label %_llgo_1 + +_llgo_3: ; preds = %_llgo_1 + ret void +} + +define i32 @"main.sort1a$1"(ptr %0, ptr %1) { +_llgo_0: + %2 = load i64, ptr %0, align 4 + %3 = load i64, ptr %1, align 4 + %4 = sub i64 %2, %3 + %5 = trunc i64 %4 to i32 + ret i32 %5 +} + +define void @main.sort1b() { +_llgo_0: + %0 = call i32 (ptr, ...) @printf(ptr @2) + %1 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 40) + %2 = getelementptr inbounds i64, ptr %1, i64 0 + %3 = getelementptr inbounds i64, ptr %1, i64 1 + %4 = getelementptr inbounds i64, ptr %1, i64 2 + %5 = getelementptr inbounds i64, ptr %1, i64 3 + %6 = getelementptr inbounds i64, ptr %1, i64 4 + store i64 100, ptr %2, align 4 + store i64 8, ptr %3, align 4 + store i64 23, ptr %4, align 4 + store i64 2, ptr %5, align 4 + store i64 7, ptr %6, align 4 + %7 = getelementptr inbounds i64, ptr %1, i64 0 + call void @qsort(ptr %7, i64 5, i64 8, ptr @"main.sort1b$1") + %8 = load [5 x i64], ptr %1, align 4 + br label %_llgo_1 + +_llgo_1: ; preds = %_llgo_2, %_llgo_0 + %9 = phi i64 [ -1, %_llgo_0 ], [ %10, %_llgo_2 ] + %10 = add i64 %9, 1 + %11 = icmp slt i64 %10, 5 + br i1 %11, label %_llgo_2, label %_llgo_3 + +_llgo_2: ; preds = %_llgo_1 + %12 = icmp slt i64 %10, 0 + %13 = icmp sge i64 %10, 5 + %14 = or i1 %13, %12 + call void @"github.com/goplus/llgo/internal/runtime.AssertIndexRange"(i1 %14) + %15 = getelementptr inbounds i64, ptr %1, i64 %10 + %16 = load i64, ptr %15, align 4 + %17 = call i32 (ptr, ...) @printf(ptr @3, i64 %16) + br label %_llgo_1 + +_llgo_3: ; preds = %_llgo_1 + ret void +} + +define i32 @"main.sort1b$1"(ptr %0, ptr %1) { +_llgo_0: + %2 = load i64, ptr %0, align 4 + %3 = load i64, ptr %1, align 4 + %4 = sub i64 %2, %3 + %5 = trunc i64 %4 to i32 + ret i32 %5 +} + +define void @main.sort2a() { +_llgo_0: + %0 = call i32 (ptr, ...) @printf(ptr @4) + %1 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 40) + %2 = getelementptr inbounds i64, ptr %1, i64 0 + %3 = getelementptr inbounds i64, ptr %1, i64 1 + %4 = getelementptr inbounds i64, ptr %1, i64 2 + %5 = getelementptr inbounds i64, ptr %1, i64 3 + %6 = getelementptr inbounds i64, ptr %1, i64 4 + store i64 100, ptr %2, align 4 + store i64 8, ptr %3, align 4 + store i64 23, ptr %4, align 4 + store i64 2, ptr %5, align 4 + store i64 7, ptr %6, align 4 + %7 = getelementptr inbounds i64, ptr %1, i64 0 + call void @qsort(ptr %7, i64 5, i64 8, ptr @"main.sort2a$1") + %8 = load [5 x i64], ptr %1, align 4 + br label %_llgo_1 + +_llgo_1: ; preds = %_llgo_2, %_llgo_0 + %9 = phi i64 [ -1, %_llgo_0 ], [ %10, %_llgo_2 ] + %10 = add i64 %9, 1 + %11 = icmp slt i64 %10, 5 + br i1 %11, label %_llgo_2, label %_llgo_3 + +_llgo_2: ; preds = %_llgo_1 + %12 = icmp slt i64 %10, 0 + %13 = icmp sge i64 %10, 5 + %14 = or i1 %13, %12 + call void @"github.com/goplus/llgo/internal/runtime.AssertIndexRange"(i1 %14) + %15 = getelementptr inbounds i64, ptr %1, i64 %10 + %16 = load i64, ptr %15, align 4 + %17 = call i32 (ptr, ...) @printf(ptr @5, i64 %16) + br label %_llgo_1 + +_llgo_3: ; preds = %_llgo_1 + ret void +} + +define i32 @"main.sort2a$1"(ptr %0, ptr %1) { +_llgo_0: + %2 = load i64, ptr %0, align 4 + %3 = load i64, ptr %1, align 4 + %4 = sub i64 %2, %3 + %5 = trunc i64 %4 to i32 + ret i32 %5 +} + +define void @main.sort2b() { +_llgo_0: + %0 = call i32 (ptr, ...) @printf(ptr @6) + %1 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 40) + %2 = getelementptr inbounds i64, ptr %1, i64 0 + %3 = getelementptr inbounds i64, ptr %1, i64 1 + %4 = getelementptr inbounds i64, ptr %1, i64 2 + %5 = getelementptr inbounds i64, ptr %1, i64 3 + %6 = getelementptr inbounds i64, ptr %1, i64 4 + store i64 100, ptr %2, align 4 + store i64 8, ptr %3, align 4 + store i64 23, ptr %4, align 4 + store i64 2, ptr %5, align 4 + store i64 7, ptr %6, align 4 + %7 = getelementptr inbounds i64, ptr %1, i64 0 + call void @qsort(ptr %7, i64 5, i64 8, ptr @"main.sort2b$1") + %8 = load [5 x i64], ptr %1, align 4 + br label %_llgo_1 + +_llgo_1: ; preds = %_llgo_2, %_llgo_0 + %9 = phi i64 [ -1, %_llgo_0 ], [ %10, %_llgo_2 ] + %10 = add i64 %9, 1 + %11 = icmp slt i64 %10, 5 + br i1 %11, label %_llgo_2, label %_llgo_3 + +_llgo_2: ; preds = %_llgo_1 + %12 = icmp slt i64 %10, 0 + %13 = icmp sge i64 %10, 5 + %14 = or i1 %13, %12 + call void @"github.com/goplus/llgo/internal/runtime.AssertIndexRange"(i1 %14) + %15 = getelementptr inbounds i64, ptr %1, i64 %10 + %16 = load i64, ptr %15, align 4 + %17 = call i32 (ptr, ...) @printf(ptr @7, i64 %16) + br label %_llgo_1 + +_llgo_3: ; preds = %_llgo_1 + ret void +} + +define i32 @"main.sort2b$1"(ptr %0, ptr %1) { +_llgo_0: + %2 = load i64, ptr %0, align 4 + %3 = load i64, ptr %1, align 4 + %4 = sub i64 %2, %3 + %5 = trunc i64 %4 to i32 + ret i32 %5 +} + +define void @main.sort3a() { +_llgo_0: + %0 = call i32 (ptr, ...) @printf(ptr @8) + %1 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 40) + %2 = getelementptr inbounds i64, ptr %1, i64 0 + %3 = getelementptr inbounds i64, ptr %1, i64 1 + %4 = getelementptr inbounds i64, ptr %1, i64 2 + %5 = getelementptr inbounds i64, ptr %1, i64 3 + %6 = getelementptr inbounds i64, ptr %1, i64 4 + store i64 100, ptr %2, align 4 + store i64 8, ptr %3, align 4 + store i64 23, ptr %4, align 4 + store i64 2, ptr %5, align 4 + store i64 7, ptr %6, align 4 + %7 = alloca { ptr, ptr }, align 8 + %8 = getelementptr inbounds { ptr, ptr }, ptr %7, i32 0, i32 0 + store ptr @"__llgo_stub.main.sort3a$1", ptr %8, align 8 + %9 = getelementptr inbounds { ptr, ptr }, ptr %7, i32 0, i32 1 + store ptr null, ptr %9, align 8 + %10 = load { ptr, ptr }, ptr %7, align 8 + %11 = getelementptr inbounds i64, ptr %1, i64 0 + call void @qsort(ptr %11, i64 5, i64 8, { ptr, ptr } %10) + %12 = load [5 x i64], ptr %1, align 4 + br label %_llgo_1 + +_llgo_1: ; preds = %_llgo_2, %_llgo_0 + %13 = phi i64 [ -1, %_llgo_0 ], [ %14, %_llgo_2 ] + %14 = add i64 %13, 1 + %15 = icmp slt i64 %14, 5 + br i1 %15, label %_llgo_2, label %_llgo_3 + +_llgo_2: ; preds = %_llgo_1 + %16 = icmp slt i64 %14, 0 + %17 = icmp sge i64 %14, 5 + %18 = or i1 %17, %16 + call void @"github.com/goplus/llgo/internal/runtime.AssertIndexRange"(i1 %18) + %19 = getelementptr inbounds i64, ptr %1, i64 %14 + %20 = load i64, ptr %19, align 4 + %21 = call i32 (ptr, ...) @printf(ptr @9, i64 %20) + br label %_llgo_1 + +_llgo_3: ; preds = %_llgo_1 + ret void +} + +define i32 @"main.sort3a$1"(ptr %0, ptr %1) { +_llgo_0: + %2 = load i64, ptr %0, align 4 + %3 = load i64, ptr %1, align 4 + %4 = sub i64 %2, %3 + %5 = trunc i64 %4 to i32 + ret i32 %5 +} + +define void @main.sort3b() { +_llgo_0: + %0 = call i32 (ptr, ...) @printf(ptr @10) + %1 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 40) + %2 = getelementptr inbounds i64, ptr %1, i64 0 + %3 = getelementptr inbounds i64, ptr %1, i64 1 + %4 = getelementptr inbounds i64, ptr %1, i64 2 + %5 = getelementptr inbounds i64, ptr %1, i64 3 + %6 = getelementptr inbounds i64, ptr %1, i64 4 + store i64 100, ptr %2, align 4 + store i64 8, ptr %3, align 4 + store i64 23, ptr %4, align 4 + store i64 2, ptr %5, align 4 + store i64 7, ptr %6, align 4 + %7 = getelementptr inbounds i64, ptr %1, i64 0 + %8 = alloca { ptr, ptr }, align 8 + %9 = getelementptr inbounds { ptr, ptr }, ptr %8, i32 0, i32 0 + store ptr @"__llgo_stub.main.sort3b$1", ptr %9, align 8 + %10 = getelementptr inbounds { ptr, ptr }, ptr %8, i32 0, i32 1 + store ptr null, ptr %10, align 8 + %11 = load { ptr, ptr }, ptr %8, align 8 + call void @qsort(ptr %7, i64 5, i64 8, { ptr, ptr } %11) + %12 = load [5 x i64], ptr %1, align 4 + br label %_llgo_1 + +_llgo_1: ; preds = %_llgo_2, %_llgo_0 + %13 = phi i64 [ -1, %_llgo_0 ], [ %14, %_llgo_2 ] + %14 = add i64 %13, 1 + %15 = icmp slt i64 %14, 5 + br i1 %15, label %_llgo_2, label %_llgo_3 + +_llgo_2: ; preds = %_llgo_1 + %16 = icmp slt i64 %14, 0 + %17 = icmp sge i64 %14, 5 + %18 = or i1 %17, %16 + call void @"github.com/goplus/llgo/internal/runtime.AssertIndexRange"(i1 %18) + %19 = getelementptr inbounds i64, ptr %1, i64 %14 + %20 = load i64, ptr %19, align 4 + %21 = call i32 (ptr, ...) @printf(ptr @11, i64 %20) + br label %_llgo_1 + +_llgo_3: ; preds = %_llgo_1 + ret void +} + +define i32 @"main.sort3b$1"(ptr %0, ptr %1) { +_llgo_0: + %2 = load i64, ptr %0, align 4 + %3 = load i64, ptr %1, align 4 + %4 = sub i64 %2, %3 + %5 = trunc i64 %4 to i32 + ret i32 %5 +} + +define void @main.sort4a() { +_llgo_0: + %0 = call i32 (ptr, ...) @printf(ptr @12) + %1 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 40) + %2 = getelementptr inbounds i64, ptr %1, i64 0 + %3 = getelementptr inbounds i64, ptr %1, i64 1 + %4 = getelementptr inbounds i64, ptr %1, i64 2 + %5 = getelementptr inbounds i64, ptr %1, i64 3 + %6 = getelementptr inbounds i64, ptr %1, i64 4 + store i64 100, ptr %2, align 4 + store i64 8, ptr %3, align 4 + store i64 23, ptr %4, align 4 + store i64 2, ptr %5, align 4 + store i64 7, ptr %6, align 4 + %7 = alloca { ptr, ptr }, align 8 + %8 = getelementptr inbounds { ptr, ptr }, ptr %7, i32 0, i32 0 + store ptr @"__llgo_stub.main.sort4a$1", ptr %8, align 8 + %9 = getelementptr inbounds { ptr, ptr }, ptr %7, i32 0, i32 1 + store ptr null, ptr %9, align 8 + %10 = load { ptr, ptr }, ptr %7, align 8 + %11 = getelementptr inbounds i64, ptr %1, i64 0 + call void @qsort(ptr %11, i64 5, i64 8, { ptr, ptr } %10) + %12 = load [5 x i64], ptr %1, align 4 + br label %_llgo_1 + +_llgo_1: ; preds = %_llgo_2, %_llgo_0 + %13 = phi i64 [ -1, %_llgo_0 ], [ %14, %_llgo_2 ] + %14 = add i64 %13, 1 + %15 = icmp slt i64 %14, 5 + br i1 %15, label %_llgo_2, label %_llgo_3 + +_llgo_2: ; preds = %_llgo_1 + %16 = icmp slt i64 %14, 0 + %17 = icmp sge i64 %14, 5 + %18 = or i1 %17, %16 + call void @"github.com/goplus/llgo/internal/runtime.AssertIndexRange"(i1 %18) + %19 = getelementptr inbounds i64, ptr %1, i64 %14 + %20 = load i64, ptr %19, align 4 + %21 = call i32 (ptr, ...) @printf(ptr @13, i64 %20) + br label %_llgo_1 + +_llgo_3: ; preds = %_llgo_1 + ret void +} + +define i32 @"main.sort4a$1"(ptr %0, ptr %1) { +_llgo_0: + %2 = load i64, ptr %0, align 4 + %3 = load i64, ptr %1, align 4 + %4 = sub i64 %2, %3 + %5 = trunc i64 %4 to i32 + ret i32 %5 +} + +define void @main.sort4b() { +_llgo_0: + %0 = call i32 (ptr, ...) @printf(ptr @14) + %1 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 40) + %2 = getelementptr inbounds i64, ptr %1, i64 0 + %3 = getelementptr inbounds i64, ptr %1, i64 1 + %4 = getelementptr inbounds i64, ptr %1, i64 2 + %5 = getelementptr inbounds i64, ptr %1, i64 3 + %6 = getelementptr inbounds i64, ptr %1, i64 4 + store i64 100, ptr %2, align 4 + store i64 8, ptr %3, align 4 + store i64 23, ptr %4, align 4 + store i64 2, ptr %5, align 4 + store i64 7, ptr %6, align 4 + %7 = getelementptr inbounds i64, ptr %1, i64 0 + call void @qsort(ptr %7, i64 5, i64 8, ptr @"main.sort4b$1") + %8 = load [5 x i64], ptr %1, align 4 + br label %_llgo_1 + +_llgo_1: ; preds = %_llgo_2, %_llgo_0 + %9 = phi i64 [ -1, %_llgo_0 ], [ %10, %_llgo_2 ] + %10 = add i64 %9, 1 + %11 = icmp slt i64 %10, 5 + br i1 %11, label %_llgo_2, label %_llgo_3 + +_llgo_2: ; preds = %_llgo_1 + %12 = icmp slt i64 %10, 0 + %13 = icmp sge i64 %10, 5 + %14 = or i1 %13, %12 + call void @"github.com/goplus/llgo/internal/runtime.AssertIndexRange"(i1 %14) + %15 = getelementptr inbounds i64, ptr %1, i64 %10 + %16 = load i64, ptr %15, align 4 + %17 = call i32 (ptr, ...) @printf(ptr @15, i64 %16) + br label %_llgo_1 + +_llgo_3: ; preds = %_llgo_1 + ret void +} + +define i32 @"main.sort4b$1"(ptr %0, ptr %1) { +_llgo_0: + %2 = load i64, ptr %0, align 4 + %3 = load i64, ptr %1, align 4 + %4 = sub i64 %2, %3 + %5 = trunc i64 %4 to i32 + ret i32 %5 +} + +define void @main.sort5a() { +_llgo_0: + %0 = call i32 (ptr, ...) @printf(ptr @16) + %1 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 40) + %2 = getelementptr inbounds i64, ptr %1, i64 0 + %3 = getelementptr inbounds i64, ptr %1, i64 1 + %4 = getelementptr inbounds i64, ptr %1, i64 2 + %5 = getelementptr inbounds i64, ptr %1, i64 3 + %6 = getelementptr inbounds i64, ptr %1, i64 4 + store i64 100, ptr %2, align 4 + store i64 8, ptr %3, align 4 + store i64 23, ptr %4, align 4 + store i64 2, ptr %5, align 4 + store i64 7, ptr %6, align 4 + %7 = alloca { ptr, ptr }, align 8 + %8 = getelementptr inbounds { ptr, ptr }, ptr %7, i32 0, i32 0 + store ptr @"__llgo_stub.main.sort5a$1", ptr %8, align 8 + %9 = getelementptr inbounds { ptr, ptr }, ptr %7, i32 0, i32 1 + store ptr null, ptr %9, align 8 + %10 = load { ptr, ptr }, ptr %7, align 8 + %11 = getelementptr inbounds i64, ptr %1, i64 0 + call void @qsort(ptr %11, i64 5, i64 8, { ptr, ptr } %10) + %12 = load [5 x i64], ptr %1, align 4 + br label %_llgo_1 + +_llgo_1: ; preds = %_llgo_2, %_llgo_0 + %13 = phi i64 [ -1, %_llgo_0 ], [ %14, %_llgo_2 ] + %14 = add i64 %13, 1 + %15 = icmp slt i64 %14, 5 + br i1 %15, label %_llgo_2, label %_llgo_3 + +_llgo_2: ; preds = %_llgo_1 + %16 = icmp slt i64 %14, 0 + %17 = icmp sge i64 %14, 5 + %18 = or i1 %17, %16 + call void @"github.com/goplus/llgo/internal/runtime.AssertIndexRange"(i1 %18) + %19 = getelementptr inbounds i64, ptr %1, i64 %14 + %20 = load i64, ptr %19, align 4 + %21 = call i32 (ptr, ...) @printf(ptr @17, i64 %20) + br label %_llgo_1 + +_llgo_3: ; preds = %_llgo_1 + ret void +} + +define i32 @"main.sort5a$1"(ptr %0, ptr %1) { +_llgo_0: + %2 = load i64, ptr %0, align 4 + %3 = load i64, ptr %1, align 4 + %4 = sub i64 %2, %3 + %5 = trunc i64 %4 to i32 + ret i32 %5 +} + +define void @main.sort5b() { +_llgo_0: + %0 = call i32 (ptr, ...) @printf(ptr @18) + %1 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 40) + %2 = getelementptr inbounds i64, ptr %1, i64 0 + %3 = getelementptr inbounds i64, ptr %1, i64 1 + %4 = getelementptr inbounds i64, ptr %1, i64 2 + %5 = getelementptr inbounds i64, ptr %1, i64 3 + %6 = getelementptr inbounds i64, ptr %1, i64 4 + store i64 100, ptr %2, align 4 + store i64 8, ptr %3, align 4 + store i64 23, ptr %4, align 4 + store i64 2, ptr %5, align 4 + store i64 7, ptr %6, align 4 + %7 = getelementptr inbounds i64, ptr %1, i64 0 + call void @qsort(ptr %7, i64 5, i64 8, ptr @"main.sort5b$1") + %8 = load [5 x i64], ptr %1, align 4 + br label %_llgo_1 + +_llgo_1: ; preds = %_llgo_2, %_llgo_0 + %9 = phi i64 [ -1, %_llgo_0 ], [ %10, %_llgo_2 ] + %10 = add i64 %9, 1 + %11 = icmp slt i64 %10, 5 + br i1 %11, label %_llgo_2, label %_llgo_3 + +_llgo_2: ; preds = %_llgo_1 + %12 = icmp slt i64 %10, 0 + %13 = icmp sge i64 %10, 5 + %14 = or i1 %13, %12 + call void @"github.com/goplus/llgo/internal/runtime.AssertIndexRange"(i1 %14) + %15 = getelementptr inbounds i64, ptr %1, i64 %10 + %16 = load i64, ptr %15, align 4 + %17 = call i32 (ptr, ...) @printf(ptr @19, i64 %16) + br label %_llgo_1 + +_llgo_3: ; preds = %_llgo_1 + ret void +} + +define i32 @"main.sort5b$1"(ptr %0, ptr %1) { +_llgo_0: + %2 = load i64, ptr %0, align 4 + %3 = load i64, ptr %1, align 4 + %4 = sub i64 %2, %3 + %5 = trunc i64 %4 to i32 + ret i32 %5 +} + +declare void @"github.com/goplus/llgo/internal/runtime.init"() + +declare i32 @printf(ptr, ...) + +declare ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64) + +declare void @qsort(ptr, i64, i64, ptr) + +declare void @"github.com/goplus/llgo/internal/runtime.AssertIndexRange"(i1) + +define linkonce i32 @"__llgo_stub.main.sort3a$1"(ptr %0, ptr %1, ptr %2) { +_llgo_0: + %3 = tail call i32 @"main.sort3a$1"(ptr %1, ptr %2) + ret i32 %3 +} + +define linkonce i32 @"__llgo_stub.main.sort3b$1"(ptr %0, ptr %1, ptr %2) { +_llgo_0: + %3 = tail call i32 @"main.sort3b$1"(ptr %1, ptr %2) + ret i32 %3 +} + +define linkonce i32 @"__llgo_stub.main.sort4a$1"(ptr %0, ptr %1, ptr %2) { +_llgo_0: + %3 = tail call i32 @"main.sort4a$1"(ptr %1, ptr %2) + ret i32 %3 +} + +define linkonce i32 @"__llgo_stub.main.sort5a$1"(ptr %0, ptr %1, ptr %2) { +_llgo_0: + %3 = tail call i32 @"main.sort5a$1"(ptr %1, ptr %2) + ret i32 %3 +} diff --git a/cl/import.go b/cl/import.go index 36597b28..aa09ba60 100644 --- a/cl/import.go +++ b/cl/import.go @@ -196,6 +196,15 @@ func (p *context) initFiles(pkgPath string, files []*ast.File) { p.collectSkipNames(line) } } + case token.TYPE: + if len(decl.Specs) == 1 { + if hasTypec(decl.Doc) { + inPkgName := decl.Specs[0].(*ast.TypeSpec).Name.Name + if obj := p.goTyps.Scope().Lookup(inPkgName); obj != nil { + p.prog.Type(obj.Type(), llssa.InC) + } + } + } } } } @@ -544,4 +553,43 @@ func (p *context) initPyModule() { } } +// ParsePkgSyntax: check llgo:type C +func ParsePkgSyntax(prog llssa.Program, pkg *types.Package, files []*ast.File) { + for _, file := range files { + for _, decl := range file.Decls { + switch decl := decl.(type) { + case *ast.GenDecl: + switch decl.Tok { + case token.TYPE: + if len(decl.Specs) == 1 { + if hasTypec(decl.Doc) { + inPkgName := decl.Specs[0].(*ast.TypeSpec).Name.Name + if obj := pkg.Scope().Lookup(inPkgName); obj != nil { + prog.Type(obj.Type(), llssa.InC) + } + } + } + } + } + } + } +} + +const ( + llgotypec = "//llgo:type C" + llgotypec2 = "// llgo:type C" +) + +func hasTypec(doc *ast.CommentGroup) bool { + if doc != nil { + if n := len(doc.List); n > 0 { + line := doc.List[n-1].Text + if strings.HasPrefix(line, llgotypec) || strings.HasPrefix(line, llgotypec2) { + return true + } + } + } + return false +} + // ----------------------------------------------------------------------------- diff --git a/cl/internal/qsort/qsort.go b/cl/internal/qsort/qsort.go new file mode 100644 index 00000000..394066ce --- /dev/null +++ b/cl/internal/qsort/qsort.go @@ -0,0 +1,20 @@ +package qsort + +import ( + _ "unsafe" + + "github.com/goplus/llgo/c" +) + +const ( + LLGoPackage = "decl" +) + +// llgo:type C +type Comp func(a, b c.Pointer) c.Int + +//go:linkname Qsort C.qsort +func Qsort(base c.Pointer, count, elem uintptr, compar Comp) + +//go:linkname Qsort2 C.qsort +func Qsort2(base c.Pointer, count, elem uintptr, compar func(a, b c.Pointer) c.Int) diff --git a/internal/build/build.go b/internal/build/build.go index 3d2d5241..0b06e549 100644 --- a/internal/build/build.go +++ b/internal/build/build.go @@ -247,10 +247,12 @@ func buildAllPkgs(ctx *context, initial []*packages.Package, verbose bool) (pkgs continue } built[pkg.PkgPath] = none{} + //parsePkg(ctx, aPkg, verbose) switch kind, param := cl.PkgKindOf(pkg.Types); kind { case cl.PkgDeclOnly: // skip packages that only contain declarations // and set no export file + cl.ParsePkgSyntax(ctx.prog, pkg.Types, pkg.Syntax) pkg.ExportFile = "" case cl.PkgLinkIR, cl.PkgLinkExtern, cl.PkgPyModule: if isPkgInLLGo(pkg.PkgPath) { @@ -427,6 +429,7 @@ func buildPkg(ctx *context, aPkg *aPackage, verbose bool) { llssa.SetDebug(llssa.DbgFlagAll) cl.SetDebug(cl.DbgFlagAll) } + ret, err := cl.NewPackageEx(ctx.prog, ctx.patches, aPkg.SSA, syntax) if showDetail { llssa.SetDebug(0) diff --git a/ssa/expr.go b/ssa/expr.go index 2aed82c3..bf9d8e0b 100644 --- a/ssa/expr.go +++ b/ssa/expr.go @@ -704,11 +704,9 @@ func (b Builder) ChangeType(t Type, x Expr) (ret Expr) { if debugInstr { log.Printf("ChangeType %v, %v\n", t.RawType(), x.impl) } - typ := t.raw.Type - switch t.kind { - case vkClosure: - ret.impl = checkExpr(x, typ.Underlying(), b).impl - default: + if t.kind == vkClosure && x.kind == vkFuncDecl { + ret.impl = checkExpr(x, t.raw.Type.Underlying(), b).impl + } else { ret.impl = x.impl } ret.Type = t @@ -946,7 +944,7 @@ func (b Builder) Call(fn Expr, args ...Expr) (ret Expr) { raw = fn.raw.Type fallthrough case vkFuncPtr: - sig = raw.(*types.Signature) + sig = raw.Underlying().(*types.Signature) ll = b.Prog.FuncDecl(sig, InC).ll case vkFuncDecl: sig = raw.(*types.Signature)