Merge pull request #261 from xushiwei/q

defer support; llgo/ssa: IfThen/RunDefers/EndBuild
This commit is contained in:
xushiwei
2024-06-03 01:35:33 +08:00
committed by GitHub
25 changed files with 682 additions and 109 deletions

View File

@@ -85,7 +85,7 @@ _llgo_0:
_llgo_1: ; preds = %_llgo_0 _llgo_1: ; preds = %_llgo_0
store i1 true, ptr @"main.init$guard", align 1 store i1 true, ptr @"main.init$guard", align 1
call void @"main.init$abi"() call void @"main.init$after"()
store i64 0, ptr @main.minhexdigits, align 4 store i64 0, ptr @main.minhexdigits, align 4
br label %_llgo_2 br label %_llgo_2
@@ -1412,7 +1412,7 @@ declare i32 @printf(ptr, ...)
declare void @"github.com/goplus/llgo/internal/runtime.init"() declare void @"github.com/goplus/llgo/internal/runtime.init"()
define void @"main.init$abi"() { define void @"main.init$after"() {
_llgo_0: _llgo_0:
%0 = load ptr, ptr @_llgo_float32, align 8 %0 = load ptr, ptr @_llgo_float32, align 8
%1 = icmp eq ptr %0, null %1 = icmp eq ptr %0, null

View File

@@ -19,7 +19,7 @@ _llgo_0:
_llgo_1: ; preds = %_llgo_0 _llgo_1: ; preds = %_llgo_0
store i1 true, ptr @"main.init$guard", align 1 store i1 true, ptr @"main.init$guard", align 1
call void @"main.init$abi"() call void @"main.init$after"()
br label %_llgo_2 br label %_llgo_2
_llgo_2: ; preds = %_llgo_1, %_llgo_0 _llgo_2: ; preds = %_llgo_1, %_llgo_0
@@ -118,7 +118,7 @@ declare void @"github.com/goplus/llgo/internal/runtime.init"()
declare ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64) declare ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64)
define void @"main.init$abi"() { define void @"main.init$after"() {
_llgo_0: _llgo_0:
%0 = load ptr, ptr @_llgo_int, align 8 %0 = load ptr, ptr @_llgo_int, align 8
%1 = icmp eq ptr %0, null %1 = icmp eq ptr %0, null

18
cl/_testgo/defer/in.go Normal file
View File

@@ -0,0 +1,18 @@
package main
func f(s string) bool {
return len(s) > 2
}
func main() {
defer func() {
println("hi")
}()
if s := "hello"; f(s) {
defer println(s)
} else {
defer println("world")
return
}
defer println("bye")
}

199
cl/_testgo/defer/out.ll Normal file
View File

@@ -0,0 +1,199 @@
; ModuleID = 'main'
source_filename = "main"
%"github.com/goplus/llgo/internal/runtime.String" = type { ptr, i64 }
%"github.com/goplus/llgo/internal/runtime.Defer" = type { { ptr, ptr }, i64, ptr, i64 }
@"main.init$guard" = global ptr null
@__llgo_argc = global ptr null
@__llgo_argv = global ptr null
@__llgo_defer = linkonce global ptr null
@0 = private unnamed_addr constant [6 x i8] c"hello\00", align 1
@1 = private unnamed_addr constant [6 x i8] c"hello\00", align 1
@2 = private unnamed_addr constant [4 x i8] c"bye\00", align 1
@3 = private unnamed_addr constant [6 x i8] c"world\00", align 1
@4 = private unnamed_addr constant [3 x i8] c"hi\00", align 1
define i1 @main.f(%"github.com/goplus/llgo/internal/runtime.String" %0) {
_llgo_0:
%1 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %0, 1
%2 = icmp sgt i64 %1, 2
ret i1 %2
}
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
call void @"main.init$after"()
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()
%2 = load ptr, ptr @__llgo_defer, align 8
%3 = call ptr @pthread_getspecific(ptr %2)
%4 = alloca i8, i64 40, align 1
%5 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Defer", ptr %4, i32 0, i32 0
store ptr null, ptr %5, align 8
%6 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Defer", ptr %4, i32 0, i32 1
store i64 0, ptr %6, align 4
%7 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Defer", ptr %4, i32 0, i32 2
store ptr %3, ptr %7, align 8
%8 = call i32 @pthread_setspecific(ptr %2, ptr %4)
%9 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Defer", ptr %4, i32 0, i32 1
%10 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Defer", ptr %4, i32 0, i32 3
%11 = load i64, ptr %9, align 4
%12 = or i64 %11, 1
store i64 %12, ptr %9, align 4
%13 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
%14 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %13, i32 0, i32 0
store ptr @0, ptr %14, align 8
%15 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %13, i32 0, i32 1
store i64 5, ptr %15, align 4
%16 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %13, align 8
%17 = call i1 @main.f(%"github.com/goplus/llgo/internal/runtime.String" %16)
br i1 %17, label %_llgo_2, label %_llgo_3
_llgo_1: ; No predecessors!
ret i32 0
_llgo_2: ; preds = %_llgo_0
%18 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
%19 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %18, i32 0, i32 0
store ptr @1, ptr %19, align 8
%20 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %18, i32 0, i32 1
store i64 5, ptr %20, align 4
%21 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %18, align 8
%22 = load i64, ptr %9, align 4
%23 = or i64 %22, 2
store i64 %23, ptr %9, align 4
%24 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
%25 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %24, i32 0, i32 0
store ptr @2, ptr %25, align 8
%26 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %24, i32 0, i32 1
store i64 3, ptr %26, align 4
%27 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %24, align 8
%28 = load i64, ptr %9, align 4
%29 = or i64 %28, 4
store i64 %29, ptr %9, align 4
store i64 0, ptr %10, align 4
br label %_llgo_4
_llgo_3: ; preds = %_llgo_0
%30 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
%31 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %30, i32 0, i32 0
store ptr @3, ptr %31, align 8
%32 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %30, i32 0, i32 1
store i64 5, ptr %32, align 4
%33 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %30, align 8
%34 = load i64, ptr %9, align 4
%35 = or i64 %34, 8
store i64 %35, ptr %9, align 4
store i64 1, ptr %10, align 4
br label %_llgo_4
_llgo_4: ; preds = %_llgo_3, %_llgo_2
%36 = load i64, ptr %9, align 4
%37 = and i64 %36, 8
%38 = icmp ne i64 %37, 0
br i1 %38, label %_llgo_7, label %_llgo_8
_llgo_5: ; preds = %_llgo_14
ret i32 0
_llgo_6: ; preds = %_llgo_14
ret i32 0
_llgo_7: ; preds = %_llgo_4
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %33)
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10)
br label %_llgo_8
_llgo_8: ; preds = %_llgo_7, %_llgo_4
%39 = and i64 %36, 4
%40 = icmp ne i64 %39, 0
br i1 %40, label %_llgo_9, label %_llgo_10
_llgo_9: ; preds = %_llgo_8
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %27)
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10)
br label %_llgo_10
_llgo_10: ; preds = %_llgo_9, %_llgo_8
%41 = and i64 %36, 2
%42 = icmp ne i64 %41, 0
br i1 %42, label %_llgo_11, label %_llgo_12
_llgo_11: ; preds = %_llgo_10
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %21)
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10)
br label %_llgo_12
_llgo_12: ; preds = %_llgo_11, %_llgo_10
%43 = and i64 %36, 1
%44 = icmp ne i64 %43, 0
br i1 %44, label %_llgo_13, label %_llgo_14
_llgo_13: ; preds = %_llgo_12
call void @"main.main$1"()
br label %_llgo_14
_llgo_14: ; preds = %_llgo_13, %_llgo_12
%45 = load %"github.com/goplus/llgo/internal/runtime.Defer", ptr %4, align 8
%46 = extractvalue %"github.com/goplus/llgo/internal/runtime.Defer" %45, 2
%47 = call i32 @pthread_setspecific(ptr %2, ptr %46)
%48 = load i64, ptr %10, align 4
switch i64 %48, label %_llgo_5 [
i64 1, label %_llgo_6
]
}
declare void @"github.com/goplus/llgo/internal/runtime.init"()
define void @"main.main$1"() {
_llgo_0:
%0 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %0, i32 0, i32 0
store ptr @4, ptr %1, align 8
%2 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %0, i32 0, i32 1
store i64 2, ptr %2, align 4
%3 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %0, align 8
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %3)
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10)
ret void
}
declare ptr @pthread_getspecific(i32)
declare i32 @pthread_setspecific(i32, ptr)
declare void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String")
declare void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8)
define void @"main.init$after"() {
_llgo_0:
%0 = load ptr, ptr @__llgo_defer, align 8
%1 = icmp eq ptr %0, null
br i1 %1, label %_llgo_1, label %_llgo_2
_llgo_1: ; preds = %_llgo_0
%2 = call i32 @pthread_key_create(ptr @__llgo_defer, ptr null)
br label %_llgo_2
_llgo_2: ; preds = %_llgo_1, %_llgo_0
ret void
}
declare i32 @pthread_key_create(ptr, ptr)

View File

@@ -60,7 +60,7 @@ _llgo_0:
_llgo_1: ; preds = %_llgo_0 _llgo_1: ; preds = %_llgo_0
store i1 true, ptr @"main.init$guard", align 1 store i1 true, ptr @"main.init$guard", align 1
call void @"main.init$abi"() call void @"main.init$after"()
br label %_llgo_2 br label %_llgo_2
_llgo_2: ; preds = %_llgo_1, %_llgo_0 _llgo_2: ; preds = %_llgo_1, %_llgo_0
@@ -102,7 +102,7 @@ _llgo_0:
declare ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64) declare ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64)
define void @"main.init$abi"() { define void @"main.init$after"() {
_llgo_0: _llgo_0:
%0 = call ptr @"github.com/goplus/llgo/internal/runtime.NewNamed"(i64 25, i64 0, i64 1) %0 = call ptr @"github.com/goplus/llgo/internal/runtime.NewNamed"(i64 25, i64 0, i64 1)
store ptr %0, ptr @_llgo_main.errorString, align 8 store ptr %0, ptr @_llgo_main.errorString, align 8

View File

@@ -49,7 +49,7 @@ _llgo_0:
_llgo_1: ; preds = %_llgo_0 _llgo_1: ; preds = %_llgo_0
store i1 true, ptr @"main.init$guard", align 1 store i1 true, ptr @"main.init$guard", align 1
call void @"github.com/goplus/llgo/cl/internal/foo.init"() call void @"github.com/goplus/llgo/cl/internal/foo.init"()
call void @"main.init$abi"() call void @"main.init$after"()
br label %_llgo_2 br label %_llgo_2
_llgo_2: ; preds = %_llgo_1, %_llgo_0 _llgo_2: ; preds = %_llgo_1, %_llgo_0
@@ -241,7 +241,7 @@ _llgo_18: ; preds = %_llgo_17, %_llgo_16
declare ptr @"github.com/goplus/llgo/internal/runtime.Zeroinit"(ptr, i64) declare ptr @"github.com/goplus/llgo/internal/runtime.Zeroinit"(ptr, i64)
define void @"main.init$abi"() { define void @"main.init$after"() {
_llgo_0: _llgo_0:
%0 = load ptr, ptr @_llgo_int, align 8 %0 = load ptr, ptr @_llgo_int, align 8
%1 = icmp eq ptr %0, null %1 = icmp eq ptr %0, null

View File

@@ -117,7 +117,7 @@ _llgo_0:
_llgo_1: ; preds = %_llgo_0 _llgo_1: ; preds = %_llgo_0
store i1 true, ptr @"main.init$guard", align 1 store i1 true, ptr @"main.init$guard", align 1
call void @"github.com/goplus/llgo/cl/internal/foo.init"() call void @"github.com/goplus/llgo/cl/internal/foo.init"()
call void @"main.init$abi"() call void @"main.init$after"()
br label %_llgo_2 br label %_llgo_2
_llgo_2: ; preds = %_llgo_1, %_llgo_0 _llgo_2: ; preds = %_llgo_1, %_llgo_0
@@ -185,7 +185,7 @@ _llgo_0:
ret i32 0 ret i32 0
} }
define void @"main.init$abi"() { define void @"main.init$after"() {
_llgo_0: _llgo_0:
%0 = load ptr, ptr @"_llgo_github.com/goplus/llgo/cl/internal/foo.Foo", align 8 %0 = load ptr, ptr @"_llgo_github.com/goplus/llgo/cl/internal/foo.Foo", align 8
%1 = icmp eq ptr %0, null %1 = icmp eq ptr %0, null

View File

@@ -68,7 +68,7 @@ _llgo_0:
_llgo_1: ; preds = %_llgo_0 _llgo_1: ; preds = %_llgo_0
store i1 true, ptr @"main.init$guard", align 1 store i1 true, ptr @"main.init$guard", align 1
call void @"main.init$abi"() call void @"main.init$after"()
br label %_llgo_2 br label %_llgo_2
_llgo_2: ; preds = %_llgo_1, %_llgo_0 _llgo_2: ; preds = %_llgo_1, %_llgo_0
@@ -101,7 +101,7 @@ _llgo_0:
ret i32 0 ret i32 0
} }
define void @"main.init$abi"() { define void @"main.init$after"() {
_llgo_0: _llgo_0:
%0 = load ptr, ptr @_llgo_int8, align 8 %0 = load ptr, ptr @_llgo_int8, align 8
%1 = icmp eq ptr %0, null %1 = icmp eq ptr %0, null

View File

@@ -86,7 +86,7 @@ _llgo_0:
_llgo_1: ; preds = %_llgo_0 _llgo_1: ; preds = %_llgo_0
store i1 true, ptr @"main.init$guard", align 1 store i1 true, ptr @"main.init$guard", align 1
call void @"main.init$abi"() call void @"main.init$after"()
store i64 9223372036854775807, ptr @main.a, align 4 store i64 9223372036854775807, ptr @main.a, align 4
store i64 -9223372036854775808, ptr @main.b, align 4 store i64 -9223372036854775808, ptr @main.b, align 4
store i64 -1, ptr @main.n, align 4 store i64 -1, ptr @main.n, align 4
@@ -643,7 +643,7 @@ declare void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com
declare %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.SliceAppend"(%"github.com/goplus/llgo/internal/runtime.Slice", ptr, i64, i64) declare %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.SliceAppend"(%"github.com/goplus/llgo/internal/runtime.Slice", ptr, i64, i64)
define void @"main.init$abi"() { define void @"main.init$after"() {
_llgo_0: _llgo_0:
%0 = load ptr, ptr @_llgo_int, align 8 %0 = load ptr, ptr @_llgo_int, align 8
%1 = icmp eq ptr %0, null %1 = icmp eq ptr %0, null

View File

@@ -401,7 +401,7 @@ _llgo_0:
_llgo_1: ; preds = %_llgo_0 _llgo_1: ; preds = %_llgo_0
store i1 true, ptr @"main.init$guard", align 1 store i1 true, ptr @"main.init$guard", align 1
call void @"main.init$abi"() call void @"main.init$after"()
br label %_llgo_2 br label %_llgo_2
_llgo_2: ; preds = %_llgo_1, %_llgo_0 _llgo_2: ; preds = %_llgo_1, %_llgo_0
@@ -472,7 +472,7 @@ _llgo_0:
ret i32 0 ret i32 0
} }
define void @"main.init$abi"() { define void @"main.init$after"() {
_llgo_0: _llgo_0:
%0 = load ptr, ptr @_llgo_string, align 8 %0 = load ptr, ptr @_llgo_string, align 8
%1 = icmp eq ptr %0, null %1 = icmp eq ptr %0, null

View File

@@ -199,7 +199,7 @@ _llgo_0:
_llgo_1: ; preds = %_llgo_0 _llgo_1: ; preds = %_llgo_0
store i1 true, ptr @"main.init$guard", align 1 store i1 true, ptr @"main.init$guard", align 1
call void @"github.com/goplus/llgo/internal/abi.init"() call void @"github.com/goplus/llgo/internal/abi.init"()
call void @"main.init$abi"() call void @"main.init$after"()
br label %_llgo_2 br label %_llgo_2
_llgo_2: ; preds = %_llgo_1, %_llgo_0 _llgo_2: ; preds = %_llgo_1, %_llgo_0
@@ -436,7 +436,7 @@ declare void @"github.com/goplus/llgo/internal/abi.init"()
declare void @"github.com/goplus/llgo/internal/runtime.init"() declare void @"github.com/goplus/llgo/internal/runtime.init"()
define void @"main.init$abi"() { define void @"main.init$after"() {
_llgo_0: _llgo_0:
%0 = load ptr, ptr @_llgo_bool, align 8 %0 = load ptr, ptr @_llgo_bool, align 8
%1 = icmp eq ptr %0, null %1 = icmp eq ptr %0, null

View File

@@ -17,7 +17,7 @@ _llgo_0:
_llgo_1: ; preds = %_llgo_0 _llgo_1: ; preds = %_llgo_0
store i1 true, ptr @"main.init$guard", align 1 store i1 true, ptr @"main.init$guard", align 1
call void @"main.init$abi"() call void @"main.init$after"()
br label %_llgo_2 br label %_llgo_2
_llgo_2: ; preds = %_llgo_1, %_llgo_0 _llgo_2: ; preds = %_llgo_1, %_llgo_0
@@ -51,7 +51,7 @@ _llgo_0:
declare void @"github.com/goplus/llgo/internal/runtime.init"() declare void @"github.com/goplus/llgo/internal/runtime.init"()
define void @"main.init$abi"() { define void @"main.init$after"() {
_llgo_0: _llgo_0:
%0 = load ptr, ptr @_llgo_string, align 8 %0 = load ptr, ptr @_llgo_string, align 8
%1 = icmp eq ptr %0, null %1 = icmp eq ptr %0, null

View File

@@ -285,6 +285,7 @@ func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) (llssa.Fun
for _, phi := range p.phis { for _, phi := range p.phis {
phi() phi()
} }
b.EndBuild()
}) })
} }
return fn, nil, goFunc return fn, nil, goFunc
@@ -796,8 +797,12 @@ func (p *context) compileInstr(b llssa.Builder, instr ssa.Instruction) {
key := p.compileValue(b, v.Key) key := p.compileValue(b, v.Key)
val := p.compileValue(b, v.Value) val := p.compileValue(b, v.Value)
b.MapUpdate(m, key, val) b.MapUpdate(m, key, val)
case *ssa.Defer:
p.call(b, llssa.Defer, &v.Call)
case *ssa.Go: case *ssa.Go:
p.call(b, llssa.Go, &v.Call) p.call(b, llssa.Go, &v.Call)
case *ssa.RunDefers:
b.RunDefers()
case *ssa.Panic: case *ssa.Panic:
arg := p.compileValue(b, v.X) arg := p.compileValue(b, v.X)
b.Panic(arg) b.Panic(arg)

Binary file not shown.

Binary file not shown.

View File

@@ -35,7 +35,7 @@ func AllocZ(size uintptr) unsafe.Pointer {
} }
// Zeroinit initializes memory to zero. // Zeroinit initializes memory to zero.
func Zeroinit(p c.Pointer, size uintptr) c.Pointer { func Zeroinit(p unsafe.Pointer, size uintptr) unsafe.Pointer {
return c.Memset(p, 0, size) return c.Memset(p, 0, size)
} }

View File

@@ -0,0 +1,34 @@
/*
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package runtime
// Defer presents defer statements in a function.
type Defer struct {
proc func(uintptr)
bits uintptr
link *Defer
rund int // index of RunDefers
}
// DeferProc calls deferred statements.
func DeferProc(d *Defer) {
for d != nil {
d.proc(d.bits)
d = d.link
_ = d.rund
}
}

View File

@@ -19,7 +19,6 @@ package ssa
import ( import (
"go/token" "go/token"
"go/types" "go/types"
"unsafe"
"github.com/goplus/llgo/ssa/abi" "github.com/goplus/llgo/ssa/abi"
"github.com/goplus/llvm" "github.com/goplus/llvm"
@@ -285,32 +284,8 @@ func lastParamType(prog Program, fn Expr) Type {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
type abiTypes struct {
iniabi unsafe.Pointer
}
func (p Package) hasAbiInit() bool {
return p.iniabi != nil
}
func (p Package) abiInit(b Builder) {
inib := Builder(p.iniabi)
inib.Return()
b.Call(inib.Func.Expr)
}
func (p Package) abiBuilder() Builder {
if p.iniabi == nil {
sigAbiInit := types.NewSignatureType(nil, nil, nil, nil, nil, false)
fn := p.NewFunc(p.Path()+".init$abi", sigAbiInit, InC)
fnb := fn.MakeBody(1)
p.iniabi = unsafe.Pointer(fnb)
}
return Builder(p.iniabi)
}
func (p Package) abiTypeInit(g Global, t types.Type, pub bool) { func (p Package) abiTypeInit(g Global, t types.Type, pub bool) {
b := p.abiBuilder() b := p.afterBuilder()
tabi := b.abiTypeOf(t) tabi := b.abiTypeOf(t)
expr := g.Expr expr := g.Expr
var eq Expr var eq Expr

View File

@@ -85,15 +85,13 @@ func (p Package) NewVar(name string, typ types.Type, bg Background) Global {
return p.doNewVar(name, t) return p.doNewVar(name, t)
} }
/* // NewVarEx creates a new global variable.
// NewVarFrom creates a new global variable. func (p Package) NewVarEx(name string, t Type) Global {
func (p Package) NewVarFrom(name string, t Type) Global {
if v, ok := p.vars[name]; ok { if v, ok := p.vars[name]; ok {
return v return v
} }
return p.doNewVar(name, t) return p.doNewVar(name, t)
} }
*/
func (p Package) doNewVar(name string, t Type) Global { func (p Package) doNewVar(name string, t Type) Global {
var gbl llvm.Value var gbl llvm.Value
@@ -182,6 +180,8 @@ type aFunction struct {
blks []BasicBlock blks []BasicBlock
defer_ *aDefer
params []Type params []Type
freeVars Expr freeVars Expr
base int // base = 1 if hasFreeVars; base = 0 otherwise base int // base = 1 if hasFreeVars; base = 0 otherwise
@@ -222,7 +222,14 @@ func newFunction(fn llvm.Value, t Type, pkg Package, prog Program, hasFreeVars b
if hasFreeVars { if hasFreeVars {
base = 1 base = 1
} }
return &aFunction{Expr{fn, t}, pkg, prog, nil, params, Expr{}, base, hasVArg} return &aFunction{
Expr: Expr{fn, t},
Pkg: pkg,
Prog: prog,
params: params,
base: base,
hasVArg: hasVArg,
}
} }
func newParams(fn Type, prog Program) (params []Type, hasVArg bool) { func newParams(fn Type, prog Program) (params []Type, hasVArg bool) {

View File

@@ -113,6 +113,16 @@ func (p Program) Zero(t Type) Expr {
ret = llvm.ConstStruct(flds, false) ret = llvm.ConstStruct(flds, false)
case *types.Slice: case *types.Slice:
ret = p.Zero(p.rtType("Slice")).impl ret = p.Zero(p.rtType("Slice")).impl
/* TODO(xsw):
case *types.Interface:
var name string
if u.Empty() {
name = "Eface"
} else {
name = "Iface"
}
ret = p.Zero(p.rtType(name)).impl
*/
default: default:
log.Panicln("todo:", u) log.Panicln("todo:", u)
} }
@@ -493,7 +503,6 @@ func (b Builder) ChangeType(t Type, x Expr) (ret Expr) {
typ := t.raw.Type typ := t.raw.Type
switch typ.(type) { switch typ.(type) {
default: default:
// TODO(xsw): remove instr name
ret.impl = llvm.CreateBitCast(b.impl, x.impl, t.ll) ret.impl = llvm.CreateBitCast(b.impl, x.impl, t.ll)
ret.Type = b.Prog.rawType(typ) ret.Type = b.Prog.rawType(typ)
return return
@@ -748,7 +757,6 @@ func (b Builder) Call(fn Expr, args ...Expr) (ret Expr) {
var ll llvm.Type var ll llvm.Type
var data Expr var data Expr
var sig *types.Signature var sig *types.Signature
var prog = b.Prog
var raw = fn.raw.Type var raw = fn.raw.Type
switch kind { switch kind {
case vkClosure: case vkClosure:
@@ -758,7 +766,7 @@ func (b Builder) Call(fn Expr, args ...Expr) (ret Expr) {
fallthrough fallthrough
case vkFuncPtr: case vkFuncPtr:
sig = raw.(*types.Signature) sig = raw.(*types.Signature)
ll = prog.FuncDecl(sig, InC).ll ll = b.Prog.FuncDecl(sig, InC).ll
case vkFuncDecl: case vkFuncDecl:
sig = raw.(*types.Signature) sig = raw.(*types.Signature)
ll = fn.ll ll = fn.ll
@@ -768,7 +776,7 @@ func (b Builder) Call(fn Expr, args ...Expr) (ret Expr) {
default: default:
log.Panicf("unreachable: %d(%T)\n", kind, raw) log.Panicf("unreachable: %d(%T)\n", kind, raw)
} }
ret.Type = prog.retType(sig) ret.Type = b.Prog.retType(sig)
ret.impl = llvm.CreateCall(b.impl, ll, fn.impl, llvmParamsEx(data, args, sig.Params(), b)) ret.impl = llvm.CreateCall(b.impl, ll, fn.impl, llvmParamsEx(data, args, sig.Params(), b))
return return
} }
@@ -795,8 +803,8 @@ type DoAction int
const ( const (
Call DoAction = iota Call DoAction = iota
Go
Defer Defer
Go
) )
// Do call a function with an action. // Do call a function with an action.
@@ -804,6 +812,8 @@ func (b Builder) Do(da DoAction, fn Expr, args ...Expr) (ret Expr) {
switch da { switch da {
case Call: case Call:
return b.Call(fn, args...) return b.Call(fn, args...)
case Defer:
b.Defer(fn, args...)
case Go: case Go:
b.Go(fn, args...) b.Go(fn, args...)
} }
@@ -818,6 +828,11 @@ func (b Builder) Do(da DoAction, fn Expr, args ...Expr) (ret Expr) {
// Go spec (excluding "make" and "new"). // Go spec (excluding "make" and "new").
func (b Builder) BuiltinCall(fn string, args ...Expr) (ret Expr) { func (b Builder) BuiltinCall(fn string, args ...Expr) (ret Expr) {
switch fn { switch fn {
case "String": // unsafe.String
return b.unsafeString(args[0].impl, args[1].impl)
case "Slice": // unsafe.Slice
size := args[1].impl
return b.unsafeSlice(args[0], size, size)
case "len": case "len":
if len(args) == 1 { if len(args) == 1 {
arg := args[0] arg := args[0]
@@ -857,8 +872,6 @@ func (b Builder) BuiltinCall(fn string, args ...Expr) (ret Expr) {
} }
} }
} }
case "print", "println":
return b.PrintEx(fn == "println", args...)
case "copy": case "copy":
if len(args) == 2 { if len(args) == 2 {
dst := args[0] dst := args[0]
@@ -874,11 +887,10 @@ func (b Builder) BuiltinCall(fn string, args ...Expr) (ret Expr) {
} }
} }
} }
case "String": // unsafe.String //case "recover":
return b.unsafeString(args[0].impl, args[1].impl) // return b.Recover()
case "Slice": // unsafe.Slice case "print", "println":
size := args[1].impl return b.PrintEx(fn == "println", args...)
return b.unsafeSlice(args[0], size, size)
} }
panic("todo: " + fn) panic("todo: " + fn)
} }

View File

@@ -50,7 +50,7 @@ func (p Program) tyPthreadCreate() *types.Signature {
return p.createThdTy return p.createThdTy
} }
func (b Builder) createThread(pp, attr, routine, arg Expr) Expr { func (b Builder) pthreadCreate(pp, attr, routine, arg Expr) Expr {
fn := b.Pkg.cFunc("pthread_create", b.Prog.tyPthreadCreate()) fn := b.Pkg.cFunc("pthread_create", b.Prog.tyPthreadCreate())
return b.Call(fn, pp, attr, routine, arg) return b.Call(fn, pp, attr, routine, arg)
} }
@@ -86,7 +86,7 @@ func (b Builder) Go(fn Expr, args ...Expr) {
data := Expr{b.aggregateMalloc(t, flds...), voidPtr} data := Expr{b.aggregateMalloc(t, flds...), voidPtr}
size := prog.SizeOf(voidPtr) size := prog.SizeOf(voidPtr)
pthd := b.Alloca(prog.IntVal(uint64(size), prog.Uintptr())) pthd := b.Alloca(prog.IntVal(uint64(size), prog.Uintptr()))
b.createThread(pthd, prog.Null(voidPtr), pkg.routine(t, len(args)), data) b.pthreadCreate(pthd, prog.Null(voidPtr), pkg.routine(t, len(args)), data)
} }
func (p Package) routineName() string { func (p Package) routineName() string {
@@ -112,3 +112,71 @@ func (p Package) routine(t Type, n int) Expr {
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// func(c.Pointer)
func (p Program) tyDestruct() *types.Signature {
if p.destructTy == nil {
paramPtr := types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type)
params := types.NewTuple(paramPtr)
p.destructTy = types.NewSignatureType(nil, nil, nil, params, nil, false)
}
return p.destructTy
}
// func(*c.Int, func(c.Pointer)) c.Int
func (p Program) tyPthreadKeyCreate() *types.Signature {
if p.createKeyTy == nil {
cint := p.CInt()
cintPtr := p.Pointer(cint)
paramCintPtr := types.NewParam(token.NoPos, nil, "", cintPtr.raw.Type)
paramDestruct := types.NewParam(token.NoPos, nil, "", p.tyDestruct())
paramCInt := types.NewParam(token.NoPos, nil, "", cint.raw.Type)
params := types.NewTuple(paramCintPtr, paramDestruct)
results := types.NewTuple(paramCInt)
p.createKeyTy = types.NewSignatureType(nil, nil, nil, params, results, false)
}
return p.createKeyTy
}
func (b Builder) pthreadKeyCreate(key, destruct Expr) Expr {
fn := b.Pkg.cFunc("pthread_key_create", b.Prog.tyPthreadKeyCreate())
return b.Call(fn, key, destruct)
}
// -----------------------------------------------------------------------------
// func(c.Int) c.Pointer
func (p Program) tyPthreadGetspecific() *types.Signature {
if p.getSpecTy == nil {
paramCInt := types.NewParam(token.NoPos, nil, "", p.CInt().raw.Type)
paramPtr := types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type)
params := types.NewTuple(paramCInt)
results := types.NewTuple(paramPtr)
p.getSpecTy = types.NewSignatureType(nil, nil, nil, params, results, false)
}
return p.getSpecTy
}
// func(c.Int, c.Pointer) c.Int
func (p Program) tyPthreadSetspecific() *types.Signature {
if p.setSpecTy == nil {
paramCInt := types.NewParam(token.NoPos, nil, "", p.CInt().raw.Type)
paramPtr := types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type)
params := types.NewTuple(paramCInt, paramPtr)
results := types.NewTuple(paramCInt)
p.setSpecTy = types.NewSignatureType(nil, nil, nil, params, results, false)
}
return p.setSpecTy
}
func (b Builder) pthreadGetspecific(key Expr) Expr {
fn := b.Pkg.cFunc("pthread_getspecific", b.Prog.tyPthreadGetspecific())
return b.Call(fn, key)
}
func (b Builder) pthreadSetspecific(key, val Expr) Expr {
fn := b.Pkg.cFunc("pthread_setspecific", b.Prog.tyPthreadSetspecific())
return b.Call(fn, key, val)
}
// -----------------------------------------------------------------------------

View File

@@ -74,6 +74,14 @@ func (b Builder) aggregateAllocU(t Type, flds ...llvm.Value) llvm.Value {
return ptr return ptr
} }
func (b Builder) aggregateAlloca(t Type, flds ...llvm.Value) llvm.Value {
prog := b.Prog
size := prog.SizeOf(t)
ptr := b.Alloca(prog.IntVal(size, prog.Uintptr())).impl
aggregateInit(b.impl, ptr, t.ll, flds...)
return ptr
}
func (b Builder) aggregateMalloc(t Type, flds ...llvm.Value) llvm.Value { func (b Builder) aggregateMalloc(t Type, flds ...llvm.Value) llvm.Value {
prog := b.Prog prog := b.Prog
size := prog.SizeOf(t) size := prog.SizeOf(t)

View File

@@ -20,6 +20,7 @@ import (
"go/token" "go/token"
"go/types" "go/types"
"strconv" "strconv"
"unsafe"
"github.com/goplus/llgo/ssa/abi" "github.com/goplus/llgo/ssa/abi"
"github.com/goplus/llvm" "github.com/goplus/llvm"
@@ -130,13 +131,14 @@ type aProgram struct {
rtSliceTy llvm.Type rtSliceTy llvm.Type
rtMapTy llvm.Type rtMapTy llvm.Type
anyTy Type anyTy Type
voidTy Type voidTy Type
voidPtr Type voidPtr Type
voidPPtr Type voidPPtr Type
boolTy Type boolTy Type
cstrTy Type cstrTy Type
cintTy Type cintTy Type
//cintPtr Type
stringTy Type stringTy Type
uintptrTy Type uintptrTy Type
intTy Type intTy Type
@@ -148,26 +150,36 @@ type aProgram struct {
u32Ty Type u32Ty Type
i64Ty Type i64Ty Type
u64Ty Type u64Ty Type
pyObjPtr Type pyObjPtr Type
pyObjPPtr Type pyObjPPtr Type
abiTyptr Type
abiTypptr Type
pyImpTy *types.Signature abiTyPtr Type
pyNewList *types.Signature abiTyPPtr Type
pyListSetI *types.Signature deferTy Type
callArgs *types.Signature deferPtr Type
callNoArgs *types.Signature deferPPtr Type
callOneArg *types.Signature
callFOArgs *types.Signature pyImpTy *types.Signature
loadPyModS *types.Signature pyNewList *types.Signature
getAttrStr *types.Signature pyListSetI *types.Signature
floatFromDbl *types.Signature
callNoArgs *types.Signature
callOneArg *types.Signature
callFOArgs *types.Signature
loadPyModS *types.Signature
getAttrStr *types.Signature
mallocTy *types.Signature mallocTy *types.Signature
freeTy *types.Signature freeTy *types.Signature
createKeyTy *types.Signature
createThdTy *types.Signature createThdTy *types.Signature
getSpecTy *types.Signature
setSpecTy *types.Signature
routineTy *types.Signature routineTy *types.Signature
destructTy *types.Signature
//deferFnTy *types.Signature
paramObjPtr_ *types.Var paramObjPtr_ *types.Var
@@ -323,30 +335,44 @@ func (p Program) Struct(typs ...Type) Type {
return p.rawType(types.NewStruct(els, nil)) return p.rawType(types.NewStruct(els, nil))
} }
/* // Defer returns runtime.Defer type.
// Eface returns the empty interface type. func (p Program) Defer() Type {
func (p Program) Eface() Type { if p.deferTy == nil {
if p.efaceTy == nil { p.deferTy = p.rtType("Defer")
p.efaceTy = p.rawType(tyAny)
} }
return p.efaceTy return p.deferTy
} }
*/
// AbiTypePtr returns *abi.Type. // DeferPtr returns *runtime.Defer type.
func (p Program) DeferPtr() Type {
if p.deferPtr == nil {
p.deferPtr = p.Pointer(p.Defer())
}
return p.deferPtr
}
// DeferPtrPtr returns **runtime.Defer type.
func (p Program) DeferPtrPtr() Type {
if p.deferPPtr == nil {
p.deferPPtr = p.Pointer(p.DeferPtr())
}
return p.deferPPtr
}
// AbiTypePtr returns *abi.Type type.
func (p Program) AbiTypePtr() Type { func (p Program) AbiTypePtr() Type {
if p.abiTyptr == nil { if p.abiTyPtr == nil {
p.abiTyptr = p.rawType(types.NewPointer(p.rtNamed("Type"))) p.abiTyPtr = p.rawType(types.NewPointer(p.rtNamed("Type")))
} }
return p.abiTyptr return p.abiTyPtr
} }
// AbiTypePtrPtr returns **abi.Type. // AbiTypePtrPtr returns **abi.Type type.
func (p Program) AbiTypePtrPtr() Type { func (p Program) AbiTypePtrPtr() Type {
if p.abiTypptr == nil { if p.abiTyPPtr == nil {
p.abiTypptr = p.Pointer(p.AbiTypePtr()) p.abiTyPPtr = p.Pointer(p.AbiTypePtr())
} }
return p.abiTypptr return p.abiTyPPtr
} }
// PyObjectPtrPtr returns the **py.Object type. // PyObjectPtrPtr returns the **py.Object type.
@@ -410,7 +436,7 @@ func (p Program) String() Type {
return p.stringTy return p.stringTy
} }
// Any returns any type. // Any returns the any (empty interface) type.
func (p Program) Any() Type { func (p Program) Any() Type {
if p.anyTy == nil { if p.anyTy == nil {
p.anyTy = p.rawType(tyAny) p.anyTy = p.rawType(tyAny)
@@ -418,6 +444,23 @@ func (p Program) Any() Type {
return p.anyTy return p.anyTy
} }
/*
// Eface returns the empty interface type.
// It is equivalent to Any.
func (p Program) Eface() Type {
return p.Any()
}
// CIntPtr returns *c.Int type.
func (p Program) CIntPtr() Type {
if p.cintPtr == nil {
p.cintPtr = p.Pointer(p.CInt())
}
return p.cintPtr
}
*/
// CInt returns c.Int type.
func (p Program) CInt() Type { func (p Program) CInt() Type {
if p.cintTy == nil { // C.int if p.cintTy == nil { // C.int
p.cintTy = p.rawType(types.Typ[types.Int32]) // TODO(xsw): support 64-bit p.cintTy = p.rawType(types.Typ[types.Int32]) // TODO(xsw): support 64-bit
@@ -518,14 +561,15 @@ func (p Program) Uint64() Type {
type aPackage struct { type aPackage struct {
mod llvm.Module mod llvm.Module
abi abi.Builder abi abi.Builder
abiTypes
Prog Program
vars map[string]Global vars map[string]Global
fns map[string]Function fns map[string]Function
stubs map[string]Function stubs map[string]Function
pyobjs map[string]PyObjRef pyobjs map[string]PyObjRef
pymods map[string]Global pymods map[string]Global
Prog Program afterb unsafe.Pointer
iRoutine int iRoutine int
} }
@@ -593,14 +637,29 @@ func (p Package) String() string {
return p.mod.String() return p.mod.String()
} }
// -----------------------------------------------------------------------------
func (p Package) afterBuilder() Builder {
if p.afterb == nil {
sigAfterInit := types.NewSignatureType(nil, nil, nil, nil, nil, false)
fn := p.NewFunc(p.Path()+".init$after", sigAfterInit, InC)
fnb := fn.MakeBody(1)
p.afterb = unsafe.Pointer(fnb)
}
return Builder(p.afterb)
}
// AfterInit is called after the package is initialized (init all packages that depends on). // AfterInit is called after the package is initialized (init all packages that depends on).
func (p Package) AfterInit(b Builder, ret BasicBlock) { func (p Package) AfterInit(b Builder, ret BasicBlock) {
doAbiInit := p.hasAbiInit() p.deferInit()
doAfterb := p.afterb != nil
doPyLoadModSyms := p.pyHasModSyms() doPyLoadModSyms := p.pyHasModSyms()
if doAbiInit || doPyLoadModSyms { if doAfterb || doPyLoadModSyms {
b.SetBlockEx(ret, afterInit, false) b.SetBlockEx(ret, afterInit, false)
if doAbiInit { if doAfterb {
p.abiInit(b) afterb := Builder(p.afterb)
afterb.Return()
b.Call(afterb.Func.Expr)
} }
if doPyLoadModSyms { if doPyLoadModSyms {
p.pyLoadModSyms(b) p.pyLoadModSyms(b)
@@ -608,6 +667,8 @@ func (p Package) AfterInit(b Builder, ret BasicBlock) {
} }
} }
// -----------------------------------------------------------------------------
/* /*
type CodeGenFileType = llvm.CodeGenFileType type CodeGenFileType = llvm.CodeGenFileType
@@ -739,14 +800,14 @@ func (p Program) tyNewList() *types.Signature {
// func(float64) *Object // func(float64) *Object
func (p Program) tyFloatFromDouble() *types.Signature { func (p Program) tyFloatFromDouble() *types.Signature {
if p.callArgs == nil { if p.floatFromDbl == nil {
paramObjPtr := p.paramObjPtr() paramObjPtr := p.paramObjPtr()
paramFloat := types.NewParam(token.NoPos, nil, "", p.Float64().raw.Type) paramFloat := types.NewParam(token.NoPos, nil, "", p.Float64().raw.Type)
params := types.NewTuple(paramFloat) params := types.NewTuple(paramFloat)
results := types.NewTuple(paramObjPtr) results := types.NewTuple(paramObjPtr)
p.callArgs = types.NewSignatureType(nil, nil, nil, params, results, false) p.floatFromDbl = types.NewSignatureType(nil, nil, nil, params, results, false)
} }
return p.callArgs return p.floatFromDbl
} }
// func(*Object, ...) // func(*Object, ...)

View File

@@ -27,6 +27,16 @@ import (
"github.com/goplus/llvm" "github.com/goplus/llvm"
) )
func TestEndDefer(t *testing.T) {
prog := NewProgram(nil)
pkg := prog.NewPackage("foo", "foo")
sigMain := types.NewSignatureType(nil, nil, nil, nil, nil, false)
fn := pkg.NewFunc("main", sigMain, InC)
b := fn.MakeBody(1)
fn.defer_ = &aDefer{}
fn.endDefer(b)
}
func TestUnsafeString(t *testing.T) { func TestUnsafeString(t *testing.T) {
prog := NewProgram(nil) prog := NewProgram(nil)
prog.SetRuntime(func() *types.Package { prog.SetRuntime(func() *types.Package {
@@ -187,6 +197,7 @@ func TestVar(t *testing.T) {
if pkg.NewVar("a", types.Typ[types.Int], InGo) != a { if pkg.NewVar("a", types.Typ[types.Int], InGo) != a {
t.Fatal("NewVar(a) failed") t.Fatal("NewVar(a) failed")
} }
pkg.NewVarEx("a", prog.Type(types.Typ[types.Int], InGo))
a.Init(prog.Val(100)) a.Init(prog.Val(100))
b := pkg.NewVar("b", types.Typ[types.Int], InGo) b := pkg.NewVar("b", types.Typ[types.Int], InGo)
b.Init(a.Expr) b.Init(a.Expr)

View File

@@ -19,6 +19,7 @@ package ssa
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"go/token"
"go/types" "go/types"
"log" "log"
"strings" "strings"
@@ -61,6 +62,11 @@ type aBuilder struct {
// Builder represents a builder for creating instructions in a function. // Builder represents a builder for creating instructions in a function.
type Builder = *aBuilder type Builder = *aBuilder
// EndBuild ends the build process of a function.
func (b Builder) EndBuild() {
b.Func.endDefer(b)
}
// Dispose disposes of the builder. // Dispose disposes of the builder.
func (b Builder) Dispose() { func (b Builder) Dispose() {
b.impl.Dispose() b.impl.Dispose()
@@ -128,6 +134,164 @@ func notInit(instr llvm.Value) bool {
return true return true
} }
// -----------------------------------------------------------------------------
const (
deferKey = "__llgo_defer"
)
type aDefer struct {
nextBit int // next defer bit
key Expr // pthread TLS key
data Expr // pointer to runtime.Defer
bitsPtr Expr // pointer to defer bits
rundPtr Expr // pointer to RunDefers index
procBlk BasicBlock // deferProc block
stmts []func(bits Expr)
runsNext []BasicBlock // next blocks of RunDefers
}
/*
// func(uintptr)
func (p Program) tyDeferFunc() *types.Signature {
if p.deferFnTy == nil {
paramUintptr := types.NewParam(token.NoPos, nil, "", p.Uintptr().raw.Type)
params := types.NewTuple(paramUintptr)
p.deferFnTy = types.NewSignatureType(nil, nil, nil, params, nil, false)
}
return p.deferFnTy
}
*/
func (p Package) deferInit() {
keyVar := p.VarOf(deferKey)
if keyVar == nil {
return
}
prog := p.Prog
keyNil := prog.Null(prog.DeferPtrPtr())
keyVar.Init(keyNil)
keyVar.impl.SetLinkage(llvm.LinkOnceAnyLinkage)
b := p.afterBuilder()
eq := b.BinOp(token.EQL, b.Load(keyVar.Expr), keyNil)
b.IfThen(eq, func() {
b.pthreadKeyCreate(keyVar.Expr, prog.Null(prog.VoidPtr()))
})
}
func (p Package) newDeferKey() Global {
return p.NewVarEx(deferKey, p.Prog.DeferPtrPtr())
}
func (b Builder) deferKey() Expr {
return b.Load(b.Pkg.newDeferKey().Expr)
}
func (b Builder) getDefer() *aDefer {
self := b.Func
if self.defer_ == nil {
// TODO(xsw): move to funtion start
// 0: proc func(uintptr)
// 1: bits uintptr
// 2: link *Defer
// 3: rund int
prog := b.Prog
key := b.deferKey()
deferfn := prog.Null(prog.VoidPtr())
zero := prog.Val(uintptr(0))
link := b.pthreadGetspecific(key)
ptr := b.aggregateAlloca(prog.Defer(), deferfn.impl, zero.impl, link.impl)
deferData := Expr{ptr, prog.DeferPtr()}
b.pthreadSetspecific(key, deferData)
self.defer_ = &aDefer{
key: key,
data: deferData,
bitsPtr: b.FieldAddr(deferData, 1),
rundPtr: b.FieldAddr(deferData, 3),
procBlk: self.MakeBlock(),
}
}
return self.defer_
}
// Defer emits a defer instruction.
func (b Builder) Defer(fn Expr, args ...Expr) {
if debugInstr {
logCall("Defer", fn, args)
}
prog := b.Prog
self := b.getDefer()
next := self.nextBit
self.nextBit++
bits := b.Load(self.bitsPtr)
nextbit := prog.Val(uintptr(1 << next))
b.Store(self.bitsPtr, b.BinOp(token.OR, bits, nextbit))
self.stmts = append(self.stmts, func(bits Expr) {
zero := prog.Val(uintptr(0))
has := b.BinOp(token.NEQ, b.BinOp(token.AND, bits, nextbit), zero)
b.IfThen(has, func() {
b.Call(fn, args...)
})
})
}
// RunDefers emits instructions to run deferred instructions.
func (b Builder) RunDefers() {
prog := b.Prog
self := b.getDefer()
b.Store(self.rundPtr, prog.Val(len(self.runsNext)))
b.Jump(self.procBlk)
blk := b.Func.MakeBlock()
self.runsNext = append(self.runsNext, blk)
b.SetBlockEx(blk, AtEnd, false)
b.blk.last = blk.last
}
func (p Function) endDefer(b Builder) {
self := p.defer_
if self == nil {
return
}
nexts := self.runsNext
n := len(nexts)
if n == 0 {
return
}
b.SetBlockEx(self.procBlk, AtEnd, true)
bits := b.Load(self.bitsPtr)
stmts := self.stmts
for i := len(stmts) - 1; i >= 0; i-- {
stmts[i](bits)
}
link := b.getField(b.Load(self.data), 2)
b.pthreadSetspecific(self.key, link)
prog := b.Prog
rund := b.Load(self.rundPtr)
sw := b.impl.CreateSwitch(rund.impl, nexts[0].first, n-1)
for i := 1; i < n; i++ {
sw.AddCase(prog.Val(i).impl, nexts[i].first)
}
}
// -----------------------------------------------------------------------------
/*
// Recover emits a recover instruction.
func (b Builder) Recover() (v Expr) {
if debugInstr {
log.Println("Recover")
}
prog := b.Prog
return prog.Zero(prog.Eface())
}
*/
// Panic emits a panic instruction. // Panic emits a panic instruction.
func (b Builder) Panic(v Expr) { func (b Builder) Panic(v Expr) {
if debugInstr { if debugInstr {
@@ -206,6 +370,17 @@ func (b Builder) If(cond Expr, thenb, elseb BasicBlock) {
b.impl.CreateCondBr(cond.impl, thenb.first, elseb.first) b.impl.CreateCondBr(cond.impl, thenb.first, elseb.first)
} }
// IfThen emits an if-then instruction.
func (b Builder) IfThen(cond Expr, then func()) {
blks := b.Func.MakeBlocks(2)
b.If(cond, blks[0], blks[1])
b.SetBlockEx(blks[0], AtEnd, false)
then()
b.Jump(blks[1])
b.SetBlockEx(blks[1], AtEnd, false)
b.blk.last = blks[1].last
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Phi represents a phi node. // Phi represents a phi node.