11
_demo/chan/chan.go
Normal file
11
_demo/chan/chan.go
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
ch := make(chan int, 10)
|
||||||
|
println(ch, len(ch), cap(ch))
|
||||||
|
go func() {
|
||||||
|
ch <- 100
|
||||||
|
}()
|
||||||
|
n, ok := <-ch
|
||||||
|
println(n, ok)
|
||||||
|
}
|
||||||
19
cl/_testgo/chan/in.go
Normal file
19
cl/_testgo/chan/in.go
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
ch := make(chan int, 10)
|
||||||
|
var v any = ch
|
||||||
|
println(ch, len(ch), cap(ch), v)
|
||||||
|
go func() {
|
||||||
|
ch <- 100
|
||||||
|
}()
|
||||||
|
n := <-ch
|
||||||
|
println(n)
|
||||||
|
|
||||||
|
ch2 := make(chan int, 10)
|
||||||
|
go func() {
|
||||||
|
close(ch2)
|
||||||
|
}()
|
||||||
|
n2, ok := <-ch2
|
||||||
|
println(n2, ok)
|
||||||
|
}
|
||||||
1
cl/_testgo/chan/out.ll
Normal file
1
cl/_testgo/chan/out.ll
Normal file
@@ -0,0 +1 @@
|
|||||||
|
;
|
||||||
@@ -459,7 +459,11 @@ func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue
|
|||||||
ret = b.BinOp(v.Op, x, y)
|
ret = b.BinOp(v.Op, x, y)
|
||||||
case *ssa.UnOp:
|
case *ssa.UnOp:
|
||||||
x := p.compileValue(b, v.X)
|
x := p.compileValue(b, v.X)
|
||||||
ret = b.UnOp(v.Op, x)
|
if v.Op == token.ARROW {
|
||||||
|
ret = b.Recv(x, v.CommaOk)
|
||||||
|
} else {
|
||||||
|
ret = b.UnOp(v.Op, x)
|
||||||
|
}
|
||||||
case *ssa.ChangeType:
|
case *ssa.ChangeType:
|
||||||
t := v.Type()
|
t := v.Type()
|
||||||
x := p.compileValue(b, v.X)
|
x := p.compileValue(b, v.X)
|
||||||
@@ -579,6 +583,10 @@ func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue
|
|||||||
case *ssa.Field:
|
case *ssa.Field:
|
||||||
x := p.compileValue(b, v.X)
|
x := p.compileValue(b, v.X)
|
||||||
ret = b.Field(x, v.Field)
|
ret = b.Field(x, v.Field)
|
||||||
|
case *ssa.MakeChan:
|
||||||
|
t := v.Type()
|
||||||
|
size := p.compileValue(b, v.Size)
|
||||||
|
ret = b.MakeChan(p.prog.Type(t, llssa.InGo), size)
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("compileInstrAndValue: unknown instr - %T\n", iv))
|
panic(fmt.Sprintf("compileInstrAndValue: unknown instr - %T\n", iv))
|
||||||
}
|
}
|
||||||
@@ -651,6 +659,10 @@ func (p *context) compileInstr(b llssa.Builder, instr ssa.Instruction) {
|
|||||||
case *ssa.Panic:
|
case *ssa.Panic:
|
||||||
arg := p.compileValue(b, v.X)
|
arg := p.compileValue(b, v.X)
|
||||||
b.Panic(arg)
|
b.Panic(arg)
|
||||||
|
case *ssa.Send:
|
||||||
|
ch := p.compileValue(b, v.Chan)
|
||||||
|
x := p.compileValue(b, v.X)
|
||||||
|
b.Send(ch, x)
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("compileInstr: unknown instr - %T\n", instr))
|
panic(fmt.Sprintf("compileInstr: unknown instr - %T\n", instr))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -192,4 +192,20 @@ func ArrayOf(length uintptr, elem *Type) *Type {
|
|||||||
return &ret.Type
|
return &ret.Type
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ChanOf(dir int, strChan string, elem *Type) *Type {
|
||||||
|
ret := &abi.ChanType{
|
||||||
|
Type: Type{
|
||||||
|
Size_: 8,
|
||||||
|
Hash: uint32(abi.Chan),
|
||||||
|
Align_: pointerAlign,
|
||||||
|
FieldAlign_: pointerAlign,
|
||||||
|
Kind_: uint8(abi.Chan),
|
||||||
|
Str_: strChan + " " + elem.String(),
|
||||||
|
},
|
||||||
|
Elem: elem,
|
||||||
|
Dir: abi.ChanDir(dir),
|
||||||
|
}
|
||||||
|
return &ret.Type
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -65,6 +65,18 @@ func UnderlyingKind(t types.Type) abi.Kind {
|
|||||||
panic("todo")
|
panic("todo")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ChanDir(dir types.ChanDir) (abi.ChanDir, string) {
|
||||||
|
switch dir {
|
||||||
|
case types.SendRecv:
|
||||||
|
return abi.BothDir, "chan"
|
||||||
|
case types.SendOnly:
|
||||||
|
return abi.SendDir, "chan->"
|
||||||
|
case types.RecvOnly:
|
||||||
|
return abi.RecvDir, "<-chan"
|
||||||
|
}
|
||||||
|
panic("invlid chan dir")
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
type DataKind int
|
type DataKind int
|
||||||
@@ -165,6 +177,18 @@ func (b *Builder) TypeName(t types.Type) (ret string, pub bool) {
|
|||||||
key, pub1 := b.TypeName(t.Key())
|
key, pub1 := b.TypeName(t.Key())
|
||||||
elem, pub2 := b.TypeName(t.Elem())
|
elem, pub2 := b.TypeName(t.Elem())
|
||||||
return fmt.Sprintf("map[%s]%s", key, elem), pub1 && pub2
|
return fmt.Sprintf("map[%s]%s", key, elem), pub1 && pub2
|
||||||
|
case *types.Chan:
|
||||||
|
elem, pub := b.TypeName(t.Elem())
|
||||||
|
var s string
|
||||||
|
switch t.Dir() {
|
||||||
|
case types.SendRecv:
|
||||||
|
s = "chan"
|
||||||
|
case types.SendOnly:
|
||||||
|
s = "chan<-"
|
||||||
|
case types.RecvOnly:
|
||||||
|
s = "<-chan"
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s %s", s, elem), pub
|
||||||
}
|
}
|
||||||
log.Panicf("todo: %T\n", t)
|
log.Panicf("todo: %T\n", t)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -68,6 +68,8 @@ func (b Builder) abiTypeOf(t types.Type) func() Expr {
|
|||||||
return b.abiSliceOf(t)
|
return b.abiSliceOf(t)
|
||||||
case *types.Array:
|
case *types.Array:
|
||||||
return b.abiArrayOf(t)
|
return b.abiArrayOf(t)
|
||||||
|
case *types.Chan:
|
||||||
|
return b.abiChanOf(t)
|
||||||
}
|
}
|
||||||
panic("todo")
|
panic("todo")
|
||||||
}
|
}
|
||||||
@@ -274,6 +276,14 @@ func (b Builder) abiArrayOf(t *types.Array) func() Expr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b Builder) abiChanOf(t *types.Chan) func() Expr {
|
||||||
|
elem := b.abiTypeOf(t.Elem())
|
||||||
|
return func() Expr {
|
||||||
|
dir, s := abi.ChanDir(t.Dir())
|
||||||
|
return b.Call(b.Pkg.rtFunc("ChanOf"), b.Prog.IntVal(uint64(dir), b.Prog.Int()), b.Str(s), elem())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// func StructField(name string, typ *abi.Type, off uintptr, tag string, embedded bool)
|
// func StructField(name string, typ *abi.Type, off uintptr, tag string, embedded bool)
|
||||||
// func Struct(pkgPath string, size uintptr, fields []abi.StructField)
|
// func Struct(pkgPath string, size uintptr, fields []abi.StructField)
|
||||||
func (b Builder) abiStructOf(t *types.Struct) func() Expr {
|
func (b Builder) abiStructOf(t *types.Struct) func() Expr {
|
||||||
|
|||||||
@@ -540,4 +540,75 @@ func (b Builder) Next(iter Expr, isString bool) (ret Expr) {
|
|||||||
panic("todo")
|
panic("todo")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The MakeChan instruction creates a new channel object and yields a
|
||||||
|
// value of kind chan.
|
||||||
|
//
|
||||||
|
// Type() returns a (possibly named) *types.Chan.
|
||||||
|
//
|
||||||
|
// Pos() returns the ast.CallExpr.Lparen for the make(chan) that
|
||||||
|
// created it.
|
||||||
|
//
|
||||||
|
// Example printed form:
|
||||||
|
//
|
||||||
|
// t0 = make chan int 0
|
||||||
|
// t0 = make IntChan 0
|
||||||
|
//
|
||||||
|
// type MakeChan struct {
|
||||||
|
// register
|
||||||
|
// Size Value // int; size of buffer; zero => synchronous.
|
||||||
|
// }
|
||||||
|
func (b Builder) MakeChan(t Type, size Expr) (ret Expr) {
|
||||||
|
if debugInstr {
|
||||||
|
log.Printf("MakeChan %v, %v\n", t.RawType(), size.impl)
|
||||||
|
}
|
||||||
|
prog := b.Prog
|
||||||
|
eltSize := prog.IntVal(prog.SizeOf(prog.Elem(t)), prog.Int())
|
||||||
|
ret.Type = t
|
||||||
|
ret.impl = b.InlineCall(b.Pkg.rtFunc("NewChan"), eltSize, size).impl
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Send instruction sends X on channel Chan.
|
||||||
|
//
|
||||||
|
// Pos() returns the ast.SendStmt.Arrow, if explicit in the source.
|
||||||
|
//
|
||||||
|
// Example printed form:
|
||||||
|
//
|
||||||
|
// send t0 <- t1
|
||||||
|
func (b Builder) Send(ch Expr, x Expr) (ret Expr) {
|
||||||
|
if debugInstr {
|
||||||
|
log.Printf("Send %v, %v\n", ch.impl, x.impl)
|
||||||
|
}
|
||||||
|
prog := b.Prog
|
||||||
|
eltSize := prog.IntVal(prog.SizeOf(prog.Elem(ch.Type)), prog.Int())
|
||||||
|
ret = b.InlineCall(b.Pkg.rtFunc("ChanSend"), ch, b.toPtr(x), eltSize)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b Builder) toPtr(x Expr) Expr {
|
||||||
|
typ := x.Type
|
||||||
|
vtyp := b.Prog.VoidPtr()
|
||||||
|
vptr := b.Alloc(typ, false)
|
||||||
|
b.Store(vptr, x)
|
||||||
|
return Expr{vptr.impl, vtyp}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b Builder) Recv(ch Expr, commaOk bool) (ret Expr) {
|
||||||
|
if debugInstr {
|
||||||
|
log.Printf("Recv %v, %v\n", ch.impl, commaOk)
|
||||||
|
}
|
||||||
|
prog := b.Prog
|
||||||
|
eltSize := prog.IntVal(prog.SizeOf(prog.Elem(ch.Type)), prog.Int())
|
||||||
|
etyp := prog.Elem(ch.Type)
|
||||||
|
ptr := b.Alloc(etyp, false)
|
||||||
|
ok := b.InlineCall(b.Pkg.rtFunc("ChanRecv"), ch, ptr, eltSize)
|
||||||
|
if commaOk {
|
||||||
|
val := b.Load(ptr)
|
||||||
|
t := prog.Struct(etyp, prog.Bool())
|
||||||
|
return b.aggregateValue(t, val.impl, ok.impl)
|
||||||
|
} else {
|
||||||
|
return b.Load(ptr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|||||||
15
ssa/expr.go
15
ssa/expr.go
@@ -1001,6 +1001,8 @@ func (b Builder) BuiltinCall(fn string, args ...Expr) (ret Expr) {
|
|||||||
return b.SliceLen(arg)
|
return b.SliceLen(arg)
|
||||||
case vkString:
|
case vkString:
|
||||||
return b.StringLen(arg)
|
return b.StringLen(arg)
|
||||||
|
case vkChan:
|
||||||
|
return b.InlineCall(b.Pkg.rtFunc("ChanLen"), arg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case "cap":
|
case "cap":
|
||||||
@@ -1009,6 +1011,8 @@ func (b Builder) BuiltinCall(fn string, args ...Expr) (ret Expr) {
|
|||||||
switch arg.kind {
|
switch arg.kind {
|
||||||
case vkSlice:
|
case vkSlice:
|
||||||
return b.SliceCap(arg)
|
return b.SliceCap(arg)
|
||||||
|
case vkChan:
|
||||||
|
return b.InlineCall(b.Pkg.rtFunc("ChanCap"), arg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case "append":
|
case "append":
|
||||||
@@ -1047,6 +1051,14 @@ func (b Builder) BuiltinCall(fn string, args ...Expr) (ret Expr) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case "close":
|
||||||
|
if len(args) == 1 {
|
||||||
|
arg := args[0]
|
||||||
|
switch arg.kind {
|
||||||
|
case vkChan:
|
||||||
|
return b.InlineCall(b.Pkg.rtFunc("ChanClose"), arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
case "recover":
|
case "recover":
|
||||||
return b.Recover()
|
return b.Recover()
|
||||||
case "print", "println":
|
case "print", "println":
|
||||||
@@ -1114,6 +1126,9 @@ func (b Builder) PrintEx(ln bool, args ...Expr) (ret Expr) {
|
|||||||
case vkComplex:
|
case vkComplex:
|
||||||
fn = "PrintComplex"
|
fn = "PrintComplex"
|
||||||
typ = prog.Complex128()
|
typ = prog.Complex128()
|
||||||
|
case vkChan:
|
||||||
|
fn = "PrintPointer"
|
||||||
|
typ = prog.VoidPtr()
|
||||||
default:
|
default:
|
||||||
panic(fmt.Errorf("illegal types for operand: print %v", arg.RawType()))
|
panic(fmt.Errorf("illegal types for operand: print %v", arg.RawType()))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -133,6 +133,7 @@ type aProgram struct {
|
|||||||
rtIfaceTy llvm.Type
|
rtIfaceTy llvm.Type
|
||||||
rtSliceTy llvm.Type
|
rtSliceTy llvm.Type
|
||||||
rtMapTy llvm.Type
|
rtMapTy llvm.Type
|
||||||
|
rtChanTy llvm.Type
|
||||||
|
|
||||||
anyTy Type
|
anyTy Type
|
||||||
voidTy Type
|
voidTy Type
|
||||||
@@ -287,6 +288,13 @@ func (p Program) rtString() llvm.Type {
|
|||||||
return p.rtStringTy
|
return p.rtStringTy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p Program) rtChan() llvm.Type {
|
||||||
|
if p.rtChanTy.IsNil() {
|
||||||
|
p.rtChanTy = p.rtType("Chan").ll
|
||||||
|
}
|
||||||
|
return p.rtChanTy
|
||||||
|
}
|
||||||
|
|
||||||
func (p Program) tyComplex64() llvm.Type {
|
func (p Program) tyComplex64() llvm.Type {
|
||||||
if p.c64Type.IsNil() {
|
if p.c64Type.IsNil() {
|
||||||
ctx := p.ctx
|
ctx := p.ctx
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ const (
|
|||||||
vkEface
|
vkEface
|
||||||
vkIface
|
vkIface
|
||||||
vkStruct
|
vkStruct
|
||||||
|
vkChan
|
||||||
)
|
)
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
@@ -371,6 +372,7 @@ func (p Program) toType(raw types.Type) Type {
|
|||||||
elem := p.rawType(t.Elem())
|
elem := p.rawType(t.Elem())
|
||||||
return &aType{llvm.ArrayType(elem.ll, int(t.Len())), typ, vkArray}
|
return &aType{llvm.ArrayType(elem.ll, int(t.Len())), typ, vkArray}
|
||||||
case *types.Chan:
|
case *types.Chan:
|
||||||
|
return &aType{llvm.PointerType(p.rtChan(), 0), typ, vkChan}
|
||||||
}
|
}
|
||||||
panic(fmt.Sprintf("toLLVMType: todo - %T\n", raw))
|
panic(fmt.Sprintf("toLLVMType: todo - %T\n", raw))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user