func (cdd *CDD) ReturnStmt(w *bytes.Buffer, s *ast.ReturnStmt, resultT string, tup *types.Tuple) (end bool) { switch len(s.Results) { case 0: if resultT == "void" { w.WriteString("return;\n") } else { w.WriteString("goto end;\n") end = true } case 1: w.WriteString("return ") cdd.Expr(w, s.Results[0], tup.At(0).Type()) w.WriteString(";\n") default: w.WriteString("return (" + resultT + "){") for i, e := range s.Results { if i > 0 { w.WriteString(", ") } cdd.Expr(w, e, tup.At(i).Type()) } w.WriteString("};\n") } return }
func (p *exporter) tuple(t *types.Tuple) { n := t.Len() p.int(n) for i := 0; i < n; i++ { p.param(t.At(i)) } }
func (c *funcContext) typeArray(t *types.Tuple) string { s := make([]string, t.Len()) for i := range s { s[i] = c.typeName(t.At(i).Type()) } return "[" + strings.Join(s, ", ") + "]" }
func (tm *TypeMap) rtypeSlice(t *types.Tuple) llvm.Value { rtypes := make([]llvm.Value, t.Len()) for i := range rtypes { rtypes[i] = tm.ToRuntime(t.At(i).Type()) } slicetyp := tm.runtime.funcType.llvm.StructElementTypes()[2] return tm.makeSlice(rtypes, slicetyp) }
func (h Hasher) hashTuple(tuple *types.Tuple) uint32 { // See go/types.identicalTypes for rationale. n := tuple.Len() var hash uint32 = 9137 + 2*uint32(n) for i := 0; i < n; i++ { hash += 3 * h.Hash(tuple.At(i).Type()) } return hash }
func (w *Walker) writeParams(buf *bytes.Buffer, t *types.Tuple, variadic bool) { buf.WriteByte('(') for i, n := 0, t.Len(); i < n; i++ { if i > 0 { buf.WriteString(", ") } typ := t.At(i).Type() if variadic && i+1 == n { buf.WriteString("...") typ = typ.(*types.Slice).Elem() } w.writeType(buf, typ) } buf.WriteByte(')') }
func checkTypes(args *types.Tuple, types []string) (any, all bool) { matched := make([]bool, len(types)) for i := 0; i < args.Len(); i++ { for k, toCheck := range types { if args.At(i).Type().String() == toCheck { matched[k] = true any = true } } } for _, b := range matched { if !b { return any, false } } return any, true }
func (p *printer) writeTuple(this *types.Package, tup *types.Tuple, variadic bool, visited []types.Type) { p.print("(") for i, n := 0, tup.Len(); i < n; i++ { if i > 0 { p.print(", ") } v := tup.At(i) if name := v.Name(); name != "" { p.print(name) p.print(" ") } typ := v.Type() if variadic && i == n-1 { p.print("...") typ = typ.(*types.Slice).Elem() } p.writeTypeInternal(this, typ, visited) } p.print(")") }
func (cdd *CDD) results(tup *types.Tuple) (res results) { if tup == nil { res.typ = "void" return } n := tup.Len() res.names = make([]string, n) for i := 0; i < n; i++ { name := tup.At(i).Name() switch name { case "": name = "_" + strconv.Itoa(n) case "_": res.hasNames = true default: name += "$" res.hasNames = true } res.names[i] = name } if n > 1 { res.typ, res.fields, res.acds = cdd.tupleName(tup) return } v := tup.At(0) field0 := types.NewField(v.Pos(), v.Pkg(), "_0", v.Type(), false) res.fields = []*types.Var{field0} res.typ, res.dim, res.acds = cdd.TypeStr(v.Type()) return }
func argsToString(args *types.Tuple) string { ret := make([]string, args.Len()) for i := 0; i < args.Len(); i++ { name := noDot(args.At(i).Name()) typ := args.At(i).Type().String() if len(name) == 0 { ret[i] = typ } else { ret[i] = name + " " + typ } } return strings.Join(ret, ", ") }
func (ts *TypeStringer) writeParams(buf *bytes.Buffer, params *types.Tuple, isVariadic bool) { buf.WriteByte('(') for i := 0; i < int(params.Len()); i++ { par := params.At(i) if i > 0 { buf.WriteString(", ") } if isVariadic && i == int(params.Len()-1) { buf.WriteString("...") } ts.writeType(buf, par.Type()) } buf.WriteByte(')') }
func (e *exporter) makeParameters(tuple *types.Tuple, variadic bool) string { params := make([]string, tuple.Len()) for i := range params { param := tuple.At(i) paramType := param.Type() dots := "" if variadic && i == tuple.Len()-1 { dots = "..." paramType = paramType.(*types.Slice).Elem() } params[i] = e.makeName(param) + " " + dots + e.makeType(paramType) } return strings.Join(params, ", ") }
func (cdd *CDD) tupleName(tup *types.Tuple) (tupName string, fields []*types.Var, acds []*CDD) { n := tup.Len() for i := 0; i < n; i++ { if i != 0 { tupName += "$$" } name, dim, a := cdd.TypeStr(tup.At(i).Type()) tupName += dimFuncPtr(name, dim) acds = append(acds, a...) } tupName = strings.Map(symToDol, tupName) fields = make([]*types.Var, n) for i := 0; i < n; i++ { v := tup.At(i) fields[i] = types.NewField( v.Pos(), v.Pkg(), "_"+strconv.Itoa(i), v.Type(), false, ) } if _, ok := cdd.gtc.tupNames[tupName]; ok { return } cdd.gtc.tupNames[tupName] = struct{}{} s := types.NewStruct(fields, nil) o := types.NewTypeName(tup.At(0).Pos(), cdd.gtc.pkg, tupName, s) acd := cdd.gtc.newCDD(o, TypeDecl, 0) acd.structDecl(new(bytes.Buffer), tupName, s) cdd.DeclUses[o] = true acds = append(acds, acd) return }
func (cdd *CDD) Stmt(w *bytes.Buffer, stmt ast.Stmt, label, resultT string, tup *types.Tuple) (end bool, acds []*CDD) { updateEA := func(e bool, a []*CDD) { if e { end = true } acds = append(acds, a...) } cdd.Complexity++ switch s := stmt.(type) { case *ast.DeclStmt: cdds := cdd.gtc.Decl(s.Decl, cdd.il) for _, c := range cdds { for u, typPtr := range c.FuncBodyUses { cdd.FuncBodyUses[u] = typPtr } w.Write(c.Decl) } for _, c := range cdds { w.Write(c.Def) } case *ast.AssignStmt: rhs := make([]string, len(s.Lhs)) typ := make([]types.Type, len(s.Lhs)) rhsIsTuple := len(s.Lhs) > 1 && len(s.Rhs) == 1 if rhsIsTuple { tup := cdd.exprType(s.Rhs[0]).(*types.Tuple) tupName, _, a := cdd.tupleName(tup) acds = append(acds, a...) w.WriteString(tupName) tupName = "tmp" + cdd.gtc.uniqueId() w.WriteString(" " + tupName + " = ") cdd.Expr(w, s.Rhs[0], nil) w.WriteString(";\n") cdd.indent(w) for i, n := 0, tup.Len(); i < n; i++ { rhs[i] = tupName + "._" + strconv.Itoa(i) if s.Tok == token.DEFINE { typ[i] = tup.At(i).Type() } } } else { for i, e := range s.Rhs { var t types.Type if s.Tok == token.DEFINE { t = cdd.exprType(e) } else { t = cdd.exprType(s.Lhs[i]) } rhs[i] = cdd.ExprStr(e, t) typ[i] = t } } lhs := make([]string, len(s.Lhs)) if s.Tok == token.DEFINE { for i, e := range s.Lhs { name := cdd.NameStr(cdd.object(e.(*ast.Ident)), true) if name == "_$" { lhs[i] = "_" } else { t, dim, a := cdd.TypeStr(typ[i]) acds = append(acds, a...) lhs[i] = t + " " + dimFuncPtr(name, dim) } } } else { for i, e := range s.Lhs { lhs[i] = cdd.ExprStr(e, nil) } } if len(s.Rhs) == len(s.Lhs) && len(s.Lhs) > 1 && s.Tok != token.DEFINE { for i, t := range typ { if i > 0 { cdd.indent(w) } if lhs[i] == "_" { w.WriteString("(void)(") w.WriteString(rhs[i]) w.WriteString(");\n") } else { dim, a := cdd.Type(w, t) acds = append(acds, a...) tmp := "tmp" + cdd.gtc.uniqueId() w.WriteString(" " + dimFuncPtr(tmp, dim)) w.WriteString(" = " + rhs[i] + ";\n") rhs[i] = tmp } } cdd.indent(w) } var atok string switch s.Tok { case token.DEFINE: atok = " = " case token.AND_NOT_ASSIGN: atok = " &= " rhs[0] = "~(" + rhs[0] + ")" default: atok = " " + s.Tok.String() + " " } indent := false for i := 0; i < len(lhs); i++ { li := lhs[i] if li == "_" && rhsIsTuple { continue } if indent { cdd.indent(w) } else { indent = true } if li == "_" { w.WriteString("(void)(") w.WriteString(rhs[i]) w.WriteString(");\n") } else { w.WriteString(li) w.WriteString(atok) w.WriteString(rhs[i]) w.WriteString(";\n") } } case *ast.ExprStmt: cdd.Expr(w, s.X, nil) w.WriteString(";\n") case *ast.IfStmt: if s.Init != nil { w.WriteString("{\n") cdd.il++ cdd.indent(w) updateEA(cdd.Stmt(w, s.Init, "", resultT, tup)) cdd.indent(w) } w.WriteString("if (") cdd.Expr(w, s.Cond, nil) w.WriteString(") ") updateEA(cdd.BlockStmt(w, s.Body, resultT, tup)) if s.Else == nil { w.WriteByte('\n') } else { w.WriteString(" else ") updateEA(cdd.Stmt(w, s.Else, "", resultT, tup)) } if s.Init != nil { cdd.il-- cdd.indent(w) w.WriteString("}\n") } case *ast.IncDecStmt: w.WriteString(s.Tok.String()) w.WriteByte('(') cdd.Expr(w, s.X, nil) w.WriteString(");\n") case *ast.BlockStmt: updateEA(cdd.BlockStmt(w, s, resultT, tup)) w.WriteByte('\n') case *ast.ForStmt: if s.Init != nil { w.WriteString("{\n") cdd.il++ cdd.indent(w) updateEA(cdd.Stmt(w, s.Init, "", resultT, tup)) cdd.indent(w) } if label != "" && s.Post == nil { w.WriteString(label + "_continue: ") } w.WriteString("while (") if s.Cond != nil { cdd.Expr(w, s.Cond, nil) } else { w.WriteString("true") } w.WriteString(") ") if s.Post != nil { w.WriteString("{\n") cdd.il++ cdd.indent(w) } updateEA(cdd.BlockStmt(w, s.Body, resultT, tup)) w.WriteByte('\n') if s.Post != nil { if label != "" { cdd.label(w, label, "_continue") } cdd.indent(w) updateEA(cdd.Stmt(w, s.Post, "", resultT, tup)) cdd.il-- cdd.indent(w) w.WriteString("}\n") } if s.Init != nil { cdd.il-- cdd.indent(w) w.WriteString("}\n") } if label != "" { cdd.label(w, label, "_break") } case *ast.RangeStmt: w.WriteString("{\n") cdd.il++ xt := cdd.exprType(s.X) xs := "x" xl := "" array := false switch t := xt.(type) { case *types.Array: array = true xl = strconv.FormatInt(t.Len(), 10) case *types.Pointer: array = true xl = strconv.FormatInt(t.Elem().(*types.Array).Len(), 10) } if v, ok := s.Value.(*ast.Ident); ok && v.Name == "_" { s.Value = nil } switch e := s.X.(type) { case *ast.Ident: xs = cdd.NameStr(cdd.object(e), true) default: if s.Value != nil || !array { cdd.indent(w) cdd.varDecl(w, xt, false, xs, e) } } if !array { xl = "len(" + xs + ")" } switch xt.(type) { case *types.Slice, *types.Array, *types.Pointer: cdd.indent(w) ks := cdd.ExprStr(s.Key, nil) if s.Tok == token.DEFINE { w.WriteString("int ") } w.WriteString(ks + " = 0;\n") if label != "" { cdd.label(w, label, "_continue") } cdd.indent(w) w.WriteString("for (; " + ks + " < " + xl + "; ++" + ks + ") ") if s.Value != nil { w.WriteString("{\n") cdd.il++ cdd.indent(w) if s.Tok == token.DEFINE { t := xt if pt, ok := xt.(*types.Pointer); ok { t = pt.Elem() } vt := t.(interface { Elem() types.Type }).Elem() dim, _ := cdd.Type(w, vt) w.WriteByte(' ') w.WriteString(dimFuncPtr(cdd.ExprStr(s.Value, nil), dim)) } else { cdd.Expr(w, s.Value, nil) } w.WriteString(" = ") cdd.indexExpr(w, xt, xs, s.Key) w.WriteString(";\n") cdd.indent(w) } default: notImplemented(s, xt) } updateEA(cdd.BlockStmt(w, s.Body, resultT, tup)) w.WriteByte('\n') if s.Value != nil { cdd.il-- cdd.indent(w) w.WriteString("}\n") } cdd.il-- cdd.indent(w) w.WriteString("}\n") if label != "" { cdd.label(w, label, "_break") } case *ast.ReturnStmt: end = cdd.ReturnStmt(w, s, resultT, tup) case *ast.SwitchStmt: w.WriteString("switch(0) {\n") cdd.indent(w) w.WriteString("case 0:;\n") cdd.il++ if s.Init != nil { cdd.indent(w) updateEA(cdd.Stmt(w, s.Init, "", resultT, tup)) } cdd.indent(w) var typ types.Type if s.Tag != nil { typ = cdd.exprType(s.Tag) cdd.varDecl(w, typ, false, "tag", s.Tag) } else { typ = types.Typ[types.Bool] w.WriteString("bool tag = true;\n") } for _, stmt := range s.Body.List { cdd.indent(w) cs := stmt.(*ast.CaseClause) if cs.List != nil { w.WriteString("if (") for i, e := range cs.List { if i != 0 { w.WriteString(" || ") } eq(w, "tag", "==", cdd.ExprStr(e, typ), typ, typ) } w.WriteString(") ") } w.WriteString("{\n") cdd.il++ brk := true if n := len(cs.Body) - 1; n >= 0 { bs, ok := cs.Body[n].(*ast.BranchStmt) if ok && bs.Tok == token.FALLTHROUGH { brk = false cs.Body = cs.Body[:n] } } for _, s := range cs.Body { cdd.indent(w) updateEA(cdd.Stmt(w, s, "", resultT, tup)) } if brk { cdd.indent(w) w.WriteString("break;\n") } cdd.il-- cdd.indent(w) w.WriteString("}\n") } cdd.il-- cdd.indent(w) w.WriteString("}\n") if label != "" { cdd.label(w, label, "_break") } case *ast.BranchStmt: if s.Label == nil { w.WriteString(s.Tok.String()) } else { w.WriteString("goto " + s.Label.Name + "$") switch s.Tok { case token.BREAK: w.WriteString("_break") case token.CONTINUE: w.WriteString("_continue") } } w.WriteString(";\n") case *ast.GoStmt: a := cdd.GoStmt(w, s) acds = append(acds, a...) case *ast.SendStmt: et := cdd.exprType(s.Chan).(*types.Chan).Elem() w.WriteString("SEND(") cdd.Expr(w, s.Chan, nil) w.WriteString(", ") dim, a := cdd.Type(w, et) w.WriteString(dimFuncPtr("", dim)) w.WriteString(", ") cdd.Expr(w, s.Value, et) w.WriteString(");\n") acds = append(acds, a...) case *ast.SelectStmt: w.WriteString("switch(0) {\n") cdd.indent(w) w.WriteString("case 0:;\n") cdd.il++ dflt := false for i, stmt := range s.Body.List { switch s := stmt.(*ast.CommClause).Comm.(type) { case nil: dflt = true continue case *ast.SendStmt: cdd.indent(w) w.WriteString("SENDINIT(" + strconv.Itoa(i) + ", ") cdd.Expr(w, s.Chan, nil) w.WriteString(", ") et := cdd.exprType(s.Chan).(*types.Chan).Elem() dim, a := cdd.Type(w, et) dimFuncPtr("", dim) w.WriteString(", ") cdd.Expr(w, s.Value, et) w.WriteString(");\n") acds = append(acds, a...) default: cdd.indent(w) w.WriteString("RECVINIT(" + strconv.Itoa(i) + ", ") var c ast.Expr switch r := s.(type) { case *ast.AssignStmt: c = r.Rhs[0].(*ast.UnaryExpr).X case *ast.ExprStmt: c = r.X.(*ast.UnaryExpr).X default: notImplemented(s) } cdd.Expr(w, c, nil) w.WriteString(", ") et := cdd.exprType(c).(*types.Chan).Elem() dim, a := cdd.Type(w, et) dimFuncPtr("", dim) w.WriteString(");\n") acds = append(acds, a...) } } cdd.indent(w) n := len(s.Body.List) if dflt { w.WriteString("NBSELECT(\n") n-- } else { w.WriteString("SELECT(\n") } cdd.il++ for i, stmt := range s.Body.List { s := stmt.(*ast.CommClause).Comm switch s.(type) { case nil: continue case *ast.SendStmt: cdd.indent(w) w.WriteString("SENDCOMM(" + strconv.Itoa(i) + ")") default: cdd.indent(w) w.WriteString("RECVCOMM(" + strconv.Itoa(i) + ")") } if n--; n > 0 { w.WriteByte(',') } w.WriteByte('\n') } cdd.il-- cdd.indent(w) w.WriteString(");\n") for i, stmt := range s.Body.List { cc := stmt.(*ast.CommClause) s := cc.Comm cdd.indent(w) switch s.(type) { case nil: w.WriteString("DEFAULT {\n") default: w.WriteString("CASE(" + strconv.Itoa(i) + ") {\n") } cdd.il++ switch s := s.(type) { case nil: case *ast.SendStmt: cdd.indent(w) w.WriteString("SELSEND(" + strconv.Itoa(i) + ");\n") case *ast.AssignStmt: cdd.indent(w) name := cdd.ExprStr(s.Lhs[0], nil) if len(s.Lhs) == 1 { if name != "_$" { if s.Tok == token.DEFINE { dim, a := cdd.Type(w, cdd.exprType(s.Rhs[0])) w.WriteString(" " + dimFuncPtr(name, dim)) acds = append(acds, a...) } else { w.WriteString(name) } w.WriteString(" = ") } w.WriteString("SELRECV(" + strconv.Itoa(i) + ");\n") } else { ok := cdd.ExprStr(s.Lhs[1], nil) tmp := "" var tup *types.Tuple if name != "_$" || ok != "_$" { tup = cdd.exprType(s.Rhs[0]).(*types.Tuple) tupName, _, a := cdd.tupleName(tup) acds = append(acds, a...) w.WriteString(tupName + " ") tmp = "tmp" + cdd.gtc.uniqueId() w.WriteString(tmp + " = ") } w.WriteString("SELRECVOK(" + strconv.Itoa(i) + ");\n") if name != "_$" { cdd.indent(w) if s.Tok == token.DEFINE { dim, a := cdd.Type(w, tup.At(0).Type()) w.WriteString(" " + dimFuncPtr(name, dim)) acds = append(acds, a...) } else { w.WriteString(name) } w.WriteString(" = " + tmp + "._0;\n") } if ok != "_$" { cdd.indent(w) if s.Tok == token.DEFINE { w.WriteString("bool ") } w.WriteString(ok + " = " + tmp + "._1;\n") } } case *ast.ExprStmt: cdd.indent(w) w.WriteString("SELRECV(" + strconv.Itoa(i) + ")\n") default: notImplemented(s) } for _, s = range cc.Body { cdd.indent(w) updateEA(cdd.Stmt(w, s, "", resultT, tup)) } cdd.indent(w) w.WriteString("break;\n") cdd.il-- cdd.indent(w) w.WriteString("}\n") } cdd.il-- cdd.indent(w) w.WriteString("}\n") default: notImplemented(s) } return }
// buildFunction takes a function Value, a list of parameters, and a body, // and generates code for the function. func (c *compiler) buildFunction(f *LLVMValue, context, params, results *types.Tuple, body *ast.BlockStmt) { if currblock := c.builder.GetInsertBlock(); !currblock.IsNil() { defer c.builder.SetInsertPointAtEnd(currblock) } llvm_fn := llvm.ConstExtractValue(f.LLVMValue(), []uint32{0}) entry := llvm.AddBasicBlock(llvm_fn, "entry") c.builder.SetInsertPointAtEnd(entry) // For closures, context is the captured context values. var paramoffset int if context != nil { paramoffset++ // Store the existing values. We're going to temporarily // replace the values with offsets into the context param. oldvalues := make([]*LLVMValue, context.Len()) for i := range oldvalues { v := context.At(i) oldvalues[i] = c.objectdata[v].Value } defer func() { for i := range oldvalues { v := context.At(i) c.objectdata[v].Value = oldvalues[i] } }() // The context parameter is a pointer to a struct // whose elements are pointers to captured values. arg0 := llvm_fn.Param(0) for i := range oldvalues { v := context.At(i) argptr := c.builder.CreateStructGEP(arg0, i, "") argptr = c.builder.CreateLoad(argptr, "") ptrtyp := oldvalues[i].pointer.Type() newvalue := c.NewValue(argptr, ptrtyp) c.objectdata[v].Value = newvalue.makePointee() } } // Bind receiver, arguments and return values to their // identifiers/objects. We'll store each parameter on the stack so // they're addressable. nparams := int(params.Len()) for i := 0; i < nparams; i++ { v := params.At(i) name := v.Name() if !isBlank(name) { value := llvm_fn.Param(i + paramoffset) c.newArgStackVar(i+1, f, v, value, name) } } funcstate := &function{LLVMValue: f, results: results} c.functions.push(funcstate) hasdefer := hasDefer(funcstate, body) // Allocate space on the stack for named results. for i := 0; i < results.Len(); i++ { v := results.At(i) name := v.Name() allocstack := !isBlank(name) if !allocstack && hasdefer { c.objectdata[v] = &ObjectData{} allocstack = true } if allocstack { typ := v.Type() llvmtyp := c.types.ToLLVM(typ) c.newStackVar(f, v, llvm.ConstNull(llvmtyp), name) } } // Create the function body. if hasdefer { c.makeDeferBlock(funcstate, body) } c.VisitBlockStmt(body, false) c.functions.pop() c.setDebugLine(body.End()) // If the last instruction in the function is not a terminator, then // we either have unreachable code or a missing optional return statement // (the latter case is allowable only for functions without results). // // Use GetInsertBlock rather than LastBasicBlock, since the // last basic block might actually be a "defer" block. last := c.builder.GetInsertBlock() if in := last.LastInstruction(); in.IsNil() || in.IsATerminatorInst().IsNil() { c.builder.SetInsertPointAtEnd(last) if results.Len() == 0 { if funcstate.deferblock.IsNil() { c.builder.CreateRetVoid() } else { c.builder.CreateBr(funcstate.deferblock) } } else { c.builder.CreateUnreachable() } } }