func (tm *LLVMTypeMap) funcLLVMType(tstr string, f *types.Signature) llvm.Type {
typ, ok := tm.types[tstr]
if !ok {
// If there's a receiver change the receiver to an
// additional (first) parameter, and take the value of
// the resulting signature instead.
var param_types []llvm.Type
if recv := f.Recv(); recv != nil {
params := f.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...)
f := types.NewSignature(nil, params, f.Results(), f.IsVariadic())
return tm.ToLLVM(f)
}
typ = llvm.GlobalContext().StructCreateNamed("")
tm.types[tstr] = typ
params := f.Params()
nparams := int(params.Len())
for i := 0; i < nparams; i++ {
typ := params.At(i).Type()
if f.IsVariadic() && i == nparams-1 {
typ = types.NewSlice(typ)
}
llvmtyp := tm.ToLLVM(typ)
param_types = append(param_types, llvmtyp)
}
var return_type llvm.Type
results := f.Results()
switch nresults := int(results.Len()); nresults {
case 0:
return_type = llvm.VoidType()
case 1:
return_type = tm.ToLLVM(results.At(0).Type())
default:
elements := make([]llvm.Type, nresults)
for i := range elements {
result := results.At(i)
elements[i] = tm.ToLLVM(result.Type())
}
return_type = llvm.StructType(elements, false)
}
fntyp := llvm.FunctionType(return_type, param_types, false)
fnptrtyp := llvm.PointerType(fntyp, 0)
i8ptr := llvm.PointerType(llvm.Int8Type(), 0)
elements := []llvm.Type{fnptrtyp, i8ptr} // func, closure
typ.StructSetBody(elements, false)
}
return typ
}
开发者ID:hzmangel,项目名称:llgo,代码行数:57,代码来源:typemap.go
示例6: funcLLVMType
func (tm *llvmTypeMap) funcLLVMType(f *types.Signature, name string) llvm.Type {
// If there's a receiver change the receiver to an
// additional (first) parameter, and take the value of
// the resulting signature instead.
if recv := f.Recv(); recv != nil {
params := f.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...)
f := types.NewSignature(nil, nil, params, f.Results(), f.Variadic())
return tm.toLLVM(f, name)
}
if typ, ok := tm.types.At(f).(llvm.Type); ok {
return typ
}
typ := llvm.GlobalContext().StructCreateNamed(name)
tm.types.Set(f, typ)
params := f.Params()
param_types := make([]llvm.Type, params.Len())
for i := range param_types {
llvmtyp := tm.ToLLVM(params.At(i).Type())
param_types[i] = llvmtyp
}
var return_type llvm.Type
results := f.Results()
switch nresults := int(results.Len()); nresults {
case 0:
return_type = llvm.VoidType()
case 1:
return_type = tm.ToLLVM(results.At(0).Type())
default:
elements := make([]llvm.Type, nresults)
for i := range elements {
result := results.At(i)
elements[i] = tm.ToLLVM(result.Type())
}
return_type = llvm.StructType(elements, false)
}
fntyp := llvm.FunctionType(return_type, param_types, false)
fnptrtyp := llvm.PointerType(fntyp, 0)
i8ptr := llvm.PointerType(llvm.Int8Type(), 0)
elements := []llvm.Type{fnptrtyp, i8ptr} // func, closure
typ.StructSetBody(elements, false)
return typ
}
开发者ID:minux,项目名称:llgo,代码行数:52,代码来源:typemap.go
示例7: mapLLVMType
func (tm *TypeMap) mapLLVMType(m *types.Map) llvm.Type {
// XXX This map type will change in the future, when I get around to it.
// At the moment, it's representing a really dumb singly linked list.
list_type := llvm.GlobalContext().StructCreateNamed("")
list_ptr_type := llvm.PointerType(list_type, 0)
size_type := llvm.Int32Type()
element_types := []llvm.Type{size_type, list_type}
typ := llvm.StructType(element_types, false)
tm.types[m] = typ
list_element_types := []llvm.Type{
list_ptr_type, tm.ToLLVM(m.Key), tm.ToLLVM(m.Elt)}
list_type.StructSetBody(list_element_types, false)
return typ
}
func (tm *TypeMap) interfaceLLVMType(i *types.Interface) llvm.Type {
valptr_type := llvm.PointerType(llvm.Int8Type(), 0)
typptr_type := valptr_type // runtimeCommonType may not be defined yet
elements := make([]llvm.Type, 2+len(i.Methods))
elements[0] = valptr_type // value
elements[1] = typptr_type // type
for n, m := range i.Methods {
// Add an opaque pointer parameter to the function for the
// struct pointer.
fntype := m.Type.(*types.Func)
receiver_type := &types.Pointer{Base: types.Int8}
fntype.Recv = ast.NewObj(ast.Var, "")
fntype.Recv.Type = receiver_type
elements[n+2] = tm.ToLLVM(fntype)
}
return llvm.StructType(elements, false)
}
// makeClosure creates a closure from a function pointer and
// a set of bindings. The bindings are addresses of captured
// variables.
func (c *compiler) makeClosure(fn *LLVMValue, bindings []*LLVMValue) *LLVMValue {
types := make([]llvm.Type, len(bindings))
for i, binding := range bindings {
types[i] = c.types.ToLLVM(binding.Type())
}
block := c.createTypeMalloc(llvm.StructType(types, false))
for i, binding := range bindings {
addressPtr := c.builder.CreateStructGEP(block, i, "")
c.builder.CreateStore(binding.LLVMValue(), addressPtr)
}
block = c.builder.CreateBitCast(block, llvm.PointerType(llvm.Int8Type(), 0), "")
// fn is a raw function pointer; ToLLVM yields {*fn, *uint8}.
closure := llvm.Undef(c.types.ToLLVM(fn.Type()))
fnptr := c.builder.CreateBitCast(fn.LLVMValue(), closure.Type().StructElementTypes()[0], "")
closure = c.builder.CreateInsertValue(closure, fnptr, 0, "")
closure = c.builder.CreateInsertValue(closure, block, 1, "")
return c.NewValue(closure, fn.Type())
}
开发者ID:minux,项目名称:llgo,代码行数:21,代码来源:closures.go
示例11: resolveFunction
func (u *unit) resolveFunction(f *ssa.Function) *LLVMValue {
if v, ok := u.globals[f]; ok {
return v
}
name := f.String()
if f.Enclosing != nil {
// Anonymous functions are not guaranteed to
// have unique identifiers at the global scope.
name = f.Enclosing.String() + ":" + name
}
// It's possible that the function already exists in the module;
// for example, if it's a runtime intrinsic that the compiler
// has already referenced.
llvmFunction := u.module.Module.NamedFunction(name)
if llvmFunction.IsNil() {
llvmType := u.llvmtypes.ToLLVM(f.Signature)
llvmType = llvmType.StructElementTypes()[0].ElementType()
if len(f.FreeVars) > 0 {
// Add an implicit first argument.
returnType := llvmType.ReturnType()
paramTypes := llvmType.ParamTypes()
vararg := llvmType.IsFunctionVarArg()
blockElementTypes := make([]llvm.Type, len(f.FreeVars))
for i, fv := range f.FreeVars {
blockElementTypes[i] = u.llvmtypes.ToLLVM(fv.Type())
}
blockType := llvm.StructType(blockElementTypes, false)
blockPtrType := llvm.PointerType(blockType, 0)
paramTypes = append([]llvm.Type{blockPtrType}, paramTypes...)
llvmType = llvm.FunctionType(returnType, paramTypes, vararg)
}
llvmFunction = llvm.AddFunction(u.module.Module, name, llvmType)
if f.Enclosing != nil {
llvmFunction.SetLinkage(llvm.PrivateLinkage)
}
u.undefinedFuncs[f] = true
}
v := u.NewValue(llvmFunction, f.Signature)
u.globals[f] = v
return v
}
func (c *compiler) VisitSelectorExpr(expr *ast.SelectorExpr) Value {
selection := c.typeinfo.Selections[expr]
// Imported package funcs/vars.
if selection.Kind() == types.PackageObj {
return c.Resolve(expr.Sel)
}
// Method expression. Returns an unbound function pointer.
if selection.Kind() == types.MethodExpr {
ftyp := c.typeinfo.Types[expr].(*types.Signature)
recvtyp := ftyp.Params().At(0).Type()
var name *types.Named
var isptr bool
if ptrtyp, ok := recvtyp.(*types.Pointer); ok {
isptr = true
name = ptrtyp.Elem().(*types.Named)
} else {
name = recvtyp.(*types.Named)
}
obj := c.methods(name).lookup(expr.Sel.Name, isptr)
method := c.Resolve(c.objectdata[obj].Ident).(*LLVMValue)
return c.NewValue(method.value, ftyp)
}
// Interface: search for method by name.
lhs := c.VisitExpr(expr.X)
name := expr.Sel.Name
if iface, ok := lhs.Type().Underlying().(*types.Interface); ok {
i := selection.Index()[0]
ftype := selection.Type()
methodset := iface.MethodSet()
if methodset.At(i).Obj() != selection.Obj() {
// TODO cache mapping from unsorted to sorted index.
for j := 0; j < methodset.Len(); j++ {
if methodset.At(j).Obj() == selection.Obj() {
i = j
break
}
}
}
structValue := lhs.LLVMValue()
receiver := c.builder.CreateExtractValue(structValue, 1, "")
f := c.builder.CreateExtractValue(structValue, i+2, "")
types := []llvm.Type{f.Type(), receiver.Type()}
llvmStructType := llvm.StructType(types, false)
structValue = llvm.Undef(llvmStructType)
structValue = c.builder.CreateInsertValue(structValue, f, 0, "")
structValue = c.builder.CreateInsertValue(structValue, receiver, 1, "")
return c.NewValue(structValue, ftype)
}
// Method.
if selection.Kind() == types.MethodVal {
var isptr bool
typ := lhs.Type()
if ptr, ok := typ.(*types.Pointer); ok {
typ = ptr.Elem()
isptr = true
} else {
isptr = lhs.(*LLVMValue).pointer != nil
}
recv := lhs.(*LLVMValue)
if isptr && typ == lhs.Type() {
recv = recv.pointer
}
method := c.methods(typ).lookup(name, isptr)
if f, ok := method.(*types.Func); ok {
method = c.methodfunc(f)
}
methodValue := c.Resolve(c.objectdata[method].Ident).LLVMValue()
methodValue = c.builder.CreateExtractValue(methodValue, 0, "")
recvValue := recv.LLVMValue()
types := []llvm.Type{methodValue.Type(), recvValue.Type()}
structType := llvm.StructType(types, false)
value := llvm.Undef(structType)
value = c.builder.CreateInsertValue(value, methodValue, 0, "")
value = c.builder.CreateInsertValue(value, recvValue, 1, "")
v := c.NewValue(value, method.Type())
v.method = method
return v
}
// Get a pointer to the field.
fieldValue := lhs.(*LLVMValue)
if fieldValue.pointer == nil {
// If we've got a temporary (i.e. no pointer),
// then load the value onto the stack.
v := fieldValue.value
stackptr := c.builder.CreateAlloca(v.Type(), "")
c.builder.CreateStore(v, stackptr)
ptrtyp := types.NewPointer(fieldValue.Type())
fieldValue = c.NewValue(stackptr, ptrtyp).makePointee()
}
for _, i := range selection.Index() {
if _, ok := fieldValue.Type().(*types.Pointer); ok {
fieldValue = fieldValue.makePointee()
}
ptr := fieldValue.pointer.LLVMValue()
//.........这里部分代码省略.........
开发者ID:quarnster,项目名称:llgo,代码行数:101,代码来源:expr.go
示例14: makeDeferBlock
// makeDeferBlock creates a basic block for handling
// defer statements, and code is emitted to allocate and
// initialise a deferred function anchor point.
//
// This must be called before generating any code for
// the function body (not including allocating space
// for parameters and results).
func (c *compiler) makeDeferBlock(f *function, body *ast.BlockStmt) {
currblock := c.builder.GetInsertBlock()
defer c.builder.SetInsertPointAtEnd(currblock)
// Create space for a pointer on the stack, which
// we'll store the first panic structure in.
//
// TODO consider having stack space for one (or few)
// defer statements, to avoid heap allocation.
//
// TODO delay this until just before the first "invoke"
// instruction is emitted.
f.deferblock = llvm.AddBasicBlock(currblock.Parent(), "defer")
if hasCallExpr(body) {
f.unwindblock = llvm.AddBasicBlock(currblock.Parent(), "unwind")
f.unwindblock.MoveAfter(currblock)
f.deferblock.MoveAfter(f.unwindblock)
} else {
f.deferblock.MoveAfter(currblock)
}
// Create a landingpad/unwind target basic block.
if !f.unwindblock.IsNil() {
c.builder.SetInsertPointAtEnd(f.unwindblock)
i8ptr := llvm.PointerType(llvm.Int8Type(), 0)
restyp := llvm.StructType([]llvm.Type{i8ptr, llvm.Int32Type()}, false)
pers := c.module.Module.NamedFunction("__gxx_personality_v0")
if pers.IsNil() {
persftyp := llvm.FunctionType(llvm.Int32Type(), nil, true)
pers = llvm.AddFunction(c.module.Module, "__gxx_personality_v0", persftyp)
}
lp := c.builder.CreateLandingPad(restyp, pers, 1, "")
lp.AddClause(llvm.ConstNull(i8ptr))
// Catch the exception.
begin_catch := c.NamedFunction("__cxa_begin_catch", "func f(*int8) *int8")
exception := c.builder.CreateExtractValue(llvm.Value(lp), 0, "")
c.builder.CreateCall(begin_catch, []llvm.Value{exception}, "")
end_catch := c.NamedFunction("__cxa_end_catch", "func f()")
c.builder.CreateCall(end_catch, nil, "")
c.builder.CreateBr(f.deferblock)
}
// Create a real return instruction.
c.builder.SetInsertPointAtEnd(f.deferblock)
rundefers := c.NamedFunction("runtime.rundefers", "func f()")
c.builder.CreateCall(rundefers, nil, "")
if f.results.Len() == 0 {
c.builder.CreateRetVoid()
} else {
values := make([]llvm.Value, 0, f.results.Len())
f.results.ForEach(func(v *types.Var) {
value := c.objectdata[v].Value.LLVMValue()
values = append(values, value)
})
if len(values) == 1 {
c.builder.CreateRet(values[0])
} else {
c.builder.CreateAggregateRet(values)
}
}
}
开发者ID:hzmangel,项目名称:llgo,代码行数:71,代码来源:defer.go
示例15: Compile
func (compiler *compiler) Compile(fset *token.FileSet,
pkg *ast.Package, importpath string,
exprTypes map[ast.Expr]types.Type) (m *Module, err error) {
// FIXME create a compilation state, rather than storing in 'compiler'.
compiler.fileset = fset
compiler.pkg = pkg
compiler.importpath = importpath
compiler.initfuncs = nil
compiler.varinitfuncs = nil
// Create a Builder, for building LLVM instructions.
compiler.builder = llvm.GlobalContext().NewBuilder()
defer compiler.builder.Dispose()
// Create a TargetMachine from the OS & Arch.
triple := compiler.GetTargetTriple()
var machine llvm.TargetMachine
for target := llvm.FirstTarget(); target.C != nil && machine.C == nil; target = target.NextTarget() {
if target.Name() == compiler.targetArch {
machine = target.CreateTargetMachine(triple, "", "",
llvm.CodeGenLevelDefault,
llvm.RelocDefault,
llvm.CodeModelDefault)
defer machine.Dispose()
}
}
if machine.C == nil {
err = fmt.Errorf("Invalid target triple: %s", triple)
return
}
// Create a Module, which contains the LLVM bitcode. Dispose it on panic,
// otherwise we'll set a finalizer at the end. The caller may invoke
// Dispose manually, which will render the finalizer a no-op.
modulename := pkg.Name
compiler.target = machine.TargetData()
compiler.module = &Module{llvm.NewModule(modulename), modulename, false}
compiler.module.SetTarget(triple)
compiler.module.SetDataLayout(compiler.target.String())
defer func() {
if e := recover(); e != nil {
compiler.module.Dispose()
panic(e)
//err = e.(error)
}
}()
// Create a mapping from objects back to packages, so we can create the
// appropriate symbol names.
compiler.pkgmap = createPackageMap(pkg, importpath)
// Create a struct responsible for mapping static types to LLVM types,
// and to runtime/dynamic type values.
var resolver Resolver = compiler
llvmtypemap := NewLLVMTypeMap(compiler.module.Module, compiler.target)
compiler.FunctionCache = NewFunctionCache(compiler)
compiler.types = NewTypeMap(llvmtypemap, importpath, exprTypes, compiler.FunctionCache, compiler.pkgmap, resolver)
// Compile each file in the package.
for _, file := range pkg.Files {
file.Scope.Outer = pkg.Scope
compiler.filescope = file.Scope
compiler.scope = file.Scope
compiler.fixConstDecls(file)
for _, decl := range file.Decls {
compiler.VisitDecl(decl)
}
}
// Define intrinsics for use by the runtime: malloc, free, memcpy, etc.
// These could be defined in LLVM IR, and may be moved there later.
if pkg.Name == "runtime" {
compiler.defineRuntimeIntrinsics()
}
// Export runtime type information.
if pkg.Name == "runtime" {
compiler.exportBuiltinRuntimeTypes()
}
// Create global constructors.
//
// XXX When imports are handled, we'll need to defer creating
// llvm.global_ctors until we create an executable. This is
// due to (a) imports having to be initialised before the
// importer, and (b) LLVM having no specified order of
// initialisation for ctors with the same priority.
var initfuncs [][]Value
if compiler.varinitfuncs != nil {
initfuncs = append(initfuncs, compiler.varinitfuncs)
}
if compiler.initfuncs != nil {
initfuncs = append(initfuncs, compiler.initfuncs)
}
if initfuncs != nil {
elttypes := []llvm.Type{llvm.Int32Type(), llvm.PointerType(llvm.FunctionType(llvm.VoidType(), nil, false), 0)}
ctortype := llvm.StructType(elttypes, false)
var ctors []llvm.Value
var priority uint64
//.........这里部分代码省略.........
开发者ID:kisielk,项目名称:llgo,代码行数:101,代码来源:compiler.go
示例16: Compile
func (compiler *compiler) Compile(fset *token.FileSet,
pkg *ast.Package, importpath string,
exprTypes map[ast.Expr]types.Type) (m *Module, err error) {
// FIXME I'd prefer if we didn't modify global state. Perhaps
// we should always take a copy of types.Universe?
defer func() {
types.Universe.Lookup("true").Data = types.Const{true}
types.Universe.Lookup("false").Data = types.Const{false}
}()
// FIXME create a compilation state, rather than storing in 'compiler'.
compiler.fileset = fset
compiler.pkg = pkg
compiler.importpath = importpath
compiler.initfuncs = nil
compiler.varinitfuncs = nil
// Create a Builder, for building LLVM instructions.
compiler.builder = llvm.GlobalContext().NewBuilder()
defer compiler.builder.Dispose()
// Create a Module, which contains the LLVM bitcode. Dispose it on panic,
// otherwise we'll set a finalizer at the end. The caller may invoke
// Dispose manually, which will render the finalizer a no-op.
modulename := pkg.Name
compiler.module = &Module{llvm.NewModule(modulename), modulename, false}
compiler.module.SetTarget(compiler.TargetTriple)
compiler.module.SetDataLayout(compiler.target.String())
defer func() {
if e := recover(); e != nil {
compiler.module.Dispose()
panic(e)
//err = e.(error)
}
}()
// Create a mapping from objects back to packages, so we can create the
// appropriate symbol names.
compiler.pkgmap = createPackageMap(pkg, importpath)
// Create a struct responsible for mapping static types to LLVM types,
// and to runtime/dynamic type values.
var resolver Resolver = compiler
compiler.FunctionCache = NewFunctionCache(compiler)
compiler.types = NewTypeMap(compiler.llvmtypes, compiler.module.Module, importpath, exprTypes, compiler.FunctionCache, resolver)
// Compile each file in the package.
for _, file := range pkg.Files {
file.Scope.Outer = pkg.Scope
compiler.filescope = file.Scope
compiler.scope = file.Scope
compiler.fixConstDecls(file)
for _, decl := range file.Decls {
compiler.VisitDecl(decl)
}
}
// Define intrinsics for use by the runtime: malloc, free, memcpy, etc.
// These could be defined in LLVM IR, and may be moved there later.
if pkg.Name == "runtime" {
compiler.defineRuntimeIntrinsics()
}
// Export runtime type information.
if pkg.Name == "runtime" {
compiler.exportBuiltinRuntimeTypes()
}
// Create global constructors. The initfuncs/varinitfuncs
// slices are in the order of visitation, and that is how
// their priorities are assigned.
//
// The llgo linker (llgo-link) is responsible for reordering
// global constructors according to package dependency order.
var initfuncs [][]Value
if compiler.varinitfuncs != nil {
initfuncs = append(initfuncs, compiler.varinitfuncs)
}
if compiler.initfuncs != nil {
initfuncs = append(initfuncs, compiler.initfuncs)
}
if initfuncs != nil {
elttypes := []llvm.Type{llvm.Int32Type(), llvm.PointerType(llvm.FunctionType(llvm.VoidType(), nil, false), 0)}
ctortype := llvm.StructType(elttypes, false)
var ctors []llvm.Value
var priority uint64 = 1
for _, initfuncs := range initfuncs {
for _, fn := range initfuncs {
priorityval := llvm.ConstInt(llvm.Int32Type(), uint64(priority), false)
struct_values := []llvm.Value{priorityval, fn.LLVMValue()}
ctors = append(ctors, llvm.ConstStruct(struct_values, false))
priority++
}
}
global_ctors_init := llvm.ConstArray(ctortype, ctors)
global_ctors_var := llvm.AddGlobal(compiler.module.Module, global_ctors_init.Type(), "llvm.global_ctors")
global_ctors_var.SetInitializer(global_ctors_init)
global_ctors_var.SetLinkage(llvm.AppendingLinkage)
}
//.........这里部分代码省略.........
func (c *compiler) VisitFuncLit(lit *ast.FuncLit) Value {
ftyp := c.types.expr[lit].Type.(*types.Signature)
// Walk the function literal, promoting stack vars not defined
// in the function literal, and storing the ident's for non-const
// values not declared in the function literal.
//
// (First, set a dummy "stack" value for the params and results.)
var dummyfunc LLVMValue
dummyfunc.stack = &dummyfunc
paramVars := ftyp.Params()
resultVars := ftyp.Results()
c.functions.push(&function{
LLVMValue: &dummyfunc,
results: resultVars,
})
v := &identVisitor{compiler: c}
ast.Walk(v, lit.Body)
c.functions.pop()
// Create closure by adding a context parameter to the function,
// and bind it with the values of the stack vars found in the
// step above.
origfnpairtyp := c.types.ToLLVM(ftyp)
fnpairtyp := origfnpairtyp
fntyp := origfnpairtyp.StructElementTypes()[0].ElementType()
if v.captures != nil {
// Add the additional context param.
ctxfields := make([]*types.Field, len(v.captures))
for i, capturevar := range v.captures {
ctxfields[i] = &types.Field{
Type: types.NewPointer(capturevar.Type()),
}
}
ctxtyp := types.NewPointer(types.NewStruct(ctxfields, nil))
llvmctxtyp := c.types.ToLLVM(ctxtyp)
rettyp := fntyp.ReturnType()
paramtyps := append([]llvm.Type{llvmctxtyp}, fntyp.ParamTypes()...)
vararg := fntyp.IsFunctionVarArg()
fntyp = llvm.FunctionType(rettyp, paramtyps, vararg)
opaqueptrtyp := origfnpairtyp.StructElementTypes()[1]
elttyps := []llvm.Type{llvm.PointerType(fntyp, 0), opaqueptrtyp}
fnpairtyp = llvm.StructType(elttyps, false)
}
fnptr := llvm.AddFunction(c.module.Module, "", fntyp)
fnvalue := llvm.ConstNull(fnpairtyp)
fnvalue = llvm.ConstInsertValue(fnvalue, fnptr, []uint32{0})
currBlock := c.builder.GetInsertBlock()
f := c.NewValue(fnvalue, ftyp)
captureVars := types.NewTuple(v.captures...)
c.buildFunction(f, captureVars, paramVars, resultVars, lit.Body, ftyp.IsVariadic())
// Closure? Bind values to a context block.
if v.captures != nil {
// Store the free variables in the heap allocated block.
block := c.createTypeMalloc(fntyp.ParamTypes()[0].ElementType())
for i, contextvar := range v.captures {
value := c.objectdata[contextvar].Value
blockPtr := c.builder.CreateStructGEP(block, i, "")
c.builder.CreateStore(value.pointer.LLVMValue(), blockPtr)
}
// Cast the function pointer type back to the original
// type, without the context parameter.
fnptr = llvm.ConstBitCast(fnptr, origfnpairtyp.StructElementTypes()[0])
fnvalue = llvm.Undef(origfnpairtyp)
fnvalue = llvm.ConstInsertValue(fnvalue, fnptr, []uint32{0})
// Set the context value.
i8ptr := llvm.PointerType(llvm.Int8Type(), 0)
block = c.builder.CreateBitCast(block, i8ptr, "")
fnvalue = c.builder.CreateInsertValue(fnvalue, block, 1, "")
f.value = fnvalue
} else {
c.builder.SetInsertPointAtEnd(currBlock)
}
return f
}
开发者ID:hzmangel,项目名称:llgo,代码行数:81,代码来源:literals.go
示例18: indirectFunction
// indirectFunction creates an indirect function from a
// given function and arguments, suitable for use with
// "defer" and "go".
func (c *compiler) indirectFunction(fn *LLVMValue, args []*LLVMValue) *LLVMValue {
nilarytyp := types.NewSignature(nil, nil, nil, nil, false)
if len(args) == 0 {
val := fn.LLVMValue()
ptr := c.builder.CreateExtractValue(val, 0, "")
ctx := c.builder.CreateExtractValue(val, 1, "")
fnval := llvm.Undef(c.types.ToLLVM(nilarytyp))
ptr = c.builder.CreateBitCast(ptr, fnval.Type().StructElementTypes()[0], "")
ctx = c.builder.CreateBitCast(ctx, fnval.Type().StructElementTypes()[1], "")
fnval = c.builder.CreateInsertValue(fnval, ptr, 0, "")
fnval = c.builder.CreateInsertValue(fnval, ctx, 1, "")
return c.NewValue(fnval, nilarytyp)
}
// Check if function pointer or context pointer is global/null.
fnval := fn.LLVMValue()
fnptr := fnval
var nctx int
var fnctx llvm.Value
var fnctxindex uint64
var globalfn bool
if fnptr.Type().TypeKind() == llvm.StructTypeKind {
fnptr = c.builder.CreateExtractValue(fnval, 0, "")
fnctx = c.builder.CreateExtractValue(fnval, 1, "")
globalfn = !fnptr.IsAFunction().IsNil()
if !globalfn {
nctx++
}
if !fnctx.IsNull() {
fnctxindex = uint64(nctx)
nctx++
}
} else {
// We've got a raw global function pointer. Convert to <ptr,ctx>.
fnval = llvm.ConstNull(c.types.ToLLVM(fn.Type()))
fnval = llvm.ConstInsertValue(fnval, fnptr, []uint32{0})
fn = c.NewValue(fnval, fn.Type())
fnctx = llvm.ConstExtractValue(fnval, []uint32{1})
globalfn = true
}
i8ptr := llvm.PointerType(llvm.Int8Type(), 0)
llvmargs := make([]llvm.Value, len(args)+nctx)
llvmargtypes := make([]llvm.Type, len(args)+nctx)
for i, arg := range args {
llvmargs[i+nctx] = arg.LLVMValue()
llvmargtypes[i+nctx] = llvmargs[i+nctx].Type()
}
if !globalfn {
llvmargtypes[0] = fnptr.Type()
llvmargs[0] = fnptr
}
if !fnctx.IsNull() {
llvmargtypes[fnctxindex] = fnctx.Type()
llvmargs[fnctxindex] = fnctx
}
// TODO(axw) investigate an option for go statements
// to allocate argument structure on the stack in the
// initiator, and block until the spawned goroutine
// has loaded the arguments from it.
structtyp := llvm.StructType(llvmargtypes, false)
argstruct := c.createTypeMalloc(structtyp)
for i, llvmarg := range llvmargs {
argptr := c.builder.CreateGEP(argstruct, []llvm.Value{
llvm.ConstInt(llvm.Int32Type(), 0, false),
llvm.ConstInt(llvm.Int32Type(), uint64(i), false)}, "")
c.builder.CreateStore(llvmarg, argptr)
}
// Create a function that will take a pointer to a structure of the type
// defined above, or no parameters if there are none to pass.
fntype := llvm.FunctionType(llvm.VoidType(), []llvm.Type{argstruct.Type()}, false)
indirectfn := llvm.AddFunction(c.module.Module, "", fntype)
i8argstruct := c.builder.CreateBitCast(argstruct, i8ptr, "")
currblock := c.builder.GetInsertBlock()
c.builder.SetInsertPointAtEnd(llvm.AddBasicBlock(indirectfn, "entry"))
argstruct = indirectfn.Param(0)
newargs := make([]*LLVMValue, len(args))
for i := range llvmargs[nctx:] {
argptr := c.builder.CreateGEP(argstruct, []llvm.Value{
llvm.ConstInt(llvm.Int32Type(), 0, false),
llvm.ConstInt(llvm.Int32Type(), uint64(i+nctx), false)}, "")
newargs[i] = c.NewValue(c.builder.CreateLoad(argptr, ""), args[i].Type())
}
// Unless we've got a global function, extract the
// function pointer from the context.
if !globalfn {
fnval = llvm.Undef(fnval.Type())
fnptrptr := c.builder.CreateGEP(argstruct, []llvm.Value{
llvm.ConstInt(llvm.Int32Type(), 0, false),
llvm.ConstInt(llvm.Int32Type(), 0, false)}, "")
fnptr = c.builder.CreateLoad(fnptrptr, "")
fnval = c.builder.CreateInsertValue(fnval, fnptr, 0, "")
}
if !fnctx.IsNull() {
//.........这里部分代码省略.........
开发者ID:minux,项目名称:llgo,代码行数:101,代码来源:indirect.go
示例19: indirectFunction
// indirectFunction creates an indirect function from a
// given function, suitable for use with "defer" and "go".
func (c *compiler) indirectFunction(fn *LLVMValue, args []Value, dotdotdot bool) *LLVMValue {
nilarytyp := &types.Signature{}
if len(args) == 0 {
val := fn.LLVMValue()
ptr := c.builder.CreateExtractValue(val, 0, "")
ctx := c.builder.CreateExtractValue(val, 1, "")
fnval := llvm.Undef(c.types.ToLLVM(nilarytyp))
ptr = c.builder.CreateBitCast(ptr, fnval.Type().StructElementTypes()[0], "")
ctx = c.builder.CreateBitCast(ctx, fnval.Type().StructElementTypes()[1], "")
fnval = c.builder.CreateInsertValue(fnval, ptr, 0, "")
fnval = c.builder.CreateInsertValue(fnval, ctx, 1, "")
fn = c.NewValue(fnval, nilarytyp)
return fn
}
// TODO check if function pointer is global. I suppose
// the same can be done with the context ptr...
fnval := fn.LLVMValue()
fnptr := c.builder.CreateExtractValue(fnval, 0, "")
ctx := c.builder.CreateExtractValue(fnval, 1, "")
nctx := 1 // fnptr
if !ctx.IsNull() {
nctx++ // fnctx
}
i8ptr := llvm.PointerType(llvm.Int8Type(), 0)
llvmargs := make([]llvm.Value, len(args)+nctx)
llvmargtypes := make([]llvm.Type, len(args)+nctx)
for i, arg := range args {
llvmargs[i+nctx] = arg.LLVMValue()
llvmargtypes[i+nctx] = llvmargs[i+nctx].Type()
}
llvmargtypes[0] = fnptr.Type()
llvmargs[0] = fnptr
if nctx > 1 {
llvmargtypes[1] = ctx.Type()
llvmargs[1] = ctx
}
structtyp := llvm.StructType(llvmargtypes, false)
argstruct := c.createTypeMalloc(structtyp)
for i, llvmarg := range llvmargs {
argptr := c.builder.CreateGEP(argstruct, []llvm.Value{
llvm.ConstInt(llvm.Int32Type(), 0, false),
llvm.ConstInt(llvm.Int32Type(), uint64(i), false)}, "")
c.builder.CreateStore(llvmarg, argptr)
}
// Create a function that will take a pointer to a structure of the type
// defined above, or no parameters if there are none to pass.
fntype := llvm.FunctionType(llvm.VoidType(), []llvm.Type{argstruct.Type()}, false)
indirectfn := llvm.AddFunction(c.module.Module, "", fntype)
i8argstruct := c.builder.CreateBitCast(argstruct, i8ptr, "")
currblock := c.builder.GetInsertBlock()
c.builder.SetInsertPointAtEnd(llvm.AddBasicBlock(indirectfn, "entry"))
argstruct = indirectfn.Param(0)
for i := range llvmargs[nctx:] {
argptr := c.builder.CreateGEP(argstruct, []llvm.Value{
llvm.ConstInt(llvm.Int32Type(), 0, false),
llvm.ConstInt(llvm.Int32Type(), uint64(i+nctx), false)}, "")
ptrtyp := types.NewPointer(args[i].Type())
args[i] = c.NewValue(argptr, ptrtyp).makePointee()
}
// Extract the function pointer.
// TODO if function is a global, elide.
fnval = llvm.Undef(fnval.Type())
fnptrptr := c.builder.CreateGEP(argstruct, []llvm.Value{
llvm.ConstInt(llvm.Int32Type(), 0, false),
llvm.ConstInt(llvm.Int32Type(), 0, false)}, "")
fnptr = c.builder.CreateLoad(fnptrptr, "")
fnval = c.builder.CreateInsertValue(fnval, fnptr, 0, "")
if nctx > 1 {
ctxptr := c.builder.CreateGEP(argstruct, []llvm.Value{
llvm.ConstInt(llvm.Int32Type(), 0, false),
llvm.ConstInt(llvm.Int32Type(), 1, false)}, "")
ctx = c.builder.CreateLoad(ctxptr, "")
fnval = c.builder.CreateInsertValue(fnval, ctx, 1, "")
fn = c.NewValue(fnval, fn.Type())
}
c.createCall(fn, args, dotdotdot, false)
// Indirect function calls' return values are always ignored.
c.builder.CreateRetVoid()
c.builder.SetInsertPointAtEnd(currblock)
fnval = llvm.Undef(c.types.ToLLVM(nilarytyp))
indirectfn = c.builder.CreateBitCast(indirectfn, fnval.Type().StructElementTypes()[0], "")
fnval = c.builder.CreateInsertValue(fnval, indirectfn, 0, "")
fnval = c.builder.CreateInsertValue(fnval, i8argstruct, 1, "")
fn = c.NewValue(fnval, nilarytyp)
return fn
}
请发表评论