예제 #1
0
파일: typemap.go 프로젝트: quarnster/llgo
func (tm *TypeMap) makeAlgorithmTable(t types.Type) llvm.Value {
	// TODO set these to actual functions.
	hashAlg := llvm.ConstNull(llvm.PointerType(tm.hashAlgFunctionType, 0))
	printAlg := llvm.ConstNull(llvm.PointerType(tm.printAlgFunctionType, 0))
	copyAlg := llvm.ConstNull(llvm.PointerType(tm.copyAlgFunctionType, 0))

	const eqalgsig = "func(uintptr, unsafe.Pointer, unsafe.Pointer) bool"
	var equalAlg llvm.Value
	switch t := t.(type) {
	case *types.Basic:
		switch t.Kind() {
		case types.String:
			equalAlg = tm.functions.NamedFunction("runtime.streqalg", eqalgsig)
		case types.Float32:
			equalAlg = tm.functions.NamedFunction("runtime.f32eqalg", eqalgsig)
		case types.Float64:
			equalAlg = tm.functions.NamedFunction("runtime.f64eqalg", eqalgsig)
		case types.Complex64:
			equalAlg = tm.functions.NamedFunction("runtime.c64eqalg", eqalgsig)
		case types.Complex128:
			equalAlg = tm.functions.NamedFunction("runtime.c128eqalg", eqalgsig)
		}
	}
	if equalAlg.IsNil() {
		equalAlg = tm.functions.NamedFunction("runtime.memequal", eqalgsig)
	}
	elems := []llvm.Value{hashAlg, equalAlg, printAlg, copyAlg}
	return llvm.ConstStruct(elems, false)
}
예제 #2
0
파일: value.go 프로젝트: spate/llgo
func (v ConstValue) LLVMValue() llvm.Value {
	typ := types.Underlying(v.Type())
	switch typ {
	case types.Int, types.Uint:
		return llvm.ConstInt(llvm.Int32Type(), uint64(v.Int64()), true)
		// TODO 32/64bit (probably wait for gc)
		//int_val := v.Val.(*big.Int)
		//if int_val.Cmp(maxBigInt32) > 0 || int_val.Cmp(minBigInt32) < 0 {
		//	panic(fmt.Sprint("const ", int_val, " overflows int"))
		//}
		//return llvm.ConstInt(v.compiler.target.IntPtrType(), uint64(v.Int64()), true)
	case types.Uint:
		return llvm.ConstInt(llvm.Int32Type(), uint64(v.Int64()), false)

	case types.Int8:
		return llvm.ConstInt(llvm.Int8Type(), uint64(v.Int64()), true)
	case types.Uint8, types.Byte:
		return llvm.ConstInt(llvm.Int8Type(), uint64(v.Int64()), false)

	case types.Int16:
		return llvm.ConstInt(llvm.Int16Type(), uint64(v.Int64()), true)
	case types.Uint16:
		return llvm.ConstInt(llvm.Int16Type(), uint64(v.Int64()), false)

	case types.Int32, types.Rune:
		return llvm.ConstInt(llvm.Int32Type(), uint64(v.Int64()), true)
	case types.Uint32:
		return llvm.ConstInt(llvm.Int32Type(), uint64(v.Int64()), false)

	case types.Int64:
		return llvm.ConstInt(llvm.Int64Type(), uint64(v.Int64()), true)
	case types.Uint64:
		return llvm.ConstInt(llvm.Int64Type(), uint64(v.Int64()), true)

	case types.Float32:
		return llvm.ConstFloat(llvm.FloatType(), float64(v.Float64()))
	case types.Float64:
		return llvm.ConstFloat(llvm.DoubleType(), float64(v.Float64()))

	case types.UnsafePointer, types.Uintptr:
		inttype := v.compiler.target.IntPtrType()
		return llvm.ConstInt(inttype, uint64(v.Int64()), false)

	case types.String:
		strval := (v.Val).(string)
		ptr := v.compiler.builder.CreateGlobalStringPtr(strval, "")
		len_ := llvm.ConstInt(llvm.Int32Type(), uint64(len(strval)), false)
		return llvm.ConstStruct([]llvm.Value{ptr, len_}, false)

	case types.Bool:
		if v := v.Val.(bool); v {
			return llvm.ConstAllOnes(llvm.Int1Type())
		}
		return llvm.ConstNull(llvm.Int1Type())
	}
	panic(fmt.Errorf("Unhandled type: %v", typ)) //v.typ.Kind))
}
예제 #3
0
파일: llvmtypes.go 프로젝트: spate/llgo
func (tm *TypeMap) makeAlgorithmTable(t types.Type) llvm.Value {
	// TODO set these to actual functions.
	hashAlg := llvm.ConstNull(llvm.PointerType(tm.hashAlgFunctionType, 0))
	printAlg := llvm.ConstNull(llvm.PointerType(tm.printAlgFunctionType, 0))
	copyAlg := llvm.ConstNull(llvm.PointerType(tm.copyAlgFunctionType, 0))

	equalAlg := tm.functions.NamedFunction("runtime.memequal", "func f(uintptr, unsafe.Pointer, unsafe.Pointer) bool")
	elems := []llvm.Value{hashAlg, equalAlg, printAlg, copyAlg}
	return llvm.ConstStruct(elems, false)
}
예제 #4
0
파일: llvmtypes.go 프로젝트: prattmic/llgo
func (tm *TypeMap) makeAlgorithmTable(t types.Type) llvm.Value {
	// TODO set these to actual functions.
	hashAlg := llvm.ConstNull(llvm.PointerType(tm.hashAlgFunctionType, 0))
	equalAlg := llvm.ConstNull(llvm.PointerType(tm.equalAlgFunctionType, 0))
	printAlg := llvm.ConstNull(llvm.PointerType(tm.printAlgFunctionType, 0))
	copyAlg := llvm.ConstNull(llvm.PointerType(tm.copyAlgFunctionType, 0))

	elems := []llvm.Value{hashAlg, equalAlg, printAlg, copyAlg}
	return llvm.ConstStruct(elems, false)
}
예제 #5
0
파일: typemap.go 프로젝트: minux/llgo
// globalStringPtr returns a *string with the specified value.
func (tm *TypeMap) globalStringPtr(value string) llvm.Value {
	strval := llvm.ConstString(value, false)
	strglobal := llvm.AddGlobal(tm.module, strval.Type(), "")
	strglobal.SetInitializer(strval)
	strglobal = llvm.ConstBitCast(strglobal, llvm.PointerType(llvm.Int8Type(), 0))
	strlen := llvm.ConstInt(tm.inttype, uint64(len(value)), false)
	str := llvm.ConstStruct([]llvm.Value{strglobal, strlen}, false)
	g := llvm.AddGlobal(tm.module, str.Type(), "")
	g.SetInitializer(str)
	return g
}
예제 #6
0
파일: typemap.go 프로젝트: minux/llgo
func (tm *TypeMap) makeAlgorithmTable(t types.Type) llvm.Value {
	// TODO set these to actual functions.
	hashAlg := llvm.ConstNull(llvm.PointerType(tm.alg.hashAlgFunctionType, 0))
	printAlg := llvm.ConstNull(llvm.PointerType(tm.alg.printAlgFunctionType, 0))
	copyAlg := llvm.ConstNull(llvm.PointerType(tm.alg.copyAlgFunctionType, 0))
	equalAlg := tm.alg.eqalg(t)
	elems := []llvm.Value{
		AlgorithmHash:  hashAlg,
		AlgorithmEqual: equalAlg,
		AlgorithmPrint: printAlg,
		AlgorithmCopy:  copyAlg,
	}
	return llvm.ConstStruct(elems, false)
}
예제 #7
0
파일: llvmtypes.go 프로젝트: c0der007/llgo
func (tm *TypeMap) makeAlgorithmTable(t types.Type) llvm.Value {
	// TODO set these to actual functions.
	hashAlg := llvm.ConstNull(llvm.PointerType(tm.hashAlgFunctionType, 0))
	printAlg := llvm.ConstNull(llvm.PointerType(tm.printAlgFunctionType, 0))
	copyAlg := llvm.ConstNull(llvm.PointerType(tm.copyAlgFunctionType, 0))

	equalAlgName := "runtime.memequal"
	equalAlg := tm.module.NamedFunction(equalAlgName)
	if equalAlg.IsNil() {
		equalAlg = llvm.AddFunction(
			tm.module, equalAlgName, tm.equalAlgFunctionType)
	}

	elems := []llvm.Value{hashAlg, equalAlg, printAlg, copyAlg}
	return llvm.ConstStruct(elems, false)
}
예제 #8
0
파일: interfaces.go 프로젝트: prattmic/llgo
// convertI2I converts an interface to another interface.
func (v *LLVMValue) convertI2I(iface *types.Interface) Value {
	builder := v.compiler.builder
	src_typ := v.Type()
	vptr := v.pointer.LLVMValue()
	src_typ = src_typ.(*types.Name).Underlying

	iface_struct_type := v.compiler.types.ToLLVM(iface)
	element_types := iface_struct_type.StructElementTypes()
	iface_elements := make([]llvm.Value, len(element_types))
	for i, _ := range iface_elements {
		iface_elements[i] = llvm.ConstNull(element_types[i])
	}
	iface_struct := llvm.ConstStruct(iface_elements, false)
	receiver := builder.CreateLoad(builder.CreateStructGEP(vptr, 0, ""), "")
	iface_struct = builder.CreateInsertValue(iface_struct, receiver, 0, "")

	// TODO check whether the functions in the struct take
	// value or pointer receivers.

	// TODO handle dynamic interface conversion (non-subset).
	methods := src_typ.(*types.Interface).Methods
	for i, m := range iface.Methods {
		// TODO make this loop linear by iterating through the
		// interface methods and type methods together.
		mi := sort.Search(len(methods), func(i int) bool {
			return methods[i].Name >= m.Name
		})
		if mi >= len(methods) || methods[mi].Name != m.Name {
			panic("Failed to locate method: " + m.Name)
		}
		method := builder.CreateStructGEP(vptr, mi+2, "")
		iface_struct = builder.CreateInsertValue(
			iface_struct, builder.CreateLoad(method, ""), i+2, "")
	}
	return v.compiler.NewLLVMValue(iface_struct, iface)
}
예제 #9
0
파일: compiler.go 프로젝트: c0der007/llgo
func (compiler *compiler) Compile(fset *token.FileSet,
	pkg *ast.Package,
	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.initfuncs = make([]Value, 0)

	// Create a Builder, for building LLVM instructions.
	compiler.builder = llvm.GlobalContext().NewBuilder()
	defer compiler.builder.Dispose()

	// Create a TargetMachine from the OS & Arch.
	triple := fmt.Sprintf("%s-unknown-%s",
		getTripleArchName(compiler.targetArch),
		compiler.targetOs)
	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)
		}
	}()
	compiler.types = NewTypeMap(compiler.module.Module, compiler.target, exprTypes)

	// Create a mapping from objects back to packages, so we can create the
	// appropriate symbol names.
	compiler.pkgmap = createPackageMap(pkg)

	// 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.
	compiler.defineRuntimeIntrinsics()

	// 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.
	if len(compiler.initfuncs) > 0 {
		elttypes := []llvm.Type{
			llvm.Int32Type(),
			llvm.PointerType(
				llvm.FunctionType(llvm.VoidType(), nil, false), 0)}
		ctortype := llvm.StructType(elttypes, false)
		ctors := make([]llvm.Value, len(compiler.initfuncs))
		for i, fn := range compiler.initfuncs {
			struct_values := []llvm.Value{
				llvm.ConstInt(llvm.Int32Type(), 1, false),
				fn.LLVMValue()}
			ctors[i] = llvm.ConstStruct(struct_values, false)
		}

		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)
	}

	// Create debug metadata.
	compiler.createMetadata()

	return compiler.module, nil
}
예제 #10
0
파일: interfaces.go 프로젝트: prattmic/llgo
// convertV2I converts a value to an interface.
func (v *LLVMValue) convertV2I(iface *types.Interface) Value {
	// TODO deref indirect value, then use 'pointer' as pointer value.
	var srcname *types.Name
	srctyp := v.Type()
	if name, isname := srctyp.(*types.Name); isname {
		srcname = name
		srctyp = name.Underlying
	}

	isptr := false
	if p, fromptr := srctyp.(*types.Pointer); fromptr {
		isptr = true
		srctyp = p.Base
		if name, isname := srctyp.(*types.Name); isname {
			srcname = name
			srctyp = name.Underlying
		}
	}

	iface_struct_type := v.compiler.types.ToLLVM(iface)
	element_types := iface_struct_type.StructElementTypes()
	iface_elements := make([]llvm.Value, len(element_types))
	for i, _ := range iface_elements {
		iface_elements[i] = llvm.ConstNull(element_types[i])
	}
	iface_struct := llvm.ConstStruct(iface_elements, false)

	builder := v.compiler.builder
	var ptr llvm.Value
	if isptr {
		ptr = v.LLVMValue()
	} else {
		// If the value fits exactly in a pointer, then we can just
		// bitcast it. Otherwise we need to malloc, and create a shim
		// function to load the receiver.
		lv := v.LLVMValue()
		c := v.compiler
		ptrsize := c.target.PointerSize()
		if c.target.TypeStoreSize(lv.Type()) <= uint64(ptrsize) {
			bits := c.target.TypeSizeInBits(lv.Type())
			if bits > 0 {
				lv = builder.CreateBitCast(lv, llvm.IntType(int(bits)), "")
				ptr = builder.CreateIntToPtr(lv, element_types[0], "")
			} else {
				ptr = llvm.ConstNull(element_types[0])
			}
		} else {
			ptr = builder.CreateMalloc(v.compiler.types.ToLLVM(srctyp), "")
			builder.CreateStore(lv, ptr)
			// TODO signal that shim functions are required. Probably later
			// we'll have the CallExpr handler pick out the type, and check
			// if the receiver is a pointer or a value type, and load as
			// necessary.
		}
	}
	ptr = builder.CreateBitCast(ptr, element_types[0], "")
	iface_struct = builder.CreateInsertValue(iface_struct, ptr, 0, "")

	var runtimeType llvm.Value
	if srcname != nil {
		runtimeType = v.compiler.types.ToRuntime(srcname)
	} else {
		runtimeType = v.compiler.types.ToRuntime(srctyp)
	}
	runtimeType = builder.CreateBitCast(runtimeType, element_types[1], "")
	iface_struct = builder.CreateInsertValue(iface_struct, runtimeType, 1, "")

	// TODO assert either source is a named type (or pointer to), or the
	// interface has an empty methodset.

	if srcname != nil {
		// TODO check whether the functions in the struct take
		// value or pointer receivers.

		// Look up the method by name.
		methods := srcname.Methods
		for i, m := range iface.Methods {
			// TODO make this loop linear by iterating through the
			// interface methods and type methods together.
			mi := sort.Search(len(methods), func(i int) bool {
				return methods[i].Name >= m.Name
			})
			if mi >= len(methods) || methods[mi].Name != m.Name {
				panic("Failed to locate method: " + m.Name)
			}
			method_obj := methods[mi]
			method := v.compiler.Resolve(method_obj).(*LLVMValue)
			llvm_value := method.LLVMValue()
			llvm_value = builder.CreateBitCast(
				llvm_value, element_types[i+2], "")
			iface_struct = builder.CreateInsertValue(
				iface_struct, llvm_value, i+2, "")
		}
	}

	return v.compiler.NewLLVMValue(iface_struct, iface)
}
예제 #11
0
파일: value.go 프로젝트: kisielk/llgo
func (v ConstValue) LLVMValue() llvm.Value {
	typ := types.Underlying(v.Type())
	if name, ok := typ.(*types.Name); ok {
		typ = name.Underlying
	}

	switch typ.(*types.Basic).Kind {
	case types.IntKind, types.UintKind:
		return llvm.ConstInt(llvm.Int32Type(), uint64(v.Int64()), true)
		// TODO 32/64bit (probably wait for gc)
		//int_val := v.Val.(*big.Int)
		//if int_val.Cmp(maxBigInt32) > 0 || int_val.Cmp(minBigInt32) < 0 {
		//	panic(fmt.Sprint("const ", int_val, " overflows int"))
		//}
		//return llvm.ConstInt(v.compiler.target.IntPtrType(), uint64(v.Int64()), true)

	case types.Int8Kind:
		return llvm.ConstInt(llvm.Int8Type(), uint64(v.Int64()), true)
	case types.Uint8Kind:
		return llvm.ConstInt(llvm.Int8Type(), uint64(v.Int64()), false)

	case types.Int16Kind:
		return llvm.ConstInt(llvm.Int16Type(), uint64(v.Int64()), true)
	case types.Uint16Kind:
		return llvm.ConstInt(llvm.Int16Type(), uint64(v.Int64()), false)

	case types.Int32Kind:
		return llvm.ConstInt(llvm.Int32Type(), uint64(v.Int64()), true)
	case types.Uint32Kind:
		return llvm.ConstInt(llvm.Int32Type(), uint64(v.Int64()), false)

	case types.Int64Kind:
		return llvm.ConstInt(llvm.Int64Type(), uint64(v.Int64()), true)
	case types.Uint64Kind:
		return llvm.ConstInt(llvm.Int64Type(), uint64(v.Int64()), false)

	case types.Float32Kind:
		return llvm.ConstFloat(llvm.FloatType(), float64(v.Float64()))
	case types.Float64Kind:
		return llvm.ConstFloat(llvm.DoubleType(), float64(v.Float64()))

	case types.Complex64Kind:
		r_, i_ := v.Complex()
		r := llvm.ConstFloat(llvm.FloatType(), r_)
		i := llvm.ConstFloat(llvm.FloatType(), i_)
		return llvm.ConstStruct([]llvm.Value{r, i}, false)
	case types.Complex128Kind:
		r_, i_ := v.Complex()
		r := llvm.ConstFloat(llvm.DoubleType(), r_)
		i := llvm.ConstFloat(llvm.DoubleType(), i_)
		return llvm.ConstStruct([]llvm.Value{r, i}, false)

	case types.UnsafePointerKind, types.UintptrKind:
		inttype := v.compiler.target.IntPtrType()
		return llvm.ConstInt(inttype, uint64(v.Int64()), false)

	case types.StringKind:
		strval := (v.Val).(string)
		strlen := len(strval)
		i8ptr := llvm.PointerType(llvm.Int8Type(), 0)
		var ptr llvm.Value
		if strlen > 0 {
			ptr = v.compiler.builder.CreateGlobalStringPtr(strval, "")
			ptr = llvm.ConstBitCast(ptr, i8ptr)
		} else {
			ptr = llvm.ConstNull(i8ptr)
		}
		len_ := llvm.ConstInt(llvm.Int32Type(), uint64(strlen), false)
		return llvm.ConstStruct([]llvm.Value{ptr, len_}, false)

	case types.BoolKind:
		if v := v.Val.(bool); v {
			return llvm.ConstAllOnes(llvm.Int1Type())
		}
		return llvm.ConstNull(llvm.Int1Type())
	}
	panic(fmt.Errorf("Unhandled type: %v", typ)) //v.typ.Kind))
}
예제 #12
0
파일: compiler.go 프로젝트: octabrain/llgo
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)
	}

	// Create debug metadata.
	//compiler.createMetadata()

	return compiler.module, nil
}
예제 #13
0
파일: compiler.go 프로젝트: kisielk/llgo
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
		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)
	}

	// Create debug metadata.
	//compiler.createMetadata()

	return compiler.module, nil
}