func (m *TypeMap) descriptorInterface(t *types.Interface, name string) TypeDebugDescriptor { ifaceStruct := types.NewStruct([]*types.Var{ types.NewVar(0, nil, "type", types.NewPointer(types.Typ[types.Uint8])), types.NewVar(0, nil, "data", types.NewPointer(types.Typ[types.Uint8])), }, nil) return m.typeDebugDescriptor(ifaceStruct, name) }
func WriteInterfaces(dependencies []*types.Package, w io.Writer, merge bool) { allTypeNames := []*types.TypeName{types.New("error").(*types.Named).Obj()} for _, dep := range dependencies { scope := dep.Scope() for _, name := range scope.Names() { if typeName, isTypeName := scope.Lookup(name).(*types.TypeName); isTypeName { allTypeNames = append(allTypeNames, typeName) } } } for _, t := range allTypeNames { if in, isInterface := t.Type().Underlying().(*types.Interface); isInterface { if in.MethodSet().Len() == 0 { continue } implementedBy := make(map[string]bool, 0) for _, other := range allTypeNames { otherType := other.Type() switch otherType.Underlying().(type) { case *types.Interface: // skip case *types.Struct: if types.IsAssignableTo(otherType, in) { implementedBy[fmt.Sprintf("Go$packages[\"%s\"].%s.Go$NonPointer", other.Pkg().Path(), other.Name())] = true } if types.IsAssignableTo(types.NewPointer(otherType), in) { implementedBy[fmt.Sprintf("Go$packages[\"%s\"].%s", other.Pkg().Path(), other.Name())] = true } default: if types.IsAssignableTo(otherType, in) { implementedBy[fmt.Sprintf("Go$packages[\"%s\"].%s", other.Pkg().Path(), other.Name())] = true } if types.IsAssignableTo(types.NewPointer(otherType), in) { implementedBy[fmt.Sprintf("Go$packages[\"%s\"].%s.Go$Pointer", other.Pkg().Path(), other.Name())] = true } } } list := make([]string, 0, len(implementedBy)) for ref := range implementedBy { list = append(list, ref) } sort.Strings(list) var target string switch t.Name() { case "error": target = "Go$error" default: target = fmt.Sprintf("Go$packages[\"%s\"].%s", t.Pkg().Path(), t.Name()) } if merge { for _, entry := range list { fmt.Fprintf(w, "if (%s.Go$implementedBy.indexOf(%s) === -1) { %s.Go$implementedBy.push(%s); }\n", target, entry, target, entry) } continue } fmt.Fprintf(w, "%s.Go$implementedBy = [%s];\n", target, strings.Join(list, ", ")) } } }
// testMainSlice emits to fn code to construct a slice of type slice // (one of []testing.Internal{Test,Benchmark,Example}) for all // functions in this package whose name starts with prefix (one of // "Test", "Benchmark" or "Example") and whose type is appropriate. // It returns the slice value. // func testMainSlice(fn *Function, prefix string, slice types.Type) Value { tElem := slice.(*types.Slice).Elem() tFunc := tElem.Underlying().(*types.Struct).Field(1).Type() var testfuncs []*Function for name, mem := range fn.Pkg.Members { if fn, ok := mem.(*Function); ok && isTest(name, prefix) && types.IsIdentical(fn.Signature, tFunc) { testfuncs = append(testfuncs, fn) } } if testfuncs == nil { return nilConst(slice) } tString := types.Typ[types.String] tPtrString := types.NewPointer(tString) tPtrElem := types.NewPointer(tElem) tPtrFunc := types.NewPointer(tFunc) // Emit: array = new [n]testing.InternalTest tArray := types.NewArray(tElem, int64(len(testfuncs))) array := emitNew(fn, tArray, token.NoPos) array.Comment = "test main" for i, testfunc := range testfuncs { // Emit: pitem = &array[i] ia := &IndexAddr{X: array, Index: intConst(int64(i))} ia.setType(tPtrElem) pitem := fn.emit(ia) // Emit: pname = &pitem.Name fa := &FieldAddr{X: pitem, Field: 0} // .Name fa.setType(tPtrString) pname := fn.emit(fa) // Emit: *pname = "testfunc" emitStore(fn, pname, NewConst(exact.MakeString(testfunc.Name()), tString)) // Emit: pfunc = &pitem.F fa = &FieldAddr{X: pitem, Field: 1} // .F fa.setType(tPtrFunc) pfunc := fn.emit(fa) // Emit: *pfunc = testfunc emitStore(fn, pfunc, testfunc) } // Emit: slice array[:] sl := &Slice{X: array} sl.setType(slice) return fn.emit(sl) }
func (c *compiler) VisitIndexExpr(expr *ast.IndexExpr) Value { value := c.VisitExpr(expr.X) index := c.VisitExpr(expr.Index) typ := value.Type().Underlying() if isString(typ) { ptr := c.builder.CreateExtractValue(value.LLVMValue(), 0, "") gepindices := []llvm.Value{index.LLVMValue()} ptr = c.builder.CreateGEP(ptr, gepindices, "") byteType := types.Typ[types.Byte] result := c.NewValue(ptr, types.NewPointer(byteType)) return result.makePointee() } // We can index a pointer to an array. if _, ok := typ.(*types.Pointer); ok { value = value.(*LLVMValue).makePointee() typ = value.Type().Underlying() } switch typ := typ.(type) { case *types.Array: index := index.Convert(types.Typ[types.Int]).LLVMValue() var ptr llvm.Value value := value.(*LLVMValue) if value.pointer != nil { ptr = value.pointer.LLVMValue() } else { init := value.LLVMValue() ptr = c.builder.CreateAlloca(init.Type(), "") c.builder.CreateStore(init, ptr) } zero := llvm.ConstNull(llvm.Int32Type()) element := c.builder.CreateGEP(ptr, []llvm.Value{zero, index}, "") result := c.NewValue(element, types.NewPointer(typ.Elem())) return result.makePointee() case *types.Slice: index := index.Convert(types.Typ[types.Int]).LLVMValue() ptr := c.builder.CreateExtractValue(value.LLVMValue(), 0, "") element := c.builder.CreateGEP(ptr, []llvm.Value{index}, "") result := c.NewValue(element, types.NewPointer(typ.Elem())) return result.makePointee() case *types.Map: value, _ = c.mapLookup(value.(*LLVMValue), index, false) return value } panic(fmt.Sprintf("unreachable (%s)", typ)) }
func (c *funcContext) initType(o types.Object) { if _, isInterface := o.Type().Underlying().(*types.Interface); !isInterface { writeMethodSet := func(t types.Type) { methodSet := types.NewMethodSet(t) if methodSet.Len() == 0 { return } methods := make([]string, methodSet.Len()) for i := range methods { method := methodSet.At(i) pkgPath := "" if !method.Obj().Exported() { pkgPath = method.Obj().Pkg().Path() } t := method.Type().(*types.Signature) embeddedIndex := -1 if len(method.Index()) > 1 { embeddedIndex = method.Index()[0] } methods[i] = fmt.Sprintf(`["%s", "%s", %s, %s, %t, %d]`, method.Obj().Name(), pkgPath, c.typeArray(t.Params()), c.typeArray(t.Results()), t.Variadic(), embeddedIndex) } c.Printf("%s.methods = [%s];", c.typeName(t), strings.Join(methods, ", ")) } writeMethodSet(o.Type()) writeMethodSet(types.NewPointer(o.Type())) } switch t := o.Type().Underlying().(type) { case *types.Array, *types.Chan, *types.Interface, *types.Map, *types.Pointer, *types.Slice, *types.Signature, *types.Struct: c.Printf("%s.init(%s);", c.objectName(o), c.initArgs(t)) } }
// emitNew emits to f a new (heap Alloc) instruction allocating an // object of type typ. pos is the optional source location. // func emitNew(f *Function, typ types.Type, pos token.Pos) *Alloc { v := &Alloc{Heap: true} v.setType(types.NewPointer(typ)) v.setPos(pos) f.emit(v) return v }
// emitImplicitSelections emits to f code to apply the sequence of // implicit field selections specified by indices to base value v, and // returns the selected value. // // If v is the address of a struct, the result will be the address of // a field; if it is the value of a struct, the result will be the // value of a field. // func emitImplicitSelections(f *Function, v Value, indices []int) Value { for _, index := range indices { fld := deref(v.Type()).Underlying().(*types.Struct).Field(index) if isPointer(v.Type()) { instr := &FieldAddr{ X: v, Field: index, } instr.setType(types.NewPointer(fld.Type())) v = f.emit(instr) // Load the field's value iff indirectly embedded. if isPointer(fld.Type()) { v = emitLoad(f, v) } } else { instr := &Field{ X: v, Field: index, } instr.setType(fld.Type()) v = f.emit(instr) } } return v }
func checkVarValue(t *testing.T, prog *ssa.Program, pkg *ssa.Package, ref []ast.Node, obj *types.Var, expKind string, wantAddr bool) { // The prefix of all assertions messages. prefix := fmt.Sprintf("VarValue(%s @ L%d)", obj, prog.Fset.Position(ref[0].Pos()).Line) v := prog.VarValue(obj, pkg, ref) // Kind is the concrete type of the ssa Value. gotKind := "nil" if v != nil { gotKind = fmt.Sprintf("%T", v)[len("*ssa."):] } // fmt.Printf("%s = %v (kind %q; expect %q) addr=%t\n", prefix, v, gotKind, expKind, wantAddr) // debugging // Check the kinds match. // "nil" indicates expected failure (e.g. optimized away). if expKind != gotKind { t.Errorf("%s concrete type == %s, want %s", prefix, gotKind, expKind) } // Check the types match. // If wantAddr, the expected type is the object's address. if v != nil { expType := obj.Type() if wantAddr { expType = types.NewPointer(expType) } if !types.IsIdentical(v.Type(), expType) { t.Errorf("%s.Type() == %s, want %s", prefix, v.Type(), expType) } } }
// emitFieldSelection emits to f code to select the index'th field of v. // // If wantAddr, the input must be a pointer-to-struct and the result // will be the field's address; otherwise the result will be the // field's value. // func emitFieldSelection(f *Function, v Value, index int, wantAddr bool, pos token.Pos) Value { fld := deref(v.Type()).Underlying().(*types.Struct).Field(index) if isPointer(v.Type()) { instr := &FieldAddr{ X: v, Field: index, } instr.setPos(pos) instr.setType(types.NewPointer(fld.Type())) v = f.emit(instr) // Load the field's value iff we don't want its address. if !wantAddr { v = emitLoad(f, v) } } else { instr := &Field{ X: v, Field: index, } instr.setPos(pos) instr.setType(fld.Type()) v = f.emit(instr) } return v }
// lockPath returns a typePath describing the location of a lock value // contained in typ. If there is no contained lock, it returns nil. func lockPath(tpkg *types.Package, typ types.Type) typePath { if typ == nil { return nil } // We're only interested in the case in which the underlying // type is a struct. (Interfaces and pointers are safe to copy.) styp, ok := typ.Underlying().(*types.Struct) if !ok { return nil } // We're looking for cases in which a reference to this type // can be locked, but a value cannot. This differentiates // embedded interfaces from embedded values. if plock := types.NewMethodSet(types.NewPointer(typ)).Lookup(tpkg, "Lock"); plock != nil { if lock := types.NewMethodSet(typ).Lookup(tpkg, "Lock"); lock == nil { return []types.Type{typ} } } nfields := styp.NumFields() for i := 0; i < nfields; i++ { ftyp := styp.Field(i).Type() subpath := lockPath(tpkg, ftyp) if subpath != nil { return append(subpath, typ) } } return nil }
func (c *compiler) exportRuntimeTypes(exportedTypes []types.Type, builtin bool) { if builtin { kinds := [...]types.BasicKind{ types.Uint, types.Uint8, types.Uint16, types.Uint32, types.Uint64, types.Int, types.Int8, types.Int16, types.Int32, types.Int64, types.Float32, types.Float64, types.Complex64, types.Complex128, types.Bool, types.Uintptr, types.UnsafePointer, types.String, } for _, kind := range kinds { exportedTypes = append(exportedTypes, types.Typ[kind]) } error_ := types.Universe.Lookup("error").Type() exportedTypes = append(exportedTypes, error_) } for _, typ := range exportedTypes { c.types.ToRuntime(types.NewPointer(typ)) } }
// mapLookup searches a map for a specified key, returning a pointer to the // memory location for the value. If insert is given as true, and the key // does not exist in the map, it will be added with an uninitialised value. func (c *compiler) mapLookup(m *LLVMValue, key Value, insert bool) (elem *LLVMValue, notnull *LLVMValue) { mapType := m.Type().Underlying().(*types.Map) maplookup := c.NamedFunction("runtime.maplookup", "func f(t, m, k uintptr, insert bool) uintptr") ptrType := c.target.IntPtrType() args := make([]llvm.Value, 4) args[0] = llvm.ConstPtrToInt(c.types.ToRuntime(mapType), ptrType) args[1] = c.builder.CreatePtrToInt(m.LLVMValue(), ptrType, "") if insert { args[3] = llvm.ConstAllOnes(llvm.Int1Type()) } else { args[3] = llvm.ConstNull(llvm.Int1Type()) } if lv, islv := key.(*LLVMValue); islv && lv.pointer != nil { args[2] = c.builder.CreatePtrToInt(lv.pointer.LLVMValue(), ptrType, "") } if args[2].IsNil() { stackval := c.builder.CreateAlloca(c.types.ToLLVM(key.Type()), "") c.builder.CreateStore(key.LLVMValue(), stackval) args[2] = c.builder.CreatePtrToInt(stackval, ptrType, "") } eltPtrType := types.NewPointer(mapType.Elem()) llvmtyp := c.types.ToLLVM(eltPtrType) zeroglobal := llvm.AddGlobal(c.module.Module, llvmtyp.ElementType(), "") zeroglobal.SetInitializer(llvm.ConstNull(llvmtyp.ElementType())) result := c.builder.CreateCall(maplookup, args, "") result = c.builder.CreateIntToPtr(result, llvmtyp, "") notnull_ := c.builder.CreateIsNotNull(result, "") result = c.builder.CreateSelect(notnull_, result, zeroglobal, "") value := c.NewValue(result, eltPtrType) return value.makePointee(), c.NewValue(notnull_, types.Typ[types.Bool]) }
func (c *compiler) exportRuntimeTypes() { if c.pkg.Path() == "runtime" { kinds := [...]types.BasicKind{ types.Uint, types.Uint8, types.Uint16, types.Uint32, types.Uint64, types.Int, types.Int8, types.Int16, types.Int32, types.Int64, types.Float32, types.Float64, types.Complex64, types.Complex128, types.Bool, types.Uintptr, types.UnsafePointer, types.String, } for _, kind := range kinds { c.exportedtypes = append(c.exportedtypes, types.Typ[kind]) } error_ := types.Universe.Lookup("error").Type() c.exportedtypes = append(c.exportedtypes, error_) } for _, typ := range c.exportedtypes { c.types.ToRuntime(typ) c.types.ToRuntime(types.NewPointer(typ)) } }
// addLocal creates an anonymous local variable of type typ, adds it // to function f and returns it. pos is the optional source location. // func (f *Function) addLocal(typ types.Type, pos token.Pos) *Alloc { v := &Alloc{} v.setType(types.NewPointer(typ)) v.setPos(pos) f.Locals = append(f.Locals, v) f.emit(v) return v }
// PointerType = "*" ("any" | Type) . func (p *parser) parsePointerType(pkg *types.Package) types.Type { p.expect('*') if p.tok == scanner.Ident { p.expectKeyword("any") return types.Typ[types.UnsafePointer] } return types.NewPointer(p.parseType(pkg)) }
func (m *TypeMap) descriptorSlice(t *types.Slice, name string) TypeDebugDescriptor { sliceStruct := types.NewStruct([]*types.Var{ types.NewVar(0, nil, "ptr", types.NewPointer(t.Elem())), types.NewVar(0, nil, "len", types.Typ[types.Int]), types.NewVar(0, nil, "cap", types.Typ[types.Int]), }, nil) return m.typeDebugDescriptor(sliceStruct, name) }
// memberFromObject populates package pkg with a member for the // typechecker object obj. // // For objects from Go source code, syntax is the associated syntax // tree (for funcs and vars only); it will be used during the build // phase. // func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node) { name := obj.Name() switch obj := obj.(type) { case *types.TypeName: pkg.Members[name] = &Type{object: obj} case *types.Const: c := &NamedConst{ object: obj, Value: NewConst(obj.Val(), obj.Type()), } pkg.values[obj] = c.Value pkg.Members[name] = c case *types.Var: spec, _ := syntax.(*ast.ValueSpec) g := &Global{ Pkg: pkg, name: name, object: obj, typ: types.NewPointer(obj.Type()), // address pos: obj.Pos(), spec: spec, } pkg.values[obj] = g pkg.Members[name] = g case *types.Func: var fs *funcSyntax synthetic := "loaded from gc object file" if decl, ok := syntax.(*ast.FuncDecl); ok { synthetic = "" fs = &funcSyntax{ functype: decl.Type, recvField: decl.Recv, body: decl.Body, } } fn := &Function{ name: name, object: obj, Signature: obj.Type().(*types.Signature), Synthetic: synthetic, pos: obj.Pos(), // (iff syntax) Pkg: pkg, Prog: pkg.Prog, syntax: fs, } pkg.values[obj] = fn if fn.Signature.Recv() == nil { pkg.Members[name] = fn // package-level function } default: // (incl. *types.Package) panic("unexpected Object type: " + obj.String()) } }
// addSpilledParam declares a parameter that is pre-spilled to the // stack; the function body will load/store the spilled location. // Subsequent lifting will eliminate spills where possible. // func (f *Function) addSpilledParam(obj types.Object) { param := f.addParamObj(obj) spill := &Alloc{Comment: obj.Name()} spill.setType(types.NewPointer(obj.Type())) spill.setPos(obj.Pos()) f.objects[obj] = spill f.Locals = append(f.Locals, spill) f.emit(spill) f.emit(&Store{Addr: spill, Val: param}) }
// testMainSlice emits to fn code to construct a slice of type slice // (one of []testing.Internal{Test,Benchmark,Example}) for all // functions in testfuncs. It returns the slice value. // func testMainSlice(fn *Function, testfuncs []*Function, slice types.Type) Value { if testfuncs == nil { return nilConst(slice) } tElem := slice.(*types.Slice).Elem() tPtrString := types.NewPointer(tString) tPtrElem := types.NewPointer(tElem) tPtrFunc := types.NewPointer(funcField(slice)) // Emit: array = new [n]testing.InternalTest tArray := types.NewArray(tElem, int64(len(testfuncs))) array := emitNew(fn, tArray, token.NoPos) array.Comment = "test main" for i, testfunc := range testfuncs { // Emit: pitem = &array[i] ia := &IndexAddr{X: array, Index: intConst(int64(i))} ia.setType(tPtrElem) pitem := fn.emit(ia) // Emit: pname = &pitem.Name fa := &FieldAddr{X: pitem, Field: 0} // .Name fa.setType(tPtrString) pname := fn.emit(fa) // Emit: *pname = "testfunc" emitStore(fn, pname, stringConst(testfunc.Name())) // Emit: pfunc = &pitem.F fa = &FieldAddr{X: pitem, Field: 1} // .F fa.setType(tPtrFunc) pfunc := fn.emit(fa) // Emit: *pfunc = testfunc emitStore(fn, pfunc, testfunc) } // Emit: slice array[:] sl := &Slice{X: array} sl.setType(slice) return fn.emit(sl) }
func (c *compiler) Resolve(ident *ast.Ident) Value { obj := c.typeinfo.Objects[ident] data := c.objectdata[obj] if data.Value != nil { return data.Value } var value *LLVMValue switch obj := obj.(type) { case *types.Func: value = c.makeFunc(ident, obj.Type().(*types.Signature)) case *synthFunc: value = c.makeFunc(ident, obj.Type().(*types.Signature)) case *types.Var: if data.Ident.Obj != nil { switch decl := data.Ident.Obj.Decl.(type) { case *ast.ValueSpec: c.VisitValueSpec(decl) case *ast.Field: // No-op. Fields will be yielded for function // arg/recv/ret. We update the .Data field of the // object when we enter the function definition. if data.Value == nil { panic("expected object value") } } } // If it's an external variable, we'll need to create a global // value reference here. It may be possible for multiple objects // to refer to the same variable. value = data.Value if value == nil { module := c.module.Module t := obj.Type() name := obj.Pkg().Path() + "." + obj.Name() g := module.NamedGlobal(name) if g.IsNil() { g = llvm.AddGlobal(module, c.types.ToLLVM(t), name) } value = c.NewValue(g, types.NewPointer(t)).makePointee() } case *types.Const: value = c.NewConstValue(obj.Val(), obj.Type()) default: panic(fmt.Sprintf("unreachable (%T)", obj)) } data.Value = value return value }
// memberFromObject populates package pkg with a member for the // typechecker object obj. // // For objects from Go source code, syntax is the associated syntax // tree (for funcs and vars only); it will be used during the build // phase. // func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node) { name := obj.Name() switch obj := obj.(type) { case *types.TypeName: pkg.values[obj] = nil // for needMethods pkg.Members[name] = &Type{ object: obj, pkg: pkg, } case *types.Const: c := &NamedConst{ object: obj, Value: NewConst(obj.Val(), obj.Type()), pkg: pkg, } pkg.values[obj] = c.Value pkg.Members[name] = c case *types.Var: g := &Global{ Pkg: pkg, name: name, object: obj, typ: types.NewPointer(obj.Type()), // address pos: obj.Pos(), } pkg.values[obj] = g pkg.Members[name] = g case *types.Func: fn := &Function{ name: name, object: obj, Signature: obj.Type().(*types.Signature), syntax: syntax, pos: obj.Pos(), // (iff syntax) Pkg: pkg, Prog: pkg.Prog, } if syntax == nil { fn.Synthetic = "loaded from gc object file" } pkg.values[obj] = fn if fn.Signature.Recv() == nil { pkg.Members[name] = fn // package-level function } default: // (incl. *types.Package) panic("unexpected Object type: " + obj.String()) } }
// mapNext iterates through a map, accepting an iterator state value, // and returning a new state value, key pointer, and value pointer. func (c *compiler) mapNext(m *LLVMValue, nextin llvm.Value) (nextout, pk, pv llvm.Value) { mapnext := c.NamedFunction("runtime.mapnext", "func f(t, m, n uintptr) (uintptr, uintptr, uintptr)") mapType := m.Type().Underlying().(*types.Map) ptrType := c.target.IntPtrType() args := make([]llvm.Value, 3) args[0] = llvm.ConstPtrToInt(c.types.ToRuntime(mapType), ptrType) args[1] = c.builder.CreatePtrToInt(m.LLVMValue(), ptrType, "") args[2] = nextin results := c.builder.CreateCall(mapnext, args, "") nextout = c.builder.CreateExtractValue(results, 0, "") pk = c.builder.CreateExtractValue(results, 1, "") pv = c.builder.CreateExtractValue(results, 2, "") keyptrtype := types.NewPointer(mapType.Key()) valptrtype := types.NewPointer(mapType.Elem()) pk = c.builder.CreateIntToPtr(pk, c.types.ToLLVM(keyptrtype), "") pv = c.builder.CreateIntToPtr(pv, c.types.ToLLVM(valptrtype), "") return }
func (c *compiler) newStackVarEx(argument int, stackf *LLVMValue, v types.Object, value llvm.Value, name string) (stackvalue llvm.Value, stackvar *LLVMValue) { typ := v.Type() // We need to put alloca instructions in the top block or the values // displayed when inspecting these variables in a debugger will be // completely messed up. curBlock := c.builder.GetInsertBlock() if p := curBlock.Parent(); !p.IsNil() { fb := p.FirstBasicBlock() fi := fb.FirstInstruction() if !fb.IsNil() && !fi.IsNil() { c.builder.SetInsertPointBefore(fi) } } old := c.builder.CurrentDebugLocation() c.builder.SetCurrentDebugLocation(llvm.Value{}) stackvalue = c.builder.CreateAlloca(c.types.ToLLVM(typ), name) // For arguments we want to insert the store instruction // without debug information to ensure that they are executed // (and hence have proper values) before the debugger hits the // first line in a function. if argument == 0 { c.builder.SetCurrentDebugLocation(old) c.builder.SetInsertPointAtEnd(curBlock) } if !value.IsNil() { c.builder.CreateStore(value, stackvalue) } c.builder.SetCurrentDebugLocation(old) c.builder.SetInsertPointAtEnd(curBlock) ptrvalue := c.NewValue(stackvalue, types.NewPointer(typ)) stackvar = ptrvalue.makePointee() stackvar.stack = stackf c.objectdata[v].Value = stackvar file := c.fileset.File(v.Pos()) tag := llvm.DW_TAG_auto_variable if argument > 0 { tag = llvm.DW_TAG_arg_variable } ld := llvm.NewLocalVariableDescriptor(tag) ld.Argument = uint32(argument) ld.Line = uint32(file.Line(v.Pos())) ld.Name = name ld.File = &llvm.ContextDescriptor{llvm.FileDescriptor(file.Name())} ld.Type = c.tollvmDebugDescriptor(typ) ld.Context = c.currentDebugContext() c.builder.InsertDeclare(c.module.Module, llvm.MDNode([]llvm.Value{stackvalue}), c.debug_info.MDNode(ld)) return stackvalue, stackvar }
func (visit *visitor) program() { for _, pkg := range visit.prog.AllPackages() { for _, mem := range pkg.Members { switch mem := mem.(type) { case *Function: visit.function(mem) case *Type: visit.methodSet(mem.Type()) visit.methodSet(types.NewPointer(mem.Type())) } } } }
func (c *reflectPtrToConstraint) solve(a *analysis, _ *node, delta nodeset) { changed := false for tObj := range delta { T := a.rtypeTaggedValue(tObj) if a.addLabel(c.result, a.makeRtype(types.NewPointer(T))) { changed = true } } if changed { a.addWork(c.result) } }
func (c *compiler) VisitAppend(expr *ast.CallExpr) Value { s := c.VisitExpr(expr.Args[0]) elemtyp := s.Type().Underlying().(*types.Slice).Elem() if len(expr.Args) == 1 { return s } else if expr.Ellipsis.IsValid() { c.convertUntyped(expr.Args[1], s.Type()) } else { for _, arg := range expr.Args[1:] { c.convertUntyped(arg, elemtyp) } } sliceappend := c.NamedFunction("runtime.sliceappend", "func(t uintptr, dst, src slice) slice") i8slice := sliceappend.Type().ElementType().ReturnType() i8ptr := c.types.ToLLVM(types.NewPointer(types.Typ[types.Int8])) // Coerce first argument into an []int8. a_ := s.LLVMValue() sliceTyp := a_.Type() a := c.coerceSlice(a_, i8slice) var b llvm.Value if expr.Ellipsis.IsValid() { // Pass the provided slice straight through. If it's a string, // convert it to a []byte first. elem := c.VisitExpr(expr.Args[1]).Convert(s.Type()) b = c.coerceSlice(elem.LLVMValue(), i8slice) } else { // Construct a fresh []int8 for the temporary slice. n := llvm.ConstInt(c.types.inttype, uint64(len(expr.Args)-1), false) mem := c.builder.CreateArrayAlloca(c.types.ToLLVM(elemtyp), n, "") for i, arg := range expr.Args[1:] { elem := c.VisitExpr(arg).Convert(elemtyp) indices := []llvm.Value{llvm.ConstInt(llvm.Int32Type(), uint64(i), false)} ptr := c.builder.CreateGEP(mem, indices, "") c.builder.CreateStore(elem.LLVMValue(), ptr) } b = llvm.Undef(i8slice) b = c.builder.CreateInsertValue(b, c.builder.CreateBitCast(mem, i8ptr, ""), 0, "") b = c.builder.CreateInsertValue(b, n, 1, "") b = c.builder.CreateInsertValue(b, n, 2, "") } // Call runtime function, then coerce the result. runtimeTyp := c.types.ToRuntime(s.Type()) runtimeTyp = c.builder.CreatePtrToInt(runtimeTyp, c.target.IntPtrType(), "") args := []llvm.Value{runtimeTyp, a, b} result := c.builder.CreateCall(sliceappend, args, "") return c.NewValue(c.coerceSlice(result, sliceTyp), s.Type()) }
func (c *compiler) newStackVarEx(argument int, stackf *LLVMValue, v types.Object, value llvm.Value, name string) (stackvalue llvm.Value, stackvar *LLVMValue) { typ := v.Type() // We need to put alloca instructions in the top block or the values // displayed when inspecting these variables in a debugger will be // completely messed up. curBlock := c.builder.GetInsertBlock() if p := curBlock.Parent(); !p.IsNil() { fb := p.FirstBasicBlock() fi := fb.FirstInstruction() if !fb.IsNil() && !fi.IsNil() { c.builder.SetInsertPointBefore(fi) } } old := c.builder.CurrentDebugLocation() c.builder.SetCurrentDebugLocation(llvm.Value{}) stackvalue = c.builder.CreateAlloca(c.types.ToLLVM(typ), name) // For arguments we want to insert the store instruction // without debug information to ensure that they are executed // (and hence have proper values) before the debugger hits the // first line in a function. if argument == 0 { c.builder.SetCurrentDebugLocation(old) c.builder.SetInsertPointAtEnd(curBlock) } if !value.IsNil() { c.builder.CreateStore(value, stackvalue) } c.builder.SetCurrentDebugLocation(old) c.builder.SetInsertPointAtEnd(curBlock) ptrvalue := c.NewValue(stackvalue, types.NewPointer(typ)) stackvar = ptrvalue.makePointee() stackvar.stack = stackf c.objectdata[v].Value = stackvar // Generate debug metadata (will return nil // if debug-data generation is disabled). if descriptor := c.createLocalVariableMetadata(v, argument); descriptor != nil { c.builder.InsertDeclare( c.module.Module, llvm.MDNode([]llvm.Value{stackvalue}), c.debug_info.MDNode(descriptor), ) } return stackvalue, stackvar }
// Type = // BasicType | TypeName | ArrayType | SliceType | StructType | // PointerType | FuncType | InterfaceType | MapType | ChanType | // "(" Type ")" . // // BasicType = ident . // TypeName = ExportedName . // SliceType = "[" "]" Type . // PointerType = "*" Type . // FuncType = "func" Signature . // func (p *parser) parseType() types.Type { switch p.tok { case scanner.Ident: switch p.lit { default: return p.parseBasicType() case "struct": return p.parseStructType() case "func": // FuncType p.next() return p.parseSignature(nil) case "interface": return p.parseInterfaceType() case "map": return p.parseMapType() case "chan": return p.parseChanType() } case '@': // TypeName pkg, name := p.parseExportedName() return declTypeName(pkg, name).Type() case '[': p.next() // look ahead if p.tok == ']' { // SliceType p.next() return types.NewSlice(p.parseType()) } return p.parseArrayType() case '*': // PointerType p.next() return types.NewPointer(p.parseType()) case '<': return p.parseChanType() case '(': // "(" Type ")" p.next() typ := p.parseType() p.expect(')') return typ } p.errorf("expected type, got %s (%q)", scanner.TokenString(p.tok), p.lit) return nil }
func (m *TypeMap) descriptorSignature(t *types.Signature, name string) TypeDebugDescriptor { // If there's a receiver change the receiver to an // additional (first) parameter, and take the value of // the resulting signature instead. if recv := t.Recv(); recv != nil { params := t.Params() paramvars := make([]*types.Var, int(params.Len()+1)) paramvars[0] = recv for i := 0; i < int(params.Len()); i++ { paramvars[i+1] = params.At(i) } params = types.NewTuple(paramvars...) t := types.NewSignature(nil, nil, params, t.Results(), t.Variadic()) return m.typeDebugDescriptor(t, name) } if dt, ok := m.m.At(t).(TypeDebugDescriptor); ok { return dt } var returnType DebugDescriptor var paramTypes []DebugDescriptor if results := t.Results(); results.Len() == 1 { returnType = m.TypeDebugDescriptor(results.At(0).Type()) } else if results != nil { fields := make([]DebugDescriptor, results.Len()) for i := range fields { fields[i] = m.TypeDebugDescriptor(results.At(i).Type()) } returnType = NewStructCompositeType(fields) } if params := t.Params(); params != nil && params.Len() > 0 { paramTypes = make([]DebugDescriptor, params.Len()) for i := range paramTypes { paramTypes[i] = m.TypeDebugDescriptor(params.At(i).Type()) } } ct := NewStructCompositeType([]DebugDescriptor{ NewSubroutineCompositeType(returnType, paramTypes), m.TypeDebugDescriptor(types.NewPointer(types.Typ[types.Uint8])), }) ct.Name = name m.m.Set(t, ct) return ct }
// loadI2V loads an interface value to a type, without checking // that the interface type matches. func (v *LLVMValue) loadI2V(typ types.Type) *LLVMValue { c := v.compiler if c.types.Sizeof(typ) > int64(c.target.PointerSize()) { ptr := c.builder.CreateExtractValue(v.LLVMValue(), 1, "") typ = types.NewPointer(typ) ptr = c.builder.CreateBitCast(ptr, c.types.ToLLVM(typ), "") return c.NewValue(ptr, typ).makePointee() } value := c.builder.CreateExtractValue(v.LLVMValue(), 1, "") if _, ok := typ.Underlying().(*types.Pointer); ok { value = c.builder.CreateBitCast(value, c.types.ToLLVM(typ), "") return c.NewValue(value, typ) } bits := c.target.TypeSizeInBits(c.types.ToLLVM(typ)) value = c.builder.CreatePtrToInt(value, llvm.IntType(int(bits)), "") value = c.coerce(value, c.types.ToLLVM(typ)) return c.NewValue(value, typ) }