Beispiel #1
0
func (tm *TypeMap) interfaceRuntimeType(i *types.Interface) (global, ptr llvm.Value) {
	rtype := tm.makeRtype(i, reflect.Interface)
	interfaceType := llvm.ConstNull(tm.runtime.interfaceType.llvm)
	global, ptr = tm.makeRuntimeTypeGlobal(interfaceType, typeString(i))
	tm.types.Set(i, runtimeTypeInfo{global, ptr})
	interfaceType = llvm.ConstInsertValue(interfaceType, rtype, []uint32{0})
	methodset := tm.MethodSet(i)
	imethods := make([]llvm.Value, methodset.Len())
	for index := 0; index < methodset.Len(); index++ {
		method := methodset.At(index).Obj()
		imethod := llvm.ConstNull(tm.runtime.imethod.llvm)
		name := tm.globalStringPtr(method.Name())
		name = llvm.ConstBitCast(name, tm.runtime.imethod.llvm.StructElementTypes()[0])
		mtyp := tm.ToRuntime(method.Type())
		imethod = llvm.ConstInsertValue(imethod, name, []uint32{0})
		if !ast.IsExported(method.Name()) {
			pkgpath := tm.globalStringPtr(method.Pkg().Path())
			pkgpath = llvm.ConstBitCast(pkgpath, tm.runtime.imethod.llvm.StructElementTypes()[1])
			imethod = llvm.ConstInsertValue(imethod, pkgpath, []uint32{1})
		}
		imethod = llvm.ConstInsertValue(imethod, mtyp, []uint32{2})
		imethods[index] = imethod
	}
	imethodsSliceType := tm.runtime.interfaceType.llvm.StructElementTypes()[1]
	imethodsSlice := tm.makeSlice(imethods, imethodsSliceType)
	interfaceType = llvm.ConstInsertValue(interfaceType, imethodsSlice, []uint32{1})
	global.SetInitializer(interfaceType)
	return global, ptr
}
Beispiel #2
0
func (tm *TypeMap) interfaceRuntimeType(tstr string, i *types.Interface) (global, ptr llvm.Value) {
	rtype := tm.makeRtype(i, reflect.Interface)
	interfaceType := llvm.ConstNull(tm.runtimeInterfaceType)
	global, ptr = tm.makeRuntimeTypeGlobal(interfaceType)
	tm.types.record(tstr, global, ptr)
	interfaceType = llvm.ConstInsertValue(interfaceType, rtype, []uint32{0})
	methodset := i.MethodSet()
	imethods := make([]llvm.Value, methodset.Len())
	for index := 0; index < methodset.Len(); index++ {
		method := methodset.At(index).Obj()
		imethod := llvm.ConstNull(tm.runtimeImethod)
		name := tm.globalStringPtr(method.Name())
		name = llvm.ConstBitCast(name, tm.runtimeImethod.StructElementTypes()[0])
		//pkgpath := tm.globalStringPtr(tm.functions.objectdata[method].Package.Path())
		//pkgpath = llvm.ConstBitCast(name, tm.runtimeImethod.StructElementTypes()[1])
		mtyp := tm.ToRuntime(method.Type())
		imethod = llvm.ConstInsertValue(imethod, name, []uint32{0})
		//imethod = llvm.ConstInsertValue(imethod, pkgpath, []uint32{1})
		imethod = llvm.ConstInsertValue(imethod, mtyp, []uint32{2})
		imethods[index] = imethod
	}
	imethodsSliceType := tm.runtimeInterfaceType.StructElementTypes()[1]
	imethodsSlice := tm.makeSlice(imethods, imethodsSliceType)
	interfaceType = llvm.ConstInsertValue(interfaceType, imethodsSlice, []uint32{1})
	global.SetInitializer(interfaceType)
	return global, ptr
}
Beispiel #3
0
func (tm *TypeMap) uncommonType(n *types.Named, ptr bool) llvm.Value {
	uncommonTypeInit := llvm.ConstNull(tm.runtimeUncommonType)
	namePtr := tm.globalStringPtr(n.Obj().Name())
	uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, namePtr, []uint32{0})

	_, path := tm.qualifiedName(n)
	pkgpathPtr := tm.globalStringPtr(path)
	uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, pkgpathPtr, []uint32{1})

	methodset := tm.functions.methods(n)
	methodfuncs := methodset.nonptr
	if ptr {
		methodfuncs = methodset.ptr
	}

	// Store methods.
	methods := make([]llvm.Value, len(methodfuncs))
	for i, mfunc := range methodfuncs {
		ftyp := mfunc.Type().(*types.Signature)

		method := llvm.ConstNull(tm.runtimeMethod)
		name := tm.globalStringPtr(mfunc.Name())
		name = llvm.ConstBitCast(name, tm.runtimeMethod.StructElementTypes()[0])
		// name
		method = llvm.ConstInsertValue(method, name, []uint32{0})
		// pkgPath
		method = llvm.ConstInsertValue(method, pkgpathPtr, []uint32{1})
		// mtyp (method type, no receiver)
		{
			ftyp := types.NewSignature(nil, nil, ftyp.Params(), ftyp.Results(), ftyp.IsVariadic())
			mtyp := tm.ToRuntime(ftyp)
			method = llvm.ConstInsertValue(method, mtyp, []uint32{2})
		}
		// typ (function type, with receiver)
		typ := tm.ToRuntime(ftyp)
		method = llvm.ConstInsertValue(method, typ, []uint32{3})

		// tfn (standard method/function pointer for plain method calls)
		tfn := tm.resolver.Resolve(tm.functions.objectdata[mfunc].Ident).LLVMValue()
		tfn = llvm.ConstExtractValue(tfn, []uint32{0})
		tfn = llvm.ConstPtrToInt(tfn, tm.target.IntPtrType())

		// ifn (single-word receiver function pointer for interface calls)
		ifn := tfn
		if !ptr && tm.Sizeof(ftyp.Recv().Type()) > int64(tm.target.PointerSize()) {
			mfunc := methodset.lookup(mfunc.Name(), true)
			ifn = tm.resolver.Resolve(tm.functions.objectdata[mfunc].Ident).LLVMValue()
			ifn = llvm.ConstExtractValue(ifn, []uint32{0})
			ifn = llvm.ConstPtrToInt(ifn, tm.target.IntPtrType())
		}

		method = llvm.ConstInsertValue(method, ifn, []uint32{4})
		method = llvm.ConstInsertValue(method, tfn, []uint32{5})
		methods[i] = method
	}
	methodsSliceType := tm.runtimeUncommonType.StructElementTypes()[2]
	methodsSlice := tm.makeSlice(methods, methodsSliceType)
	uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, methodsSlice, []uint32{2})
	return uncommonTypeInit
}
Beispiel #4
0
func (tm *TypeMap) makeRuntimeTypeGlobal(v llvm.Value, name string) (global, ptr llvm.Value) {
	global = llvm.AddGlobal(tm.module, v.Type(), typeSymbol(name))
	global.SetInitializer(v)
	global.SetLinkage(llvm.LinkOnceAnyLinkage)
	ptr = llvm.ConstBitCast(global, llvm.PointerType(tm.runtime.rtype.llvm, 0))
	return global, ptr
}
Beispiel #5
0
func (tm *TypeMap) nameRuntimeType(n *types.Named) (global, ptr llvm.Value) {
	name := typeString(n)
	path := "runtime"
	if pkg := n.Obj().Pkg(); pkg != nil {
		path = pkg.Path()
	}
	if path != tm.pkgpath {
		// We're not compiling the package from whence the type came,
		// so we'll just create a pointer to it here.
		global := llvm.AddGlobal(tm.module, tm.runtime.rtype.llvm, typeSymbol(name))
		global.SetInitializer(llvm.ConstNull(tm.runtime.rtype.llvm))
		global.SetLinkage(llvm.CommonLinkage)
		return global, global
	}

	// If the underlying type is Basic, then we always create
	// a new global. Otherwise, we clone the value returned
	// from toRuntime in case it is cached and reused.
	underlying := n.Underlying()
	if basic, ok := underlying.(*types.Basic); ok {
		global, ptr = tm.basicRuntimeType(basic, true)
		global.SetName(typeSymbol(name))
	} else {
		global, ptr = tm.toRuntime(underlying)
		clone := llvm.AddGlobal(tm.module, global.Type().ElementType(), typeSymbol(name))
		clone.SetInitializer(global.Initializer())
		global = clone
		ptr = llvm.ConstBitCast(global, llvm.PointerType(tm.runtime.rtype.llvm, 0))
	}
	global.SetLinkage(llvm.ExternalLinkage)

	// Locate the rtype.
	underlyingRuntimeType := global.Initializer()
	rtype := underlyingRuntimeType
	if rtype.Type() != tm.runtime.rtype.llvm {
		rtype = llvm.ConstExtractValue(rtype, []uint32{0})
	}

	// Insert the uncommon type.
	uncommonTypeInit := tm.uncommonType(n, nil)
	uncommonType := llvm.AddGlobal(tm.module, uncommonTypeInit.Type(), "")
	uncommonType.SetInitializer(uncommonTypeInit)
	rtype = llvm.ConstInsertValue(rtype, uncommonType, []uint32{9})

	// Replace the rtype's string representation with the one from
	// uncommonType. XXX should we have the package name prepended? Probably.
	namePtr := llvm.ConstExtractValue(uncommonTypeInit, []uint32{0})
	rtype = llvm.ConstInsertValue(rtype, namePtr, []uint32{8})

	// Update the global's initialiser. Note that we take a copy
	// of the underlying type; we're not updating a shared type.
	if underlyingRuntimeType.Type() != tm.runtime.rtype.llvm {
		underlyingRuntimeType = llvm.ConstInsertValue(underlyingRuntimeType, rtype, []uint32{0})
	} else {
		underlyingRuntimeType = rtype
	}
	global.SetInitializer(underlyingRuntimeType)
	return global, ptr
}
Beispiel #6
0
func (tm *TypeMap) makeRuntimeTypeGlobal(v llvm.Value) (global, ptr llvm.Value) {
	// Each runtime type is preceded by an interface{}.
	initType := llvm.StructType([]llvm.Type{tm.runtimeType, v.Type()}, false)
	global = llvm.AddGlobal(tm.module, initType, "")
	ptr = llvm.ConstBitCast(global, llvm.PointerType(tm.runtimeType, 0))

	// interface{} containing v's *commonType representation.
	runtimeTypeValue := llvm.Undef(tm.runtimeType)
	zero := llvm.ConstNull(llvm.Int32Type())
	one := llvm.ConstInt(llvm.Int32Type(), 1, false)
	i8ptr := llvm.PointerType(llvm.Int8Type(), 0)
	if tm.commonTypePtrRuntimeType.IsNil() {
		// Create a dummy pointer value, which we'll update straight after
		// defining the runtime type info for commonType.
		tm.commonTypePtrRuntimeType = llvm.Undef(i8ptr)
		commonTypePtr := &types.Pointer{Base: tm.commonType}
		commonTypeGlobal, commonTypeRuntimeType := tm.makeRuntimeType(tm.commonType)
		tm.types[tm.commonType.String()] = runtimeTypeInfo{commonTypeGlobal, commonTypeRuntimeType}
		commonTypePtrGlobal, commonTypePtrRuntimeType := tm.makeRuntimeType(commonTypePtr)
		tm.types[commonTypePtr.String()] = runtimeTypeInfo{commonTypePtrGlobal, commonTypePtrRuntimeType}
		tm.commonTypePtrRuntimeType = llvm.ConstBitCast(commonTypePtrRuntimeType, i8ptr)
		if tm.pkgpath == tm.commonType.Package {
			// Update the interace{} header of the commonType/*commonType
			// runtime types we just created.
			for _, g := range [...]llvm.Value{commonTypeGlobal, commonTypePtrGlobal} {
				init := g.Initializer()
				typptr := tm.commonTypePtrRuntimeType
				runtimeTypeValue := llvm.ConstExtractValue(init, []uint32{0})
				runtimeTypeValue = llvm.ConstInsertValue(runtimeTypeValue, typptr, []uint32{0})
				init = llvm.ConstInsertValue(init, runtimeTypeValue, []uint32{0})
				g.SetInitializer(init)
			}
		}
	}
	commonTypePtr := llvm.ConstGEP(global, []llvm.Value{zero, one})
	commonTypePtr = llvm.ConstBitCast(commonTypePtr, i8ptr)
	runtimeTypeValue = llvm.ConstInsertValue(runtimeTypeValue, tm.commonTypePtrRuntimeType, []uint32{0})
	runtimeTypeValue = llvm.ConstInsertValue(runtimeTypeValue, commonTypePtr, []uint32{1})

	init := llvm.Undef(initType)
	init = llvm.ConstInsertValue(init, runtimeTypeValue, []uint32{0})
	init = llvm.ConstInsertValue(init, v, []uint32{1})
	global.SetInitializer(init)

	return global, ptr
}
Beispiel #7
0
func (tm *TypeMap) basicRuntimeType(b *types.Basic) llvm.Value {
	commonType := tm.makeCommonType(b, reflect.Kind(b.Kind))
	result := llvm.AddGlobal(tm.module, commonType.Type(), "")
	elementTypes := tm.runtimeCommonType.StructElementTypes()
	ptr := llvm.ConstBitCast(result, elementTypes[9])
	commonType = llvm.ConstInsertValue(commonType, ptr, []uint32{9})
	result.SetInitializer(commonType)
	return result
}
Beispiel #8
0
func (tm *TypeMap) structRuntimeType(s *types.Struct) (global, ptr llvm.Value) {
	rtype := tm.makeRtype(s, reflect.Struct)
	structType := llvm.ConstNull(tm.runtime.structType.llvm)
	structType = llvm.ConstInsertValue(structType, rtype, []uint32{0})
	global, ptr = tm.makeRuntimeTypeGlobal(structType, typeString(s))
	tm.types.Set(s, runtimeTypeInfo{global, ptr})
	fieldVars := make([]*types.Var, s.NumFields())
	for i := range fieldVars {
		fieldVars[i] = s.Field(i)
	}
	offsets := tm.Offsetsof(fieldVars)
	structFields := make([]llvm.Value, len(fieldVars))
	for i := range structFields {
		field := fieldVars[i]
		structField := llvm.ConstNull(tm.runtime.structField.llvm)
		if !field.Anonymous() {
			name := tm.globalStringPtr(field.Name())
			name = llvm.ConstBitCast(name, tm.runtime.structField.llvm.StructElementTypes()[0])
			structField = llvm.ConstInsertValue(structField, name, []uint32{0})
		}
		if !ast.IsExported(field.Name()) {
			pkgpath := tm.globalStringPtr(field.Pkg().Path())
			pkgpath = llvm.ConstBitCast(pkgpath, tm.runtime.structField.llvm.StructElementTypes()[1])
			structField = llvm.ConstInsertValue(structField, pkgpath, []uint32{1})
		}
		fieldType := tm.ToRuntime(field.Type())
		structField = llvm.ConstInsertValue(structField, fieldType, []uint32{2})
		if tag := s.Tag(i); tag != "" {
			tag := tm.globalStringPtr(tag)
			tag = llvm.ConstBitCast(tag, tm.runtime.structField.llvm.StructElementTypes()[3])
			structField = llvm.ConstInsertValue(structField, tag, []uint32{3})
		}
		offset := llvm.ConstInt(tm.runtime.structField.llvm.StructElementTypes()[4], uint64(offsets[i]), false)
		structField = llvm.ConstInsertValue(structField, offset, []uint32{4})
		structFields[i] = structField
	}
	structFieldsSliceType := tm.runtime.structType.llvm.StructElementTypes()[1]
	structFieldsSlice := tm.makeSlice(structFields, structFieldsSliceType)
	structType = llvm.ConstInsertValue(structType, structFieldsSlice, []uint32{1})
	global.SetInitializer(structType)
	return global, ptr
}
Beispiel #9
0
// 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
}
Beispiel #10
0
func (tm *TypeMap) interfaceRuntimeType(i *types.Interface) (global, ptr llvm.Value) {
	rtype := tm.makeRtype(i, reflect.Interface)
	interfaceType := llvm.ConstNull(tm.runtimeInterfaceType)
	interfaceType = llvm.ConstInsertValue(interfaceType, rtype, []uint32{0})

	imethods := make([]llvm.Value, i.NumMethods())
	for index := range imethods {
		method := i.Method(index)

		//name, pkgPath, type
		imethod := llvm.ConstNull(tm.runtimeImethod)
		name := tm.globalStringPtr(method.Name())
		name = llvm.ConstBitCast(name, tm.runtimeImethod.StructElementTypes()[0])

		imethod = llvm.ConstInsertValue(imethod, name, []uint32{0})
		//imethod = llvm.ConstInsertValue(imethod, , []uint32{1})
		//imethod = llvm.ConstInsertValue(imethod, , []uint32{2})
		imethods[index] = imethod
	}

	var imethodsGlobalPtr llvm.Value
	imethodPtrType := llvm.PointerType(tm.runtimeImethod, 0)
	if len(imethods) > 0 {
		imethodsArray := llvm.ConstArray(tm.runtimeImethod, imethods)
		imethodsGlobalPtr = llvm.AddGlobal(tm.module, imethodsArray.Type(), "")
		imethodsGlobalPtr.SetInitializer(imethodsArray)
		imethodsGlobalPtr = llvm.ConstBitCast(imethodsGlobalPtr, imethodPtrType)
	} else {
		imethodsGlobalPtr = llvm.ConstNull(imethodPtrType)
	}

	len_ := llvm.ConstInt(tm.inttype, uint64(i.NumMethods()), false)
	imethodsSliceType := tm.runtimeInterfaceType.StructElementTypes()[1]
	imethodsSlice := llvm.ConstNull(imethodsSliceType)
	imethodsSlice = llvm.ConstInsertValue(imethodsSlice, imethodsGlobalPtr, []uint32{0})
	imethodsSlice = llvm.ConstInsertValue(imethodsSlice, len_, []uint32{1})
	imethodsSlice = llvm.ConstInsertValue(imethodsSlice, len_, []uint32{2})
	interfaceType = llvm.ConstInsertValue(interfaceType, imethodsSlice, []uint32{1})
	return tm.makeRuntimeTypeGlobal(interfaceType)
}
Beispiel #11
0
func (tm *TypeMap) mapRuntimeType(m *types.Map) llvm.Value {
	result := llvm.AddGlobal(tm.module, tm.runtimeMapType, "")
	elementTypes := tm.runtimeCommonType.StructElementTypes()
	ptr := llvm.ConstBitCast(result, elementTypes[9])
	commonType := tm.makeCommonType(m, reflect.Map)
	commonType = llvm.ConstInsertValue(commonType, ptr, []uint32{9})

	init := llvm.ConstNull(tm.runtimeMapType)
	init = llvm.ConstInsertValue(init, commonType, []uint32{0})
	result.SetInitializer(init)

	// TODO set key, elem

	return result
}
Beispiel #12
0
func (tm *TypeMap) structRuntimeType(s *types.Struct) llvm.Value {
	result := llvm.AddGlobal(tm.module, tm.runtimeStructType, "")
	elementTypes := tm.runtimeCommonType.StructElementTypes()
	ptr := llvm.ConstBitCast(result, elementTypes[9])
	commonType := tm.makeCommonType(s, reflect.Struct)
	commonType = llvm.ConstInsertValue(commonType, ptr, []uint32{9})

	init := llvm.ConstNull(tm.runtimeStructType)
	init = llvm.ConstInsertValue(init, commonType, []uint32{0})
	result.SetInitializer(init)

	// TODO set fields

	//panic("unimplemented")
	return result
}
Beispiel #13
0
func (tm *TypeMap) nameRuntimeType(n *types.Name) llvm.Value {
	underlyingRuntimeType := tm.ToRuntime(n.Underlying).Initializer()
	result := llvm.AddGlobal(tm.module, underlyingRuntimeType.Type(), "")
	result.SetName("__llgo.reflect." + n.Obj.Name)
	elementTypes := tm.runtimeCommonType.StructElementTypes()
	ptr := llvm.ConstBitCast(result, elementTypes[9])
	commonType := llvm.ConstInsertValue(underlyingRuntimeType, ptr, []uint32{9})

	uncommonTypeInit := llvm.ConstNull(tm.runtimeUncommonType) // TODO
	uncommonType := llvm.AddGlobal(tm.module, uncommonTypeInit.Type(), "")
	uncommonType.SetInitializer(uncommonTypeInit)
	commonType = llvm.ConstInsertValue(commonType, uncommonType, []uint32{8})

	// TODO set string, uncommonType.
	result.SetInitializer(commonType)
	return result
}
Beispiel #14
0
func (tm *TypeMap) makeSlice(values []llvm.Value, slicetyp llvm.Type) llvm.Value {
	ptrtyp := slicetyp.StructElementTypes()[0]
	var globalptr llvm.Value
	if len(values) > 0 {
		array := llvm.ConstArray(ptrtyp.ElementType(), values)
		globalptr = llvm.AddGlobal(tm.module, array.Type(), "")
		globalptr.SetInitializer(array)
		globalptr = llvm.ConstBitCast(globalptr, ptrtyp)
	} else {
		globalptr = llvm.ConstNull(ptrtyp)
	}
	len_ := llvm.ConstInt(tm.inttype, uint64(len(values)), false)
	slice := llvm.ConstNull(slicetyp)
	slice = llvm.ConstInsertValue(slice, globalptr, []uint32{0})
	slice = llvm.ConstInsertValue(slice, len_, []uint32{1})
	slice = llvm.ConstInsertValue(slice, len_, []uint32{2})
	return slice
}
Beispiel #15
0
// convertI2V converts an interface to a value.
func (v *LLVMValue) convertI2V(typ types.Type) (result, success Value) {
	typptrType := llvm.PointerType(llvm.Int8Type(), 0)
	runtimeType := v.compiler.types.ToRuntime(typ)
	runtimeType = llvm.ConstBitCast(runtimeType, typptrType)
	vval := v.LLVMValue()

	builder := v.compiler.builder
	ifaceType := builder.CreateExtractValue(vval, 0, "")
	diff := builder.CreatePtrDiff(runtimeType, ifaceType, "")
	zero := llvm.ConstNull(diff.Type())
	predicate := builder.CreateICmp(llvm.IntEQ, diff, zero, "")

	// If result is zero, then we've got a match.
	end := llvm.InsertBasicBlock(builder.GetInsertBlock(), "end")
	end.MoveAfter(builder.GetInsertBlock())
	nonmatch := llvm.InsertBasicBlock(end, "nonmatch")
	match := llvm.InsertBasicBlock(nonmatch, "match")
	builder.CreateCondBr(predicate, match, nonmatch)

	builder.SetInsertPointAtEnd(match)
	matchResultValue := v.loadI2V(typ).LLVMValue()
	builder.CreateBr(end)

	builder.SetInsertPointAtEnd(nonmatch)
	nonmatchResultValue := llvm.ConstNull(matchResultValue.Type())
	builder.CreateBr(end)

	builder.SetInsertPointAtEnd(end)
	successValue := builder.CreatePHI(llvm.Int1Type(), "")
	resultValue := builder.CreatePHI(matchResultValue.Type(), "")

	successValues := []llvm.Value{llvm.ConstAllOnes(llvm.Int1Type()), llvm.ConstNull(llvm.Int1Type())}
	successBlocks := []llvm.BasicBlock{match, nonmatch}
	successValue.AddIncoming(successValues, successBlocks)
	success = v.compiler.NewLLVMValue(successValue, types.Bool)

	resultValues := []llvm.Value{matchResultValue, nonmatchResultValue}
	resultBlocks := []llvm.BasicBlock{match, nonmatch}
	resultValue.AddIncoming(resultValues, resultBlocks)
	result = v.compiler.NewLLVMValue(resultValue, typ)
	return result, success
}
Beispiel #16
0
func (tm *TypeMap) makeRtype(t types.Type, k reflect.Kind) llvm.Value {
	// Not sure if there's an easier way to do this, but if you just
	// use ConstStruct, you end up getting a different llvm.Type.
	lt := tm.ToLLVM(t)
	typ := llvm.ConstNull(tm.runtimeType)
	elementTypes := tm.runtimeType.StructElementTypes()

	// Size.
	size := llvm.SizeOf(lt)
	if size.Type().IntTypeWidth() > elementTypes[0].IntTypeWidth() {
		size = llvm.ConstTrunc(size, elementTypes[0])
	}
	typ = llvm.ConstInsertValue(typ, size, []uint32{0})

	// TODO hash
	// TODO padding

	// Alignment.
	align := llvm.ConstTrunc(llvm.AlignOf(lt), llvm.Int8Type())
	typ = llvm.ConstInsertValue(typ, align, []uint32{3}) // var
	typ = llvm.ConstInsertValue(typ, align, []uint32{4}) // field

	// Kind.
	kind := llvm.ConstInt(llvm.Int8Type(), uint64(k), false)
	typ = llvm.ConstInsertValue(typ, kind, []uint32{5})

	// Algorithm table.
	alg := tm.makeAlgorithmTable(t)
	algptr := llvm.AddGlobal(tm.module, alg.Type(), "")
	algptr.SetInitializer(alg)
	algptr = llvm.ConstBitCast(algptr, elementTypes[6])
	typ = llvm.ConstInsertValue(typ, algptr, []uint32{6})

	// String representation.
	stringrep := tm.globalStringPtr(tm.TypeString(t))
	typ = llvm.ConstInsertValue(typ, stringrep, []uint32{8})

	// TODO gc
	return typ
}
Beispiel #17
0
func (tm *TypeMap) makeRuntimeTypeGlobal(v llvm.Value) (global, ptr llvm.Value) {
	runtimeTypeValue := llvm.ConstNull(tm.runtimeType)
	initType := llvm.StructType([]llvm.Type{tm.runtimeType, v.Type()}, false)
	global = llvm.AddGlobal(tm.module, initType, "")
	ptr = llvm.ConstBitCast(global, llvm.PointerType(tm.runtimeType, 0))

	// Set ptrToThis in v's commonType.
	if v.Type() == tm.runtimeCommonType {
		v = llvm.ConstInsertValue(v, ptr, []uint32{9})
	} else {
		commonType := llvm.ConstExtractValue(v, []uint32{0})
		commonType = llvm.ConstInsertValue(commonType, ptr, []uint32{9})
		v = llvm.ConstInsertValue(v, commonType, []uint32{0})
	}

	init := llvm.Undef(initType)
	//runtimeTypeValue = llvm.ConstInsertValue() TODO
	init = llvm.ConstInsertValue(init, runtimeTypeValue, []uint32{0})
	init = llvm.ConstInsertValue(init, v, []uint32{1})
	global.SetInitializer(init)

	return
}
Beispiel #18
0
// convertI2V converts an interface to a value.
func (v *LLVMValue) convertI2V(typ types.Type) Value {
	typptrType := llvm.PointerType(llvm.Int8Type(), 0)
	runtimeType := v.compiler.types.ToRuntime(typ)
	runtimeType = llvm.ConstBitCast(runtimeType, typptrType)
	vptr := v.pointer.LLVMValue()

	builder := v.compiler.builder
	ifaceType := builder.CreateLoad(builder.CreateStructGEP(vptr, 1, ""), "")
	diff := builder.CreatePtrDiff(runtimeType, ifaceType, "")
	zero := llvm.ConstNull(diff.Type())
	predicate := builder.CreateICmp(llvm.IntEQ, diff, zero, "")
	llvmtype := v.compiler.types.ToLLVM(typ)
	result := builder.CreateAlloca(llvmtype, "")

	// If result is zero, then we've got a match.
	end := llvm.InsertBasicBlock(builder.GetInsertBlock(), "end")
	end.MoveAfter(builder.GetInsertBlock())
	nonmatch := llvm.InsertBasicBlock(end, "nonmatch")
	match := llvm.InsertBasicBlock(nonmatch, "match")
	builder.CreateCondBr(predicate, match, nonmatch)

	builder.SetInsertPointAtEnd(match)
	value := builder.CreateLoad(builder.CreateStructGEP(vptr, 0, ""), "")
	value = builder.CreateBitCast(value, result.Type(), "")
	value = builder.CreateLoad(value, "")
	builder.CreateStore(value, result)
	builder.CreateBr(end)

	// TODO should return {value, ok}
	builder.SetInsertPointAtEnd(nonmatch)
	builder.CreateStore(llvm.ConstNull(llvmtype), result)
	builder.CreateBr(end)

	//builder.SetInsertPointAtEnd(end)
	result = builder.CreateLoad(result, "")
	return v.compiler.NewLLVMValue(result, typ)
}
Beispiel #19
0
func (compiler *compiler) Compile(fset *token.FileSet, files []*ast.File, importpath string) (m *Module, err error) {
	// FIXME create a compilation state, rather than storing in 'compiler'.
	compiler.fileset = fset
	compiler.initfuncs = nil
	compiler.varinitfuncs = nil

	// Type-check, and store object data.
	compiler.objects = make(map[*ast.Ident]types.Object)
	compiler.objectdata = make(map[types.Object]*ObjectData)
	compiler.methodsets = make(map[types.Type]*methodset)
	compiler.llvmtypes = NewLLVMTypeMap(compiler.target)
	pkg, exprtypes, err := compiler.typecheck(importpath, fset, files)
	if err != nil {
		return nil, err
	}
	compiler.pkg = pkg
	importpath = pkgpath(pkg)

	// 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 := importpath
	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)
		}
	}()

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

	// Create a Builder, for building LLVM instructions.
	compiler.builder = newBuilder(compiler.types)
	defer compiler.builder.Dispose()

	// Compile each file in the package.
	for _, file := range files {
		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 importpath == "runtime" {
		compiler.defineRuntimeIntrinsics()
	}

	// Export runtime type information.
	if importpath == "runtime" {
		compiler.exportBuiltinRuntimeTypes()
	}

	// Wrap "main.main" in a call to runtime.main.
	if importpath == "main" {
		err = compiler.createMainFunction()
		if err != nil {
			return nil, err
		}
	}

	// Create global constructors. The initfuncs/varinitfuncs
	// slices are in the order of visitation; we generate the
	// list of constructors in the reverse order.
	//
	// The llgo linker will link modules in the order of
	// package dependency, i.e. if A requires B, then llgo-link
	// will link the modules in the order A, B. The "runtime"
	// package is always last.
	//
	// At program initialisation, the runtime initialisation
	// function (runtime.main) will invoke the constructors
	// in reverse order.
	var initfuncs [][]llvm.Value
	if compiler.varinitfuncs != nil {
		initfuncs = append(initfuncs, compiler.varinitfuncs)
	}
	if compiler.initfuncs != nil {
		initfuncs = append(initfuncs, compiler.initfuncs)
	}
	if initfuncs != nil {
		ctortype := llvm.PointerType(llvm.Int8Type(), 0)
		var ctors []llvm.Value
		var index int = 0
		for _, initfuncs := range initfuncs {
			for _, fnptr := range initfuncs {
				name := fmt.Sprintf("__llgo.ctor.%s.%d", importpath, index)
				fnptr.SetName(name)
				fnptr = llvm.ConstBitCast(fnptr, ctortype)
				ctors = append(ctors, fnptr)
				index++
			}
		}
		for i, n := 0, len(ctors); i < n/2; i++ {
			ctors[i], ctors[n-i-1] = ctors[n-i-1], ctors[i]
		}
		ctorsInit := llvm.ConstArray(ctortype, ctors)
		ctorsVar := llvm.AddGlobal(compiler.module.Module, ctorsInit.Type(), "runtime.ctors")
		ctorsVar.SetInitializer(ctorsInit)
		ctorsVar.SetLinkage(llvm.AppendingLinkage)
	}

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

	return compiler.module, nil
}
Beispiel #20
0
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))
}
Beispiel #21
0
func (tm *TypeMap) makeRuntimeTypeGlobal(v llvm.Value) (global, ptr llvm.Value) {
	global = llvm.AddGlobal(tm.module, v.Type(), "")
	global.SetInitializer(v)
	ptr = llvm.ConstBitCast(global, llvm.PointerType(tm.runtimeType, 0))
	return global, ptr
}
Beispiel #22
0
func (tm *TypeMap) uncommonType(n *types.Named, ptr bool) llvm.Value {
	uncommonTypeInit := llvm.ConstNull(tm.runtimeUncommonType)
	namePtr := tm.globalStringPtr(n.Obj().Name())
	uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, namePtr, []uint32{0})

	// FIXME clean this up
	var pkgpathPtr llvm.Value
	var path string
	if data, ok := tm.functions.objectdata[n.Obj()]; ok {
		path = pkgpath(data.Package)
	}
	if path != "" {
		pkgpathPtr = tm.globalStringPtr(path)
		uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, pkgpathPtr, []uint32{1})
	}

	methodset := tm.functions.methods(n)
	methodfuncs := methodset.nonptr
	if ptr {
		methodfuncs = methodset.ptr
	}

	// Store methods.
	methods := make([]llvm.Value, len(methodfuncs))
	for i, mfunc := range methodfuncs {
		ftyp := mfunc.Type().(*types.Signature)

		method := llvm.ConstNull(tm.runtimeMethod)
		name := tm.globalStringPtr(mfunc.Name())
		name = llvm.ConstBitCast(name, tm.runtimeMethod.StructElementTypes()[0])
		// name
		method = llvm.ConstInsertValue(method, name, []uint32{0})
		// pkgPath
		method = llvm.ConstInsertValue(method, pkgpathPtr, []uint32{1})
		// mtyp (method type, no receiver)
		{
			ftyp := types.NewSignature(nil, ftyp.Params(), ftyp.Results(), ftyp.IsVariadic())
			mtyp := tm.ToRuntime(ftyp)
			method = llvm.ConstInsertValue(method, mtyp, []uint32{2})
		}
		// typ (function type, with receiver)
		typ := tm.ToRuntime(ftyp)
		method = llvm.ConstInsertValue(method, typ, []uint32{3})

		// tfn (standard method/function pointer for plain method calls)
		tfn := tm.resolver.Resolve(tm.functions.objectdata[mfunc].Ident).LLVMValue()
		tfn = llvm.ConstExtractValue(tfn, []uint32{0})
		tfn = llvm.ConstPtrToInt(tfn, tm.target.IntPtrType())

		// ifn (single-word receiver function pointer for interface calls)
		ifn := tfn
		if !ptr && tm.Sizeof(ftyp.Recv().Type()) > int64(tm.target.PointerSize()) {
			mfunc := methodset.lookup(mfunc.Name(), true)
			ifn = tm.resolver.Resolve(tm.functions.objectdata[mfunc].Ident).LLVMValue()
			ifn = llvm.ConstExtractValue(ifn, []uint32{0})
			ifn = llvm.ConstPtrToInt(ifn, tm.target.IntPtrType())
		}

		method = llvm.ConstInsertValue(method, ifn, []uint32{4})
		method = llvm.ConstInsertValue(method, tfn, []uint32{5})
		methods[i] = method
	}

	var methodsGlobalPtr llvm.Value
	if len(methods) > 0 {
		methodsArray := llvm.ConstArray(tm.runtimeMethod, methods)
		methodsGlobalPtr = llvm.AddGlobal(tm.module, methodsArray.Type(), "")
		methodsGlobalPtr.SetInitializer(methodsArray)
		i32zero := llvm.ConstNull(llvm.Int32Type())
		methodsGlobalPtr = llvm.ConstGEP(methodsGlobalPtr, []llvm.Value{i32zero, i32zero})
	} else {
		methodsGlobalPtr = llvm.ConstNull(llvm.PointerType(tm.runtimeMethod, 0))
	}
	len_ := llvm.ConstInt(tm.inttype, uint64(len(methods)), false)
	methodsSliceType := tm.runtimeUncommonType.StructElementTypes()[2]
	methodsSlice := llvm.ConstNull(methodsSliceType)
	methodsSlice = llvm.ConstInsertValue(methodsSlice, methodsGlobalPtr, []uint32{0})
	methodsSlice = llvm.ConstInsertValue(methodsSlice, len_, []uint32{1})
	methodsSlice = llvm.ConstInsertValue(methodsSlice, len_, []uint32{2})
	uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, methodsSlice, []uint32{2})
	return uncommonTypeInit
}
Beispiel #23
0
func (tm *TypeMap) nameRuntimeType(n *types.Name) (global, ptr llvm.Value) {
	pkgpath := tm.pkgmap[n.Obj]
	if pkgpath == "" {
		// XXX "builtin"?
		pkgpath = "runtime"
	}
	globalname := "__llgo.type.name." + pkgpath + "." + n.Obj.Name
	if pkgpath != tm.pkgpath {
		// We're not compiling the package from whence the type came,
		// so we'll just create a pointer to it here.
		global := llvm.AddGlobal(tm.module, tm.runtimeType, globalname)
		global.SetInitializer(llvm.ConstNull(tm.runtimeType))
		global.SetLinkage(llvm.CommonLinkage)
		return global, global
	}

	underlying := n.Underlying
	if name, ok := underlying.(*types.Name); ok {
		underlying = name.Underlying
	}

	global, ptr = tm.makeRuntimeType(underlying)
	globalInit := global.Initializer()

	// Locate the common type.
	underlyingRuntimeType := llvm.ConstExtractValue(globalInit, []uint32{1})
	commonType := underlyingRuntimeType
	if underlyingRuntimeType.Type() != tm.runtimeCommonType {
		commonType = llvm.ConstExtractValue(commonType, []uint32{0})
	}

	// Insert the uncommon type.
	uncommonTypeInit := llvm.ConstNull(tm.runtimeUncommonType)
	namePtr := tm.globalStringPtr(n.Obj.Name)
	uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, namePtr, []uint32{0})
	pkgpathPtr := tm.globalStringPtr(pkgpath)
	uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, pkgpathPtr, []uint32{1})

	// Replace the commonType's string representation.
	commonType = llvm.ConstInsertValue(commonType, namePtr, []uint32{8})

	methods := make([]llvm.Value, len(n.Methods))
	for index, m := range n.Methods {
		method := llvm.ConstNull(tm.runtimeMethod)
		name := tm.globalStringPtr(m.Name)
		name = llvm.ConstBitCast(name, tm.runtimeMethod.StructElementTypes()[0])
		// name
		method = llvm.ConstInsertValue(method, name, []uint32{0})
		// pkgPath
		method = llvm.ConstInsertValue(method, pkgpathPtr, []uint32{1})
		// mtyp (method type, no receiver)
		ftyp := m.Type.(*types.Func)
		{
			recv := ftyp.Recv
			ftyp.Recv = nil
			mtyp := tm.ToRuntime(ftyp)
			method = llvm.ConstInsertValue(method, mtyp, []uint32{2})
			ftyp.Recv = recv
		}
		// typ (function type, with receiver)
		typ := tm.ToRuntime(ftyp)
		method = llvm.ConstInsertValue(method, typ, []uint32{3})
		// ifn (single-word receiver function pointer for interface calls)
		ifn := tm.resolver.Resolve(m).LLVMValue() // TODO generate trampoline as necessary.
		ifn = llvm.ConstPtrToInt(ifn, tm.target.IntPtrType())
		method = llvm.ConstInsertValue(method, ifn, []uint32{4})
		// tfn (standard method/function pointer for plain method calls)
		tfn := tm.resolver.Resolve(m).LLVMValue()
		tfn = llvm.ConstPtrToInt(tfn, tm.target.IntPtrType())
		method = llvm.ConstInsertValue(method, tfn, []uint32{5})
		methods[index] = method
	}

	var methodsGlobalPtr llvm.Value
	if len(methods) > 0 {
		methodsArray := llvm.ConstArray(tm.runtimeMethod, methods)
		methodsGlobalPtr = llvm.AddGlobal(tm.module, methodsArray.Type(), "")
		methodsGlobalPtr.SetInitializer(methodsArray)
		i32zero := llvm.ConstNull(llvm.Int32Type())
		methodsGlobalPtr = llvm.ConstGEP(methodsGlobalPtr, []llvm.Value{i32zero, i32zero})
	} else {
		methodsGlobalPtr = llvm.ConstNull(llvm.PointerType(tm.runtimeMethod, 0))
	}
	len_ := llvm.ConstInt(llvm.Int32Type(), uint64(len(methods)), false)
	methodsSliceType := tm.runtimeUncommonType.StructElementTypes()[2]
	methodsSlice := llvm.ConstNull(methodsSliceType)
	methodsSlice = llvm.ConstInsertValue(methodsSlice, methodsGlobalPtr, []uint32{0})
	methodsSlice = llvm.ConstInsertValue(methodsSlice, len_, []uint32{1})
	methodsSlice = llvm.ConstInsertValue(methodsSlice, len_, []uint32{2})
	uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, methodsSlice, []uint32{2})

	uncommonType := llvm.AddGlobal(tm.module, uncommonTypeInit.Type(), "")
	uncommonType.SetInitializer(uncommonTypeInit)
	commonType = llvm.ConstInsertValue(commonType, uncommonType, []uint32{9})

	// Update the global's initialiser. Note that we take a copy
	// of the underlying type; we're not updating a shared type.
	if underlyingRuntimeType.Type() != tm.runtimeCommonType {
		underlyingRuntimeType = llvm.ConstInsertValue(underlyingRuntimeType, commonType, []uint32{0})
	} else {
		underlyingRuntimeType = commonType
	}
	globalInit = llvm.ConstInsertValue(globalInit, underlyingRuntimeType, []uint32{1})
	global.SetName(globalname)
	global.SetInitializer(globalInit)
	return global, ptr
}
Beispiel #24
0
Datei: ssa.go Projekt: pcc/llgo
func (fr *frame) value(v ssa.Value) (result *LLVMValue) {
	switch v := v.(type) {
	case nil:
		return nil
	case *ssa.Function:
		result, ok := fr.funcvals[v]
		if ok {
			return result
		}
		// fr.globals[v] has the function in raw pointer form;
		// we must convert it to <f,ctx> form. If the function
		// does not have a receiver, then create a wrapper
		// function that has an additional "context" parameter.
		f := fr.resolveFunction(v)
		if v.Signature.Recv() == nil && len(v.FreeVars) == 0 {
			f = contextFunction(fr.compiler, f)
		}
		pair := llvm.ConstNull(fr.llvmtypes.ToLLVM(f.Type()))
		fnptr := llvm.ConstBitCast(f.LLVMValue(), pair.Type().StructElementTypes()[0])
		pair = llvm.ConstInsertValue(pair, fnptr, []uint32{0})
		result = fr.NewValue(pair, f.Type())
		fr.funcvals[v] = result
		return result
	case *ssa.Const:
		return fr.NewConstValue(v.Value, v.Type())
	case *ssa.Global:
		if g, ok := fr.globals[v]; ok {
			return g
		}
		// Create an external global. Globals for this package are defined
		// on entry to translatePackage, and have initialisers.
		llelemtyp := fr.llvmtypes.ToLLVM(deref(v.Type()))
		llglobal := llvm.AddGlobal(fr.module.Module, llelemtyp, v.String())
		global := fr.NewValue(llglobal, v.Type())
		fr.globals[v] = global
		return global
	}
	if value, ok := fr.env[v]; ok {
		return value
	}

	// Instructions are not necessarily visited before they are used (e.g. Phi
	// edges) so we must "backpatch": create a value with the resultant type,
	// and then replace it when we visit the instruction.
	if b, ok := fr.backpatch[v]; ok {
		return b
	}
	if fr.backpatch == nil {
		fr.backpatch = make(map[ssa.Value]*LLVMValue)
	}
	// Note: we must not create a constant here (e.g. Undef/ConstNull), as
	// it is not permissible to replace a constant with a non-constant.
	// We must create the value in its own standalone basic block, so we can
	// dispose of it after replacing.
	currBlock := fr.builder.GetInsertBlock()
	fr.builder.SetInsertPointAtEnd(llvm.AddBasicBlock(currBlock.Parent(), ""))
	placeholder := fr.compiler.builder.CreatePHI(fr.llvmtypes.ToLLVM(v.Type()), "")
	fr.builder.SetInsertPointAtEnd(currBlock)
	value := fr.NewValue(placeholder, v.Type())
	fr.backpatch[v] = value
	return value
}
Beispiel #25
0
func (tm *TypeMap) uncommonType(n *types.Name, ptr bool) llvm.Value {
	uncommonTypeInit := llvm.ConstNull(tm.runtimeUncommonType)
	namePtr := tm.globalStringPtr(n.Obj.Name)
	uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, namePtr, []uint32{0})
	var pkgpathPtr llvm.Value
	if n.Package != "" {
		pkgpathPtr = tm.globalStringPtr(n.Package)
		uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, pkgpathPtr, []uint32{1})
	}

	// Store methods.
	methods := make([]llvm.Value, 0, len(n.Methods))
	for _, m := range n.Methods {
		ftyp := m.Type.(*types.Func)
		ptrrecv := !types.Identical(ftyp.Recv.Type.(types.Type), n)
		if !ptr && ptrrecv {
			// For a type T, we only store methods where the
			// receiver is T and not *T. For *T we store both.
			continue
		}

		method := llvm.ConstNull(tm.runtimeMethod)
		name := tm.globalStringPtr(m.Name)
		name = llvm.ConstBitCast(name, tm.runtimeMethod.StructElementTypes()[0])
		// name
		method = llvm.ConstInsertValue(method, name, []uint32{0})
		// pkgPath
		method = llvm.ConstInsertValue(method, pkgpathPtr, []uint32{1})
		// mtyp (method type, no receiver)
		{
			recv := ftyp.Recv
			ftyp.Recv = nil
			mtyp := tm.ToRuntime(ftyp)
			method = llvm.ConstInsertValue(method, mtyp, []uint32{2})
			ftyp.Recv = recv
		}
		// typ (function type, with receiver)
		typ := tm.ToRuntime(ftyp)
		method = llvm.ConstInsertValue(method, typ, []uint32{3})

		// tfn (standard method/function pointer for plain method calls)
		tfn := tm.resolver.Resolve(m).LLVMValue()
		tfn = llvm.ConstPtrToInt(tfn, tm.target.IntPtrType())

		// ifn (single-word receiver function pointer for interface calls)
		ifn := tfn
		needload := ptr && !ptrrecv
		if !needload {
			recvtyp := tm.ToLLVM(ftyp.Recv.Type.(types.Type))
			needload = int(tm.target.TypeAllocSize(recvtyp)) > tm.target.PointerSize()
		}
		if needload {
			// If the receiver type is wider than a word, we
			// need to use an intermediate function which takes
			// a pointer-receiver, loads it, and then calls the
			// standard receiver function.
			fname := fmt.Sprintf("*%s.%s", ftyp.Recv.Type, m.Name)
			ifn = tm.module.NamedFunction(fname)
			ifn = llvm.ConstPtrToInt(ifn, tm.target.IntPtrType())
		}

		method = llvm.ConstInsertValue(method, ifn, []uint32{4})
		method = llvm.ConstInsertValue(method, tfn, []uint32{5})
		methods = append(methods, method)
	}

	var methodsGlobalPtr llvm.Value
	if len(methods) > 0 {
		methodsArray := llvm.ConstArray(tm.runtimeMethod, methods)
		methodsGlobalPtr = llvm.AddGlobal(tm.module, methodsArray.Type(), "")
		methodsGlobalPtr.SetInitializer(methodsArray)
		i32zero := llvm.ConstNull(llvm.Int32Type())
		methodsGlobalPtr = llvm.ConstGEP(methodsGlobalPtr, []llvm.Value{i32zero, i32zero})
	} else {
		methodsGlobalPtr = llvm.ConstNull(llvm.PointerType(tm.runtimeMethod, 0))
	}
	len_ := llvm.ConstInt(llvm.Int32Type(), uint64(len(methods)), false)
	methodsSliceType := tm.runtimeUncommonType.StructElementTypes()[2]
	methodsSlice := llvm.ConstNull(methodsSliceType)
	methodsSlice = llvm.ConstInsertValue(methodsSlice, methodsGlobalPtr, []uint32{0})
	methodsSlice = llvm.ConstInsertValue(methodsSlice, len_, []uint32{1})
	methodsSlice = llvm.ConstInsertValue(methodsSlice, len_, []uint32{2})
	uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, methodsSlice, []uint32{2})
	return uncommonTypeInit
}
Beispiel #26
0
func (compiler *compiler) Compile(fset *token.FileSet, files []*ast.File, importpath string) (m *Module, err error) {
	// FIXME create a compilation state, rather than storing in 'compiler'.
	compiler.fileset = fset
	compiler.initfuncs = nil
	compiler.varinitfuncs = nil

	// If no import path is specified, or the package's
	// name (not path) is "main", then set the import
	// path to be the same as the package's name.
	if importpath == "" || files[0].Name.String() == "main" {
		importpath = files[0].Name.String()
	}

	// Type-check, and store object data.
	compiler.typeinfo.Types = make(map[ast.Expr]types.Type)
	compiler.typeinfo.Values = make(map[ast.Expr]exact.Value)
	compiler.typeinfo.Objects = make(map[*ast.Ident]types.Object)
	compiler.typeinfo.Implicits = make(map[ast.Node]types.Object)
	compiler.typeinfo.Selections = make(map[*ast.SelectorExpr]*types.Selection)
	compiler.objectdata = make(map[types.Object]*ObjectData)
	compiler.methodsets = make(map[types.Type]*methodset)
	compiler.exportedtypes = nil
	compiler.llvmtypes = NewLLVMTypeMap(compiler.target)
	pkg, err := compiler.typecheck(importpath, fset, files)
	if err != nil {
		return nil, err
	}
	compiler.pkg = pkg

	// 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 := importpath
	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)
		}
	}()

	// 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, compiler.FunctionCache, resolver)

	// Create a Builder, for building LLVM instructions.
	compiler.builder = newBuilder(compiler.types)
	defer compiler.builder.Dispose()

	compiler.debug_info = &llvm.DebugInfo{}
	// Compile each file in the package.
	for _, file := range files {
		compiler.compile_unit = &llvm.CompileUnitDescriptor{
			Language: llvm.DW_LANG_Go,
			Path:     llvm.FileDescriptor(fset.File(file.Pos()).Name()),
			Producer: LLGOProducer,
			Runtime:  LLGORuntimeVersion,
		}
		compiler.pushDebugContext(&compiler.compile_unit.Path)

		for _, decl := range file.Decls {
			compiler.VisitDecl(decl)
		}
		compiler.popDebugContext()
		if len(compiler.debug_context) > 0 {
			log.Panicln(compiler.debug_context)
		}
		compiler.module.AddNamedMetadataOperand("llvm.dbg.cu", compiler.debug_info.MDNode(compiler.compile_unit))
	}

	// Export runtime type information.
	compiler.exportRuntimeTypes()

	// Wrap "main.main" in a call to runtime.main.
	if importpath == "main" {
		err = compiler.createMainFunction()
		if err != nil {
			return nil, err
		}
	} else {
		var e = exporter{compiler: compiler}
		if err := e.Export(pkg); err != nil {
			return nil, err
		}
	}

	// Create global constructors. The initfuncs/varinitfuncs
	// slices are in the order of visitation; we generate the
	// list of constructors in the reverse order.
	//
	// The llgo linker will link modules in the order of
	// package dependency, i.e. if A requires B, then llgo-link
	// will link the modules in the order A, B. The "runtime"
	// package is always last.
	//
	// At program initialisation, the runtime initialisation
	// function (runtime.main) will invoke the constructors
	// in reverse order.
	var initfuncs [][]llvm.Value
	if compiler.varinitfuncs != nil {
		initfuncs = append(initfuncs, compiler.varinitfuncs)
	}
	if compiler.initfuncs != nil {
		initfuncs = append(initfuncs, compiler.initfuncs)
	}
	if initfuncs != nil {
		ctortype := llvm.PointerType(llvm.Int8Type(), 0)
		var ctors []llvm.Value
		var index int = 0
		for _, initfuncs := range initfuncs {
			for _, fnptr := range initfuncs {
				name := fmt.Sprintf("__llgo.ctor.%s.%d", importpath, index)
				fnptr.SetName(name)
				fnptr = llvm.ConstBitCast(fnptr, ctortype)
				ctors = append(ctors, fnptr)
				index++
			}
		}
		for i, n := 0, len(ctors); i < n/2; i++ {
			ctors[i], ctors[n-i-1] = ctors[n-i-1], ctors[i]
		}
		ctorsInit := llvm.ConstArray(ctortype, ctors)
		ctorsVar := llvm.AddGlobal(compiler.module.Module, ctorsInit.Type(), "runtime.ctors")
		ctorsVar.SetInitializer(ctorsInit)
		ctorsVar.SetLinkage(llvm.AppendingLinkage)
	}

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

	return compiler.module, nil
}
Beispiel #27
0
// p != nil iff we're generatig the uncommonType for a pointer type.
func (tm *TypeMap) uncommonType(n *types.Named, p *types.Pointer) llvm.Value {
	uncommonTypeInit := llvm.ConstNull(tm.runtime.uncommonType.llvm)
	namePtr := tm.globalStringPtr(n.Obj().Name())
	uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, namePtr, []uint32{0})
	var path string
	if pkg := n.Obj().Pkg(); pkg != nil {
		path = pkg.Path()
	}
	pkgpathPtr := tm.globalStringPtr(path)
	uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, pkgpathPtr, []uint32{1})

	// If we're dealing with an interface, stop now;
	// we store interface methods on the interface
	// type.
	if _, ok := n.Underlying().(*types.Interface); ok {
		return uncommonTypeInit
	}

	var methodset, pmethodset *types.MethodSet
	if p != nil {
		methodset = tm.MethodSet(p)
	} else {
		methodset = tm.MethodSet(n)
	}

	// Store methods. All methods must be stored, not only exported ones;
	// this is to allow satisfying of interfaces with non-exported methods.
	methods := make([]llvm.Value, methodset.Len())
	for i := range methods {
		sel := methodset.At(i)
		mname := sel.Obj().Name()
		mfunc := tm.methodResolver.ResolveMethod(sel)
		ftyp := mfunc.Type().(*types.Signature)

		method := llvm.ConstNull(tm.runtime.method.llvm)
		name := tm.globalStringPtr(mname)
		name = llvm.ConstBitCast(name, tm.runtime.method.llvm.StructElementTypes()[0])
		// name
		method = llvm.ConstInsertValue(method, name, []uint32{0})
		// pkgPath
		method = llvm.ConstInsertValue(method, pkgpathPtr, []uint32{1})
		// mtyp (method type, no receiver)
		{
			ftyp := types.NewSignature(nil, nil, ftyp.Params(), ftyp.Results(), ftyp.Variadic())
			mtyp := tm.ToRuntime(ftyp)
			method = llvm.ConstInsertValue(method, mtyp, []uint32{2})
		}
		// typ (function type, with receiver)
		typ := tm.ToRuntime(ftyp)
		method = llvm.ConstInsertValue(method, typ, []uint32{3})

		// tfn (standard method/function pointer for plain method calls)
		tfn := llvm.ConstPtrToInt(mfunc.LLVMValue(), tm.target.IntPtrType())

		// ifn (single-word receiver function pointer for interface calls)
		ifn := tfn
		if p == nil {
			if tm.Sizeof(n) > int64(tm.target.PointerSize()) {
				if pmethodset == nil {
					pmethodset = tm.MethodSet(types.NewPointer(n))
				}
				pmfunc := tm.methodResolver.ResolveMethod(pmethodset.Lookup(sel.Obj().Pkg(), mname))
				ifn = llvm.ConstPtrToInt(pmfunc.LLVMValue(), tm.target.IntPtrType())
			} else if _, ok := n.Underlying().(*types.Pointer); !ok {
				// Create a wrapper function that takes an *int8,
				// and coerces to the receiver type.
				ifn = tm.interfaceFuncWrapper(mfunc.LLVMValue())
				ifn = llvm.ConstPtrToInt(ifn, tm.target.IntPtrType())
			}
		}

		method = llvm.ConstInsertValue(method, ifn, []uint32{4})
		method = llvm.ConstInsertValue(method, tfn, []uint32{5})
		methods[i] = method
	}
	methodsSliceType := tm.runtime.uncommonType.llvm.StructElementTypes()[2]
	methodsSlice := tm.makeSlice(methods, methodsSliceType)
	uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, methodsSlice, []uint32{2})
	return uncommonTypeInit
}
Beispiel #28
0
func (c *compiler) NewConstValue(v exact.Value, typ types.Type) *LLVMValue {
	switch {
	case v.Kind() == exact.Unknown:
		// TODO nil literals should be represented more appropriately once the exact-package supports it.
		llvmtyp := c.types.ToLLVM(typ)
		return c.NewValue(llvm.ConstNull(llvmtyp), typ)

	case isString(typ):
		if isUntyped(typ) {
			typ = types.Typ[types.String]
		}
		llvmtyp := c.types.ToLLVM(typ)
		strval := exact.StringVal(v)
		strlen := len(strval)
		i8ptr := llvm.PointerType(llvm.Int8Type(), 0)
		var ptr llvm.Value
		if strlen > 0 {
			init := llvm.ConstString(strval, false)
			ptr = llvm.AddGlobal(c.module.Module, init.Type(), "")
			ptr.SetInitializer(init)
			ptr = llvm.ConstBitCast(ptr, i8ptr)
		} else {
			ptr = llvm.ConstNull(i8ptr)
		}
		len_ := llvm.ConstInt(c.types.inttype, uint64(strlen), false)
		llvmvalue := llvm.Undef(llvmtyp)
		llvmvalue = llvm.ConstInsertValue(llvmvalue, ptr, []uint32{0})
		llvmvalue = llvm.ConstInsertValue(llvmvalue, len_, []uint32{1})
		return c.NewValue(llvmvalue, typ)

	case isInteger(typ):
		if isUntyped(typ) {
			typ = types.Typ[types.Int]
		}
		llvmtyp := c.types.ToLLVM(typ)
		var llvmvalue llvm.Value
		if isUnsigned(typ) {
			v, _ := exact.Uint64Val(v)
			llvmvalue = llvm.ConstInt(llvmtyp, v, false)
		} else {
			v, _ := exact.Int64Val(v)
			llvmvalue = llvm.ConstInt(llvmtyp, uint64(v), true)
		}
		return c.NewValue(llvmvalue, typ)

	case isBoolean(typ):
		if isUntyped(typ) {
			typ = types.Typ[types.Bool]
		}
		var llvmvalue llvm.Value
		if exact.BoolVal(v) {
			llvmvalue = llvm.ConstAllOnes(llvm.Int1Type())
		} else {
			llvmvalue = llvm.ConstNull(llvm.Int1Type())
		}
		return c.NewValue(llvmvalue, typ)

	case isFloat(typ):
		if isUntyped(typ) {
			typ = types.Typ[types.Float64]
		}
		llvmtyp := c.types.ToLLVM(typ)
		floatval, _ := exact.Float64Val(v)
		llvmvalue := llvm.ConstFloat(llvmtyp, floatval)
		return c.NewValue(llvmvalue, typ)

	case typ == types.Typ[types.UnsafePointer]:
		llvmtyp := c.types.ToLLVM(typ)
		v, _ := exact.Uint64Val(v)
		llvmvalue := llvm.ConstInt(llvmtyp, v, false)
		return c.NewValue(llvmvalue, typ)

	case isComplex(typ):
		if isUntyped(typ) {
			typ = types.Typ[types.Complex128]
		}
		llvmtyp := c.types.ToLLVM(typ)
		floattyp := llvmtyp.StructElementTypes()[0]
		llvmvalue := llvm.ConstNull(llvmtyp)
		realv := exact.Real(v)
		imagv := exact.Imag(v)
		realfloatval, _ := exact.Float64Val(realv)
		imagfloatval, _ := exact.Float64Val(imagv)
		llvmre := llvm.ConstFloat(floattyp, realfloatval)
		llvmim := llvm.ConstFloat(floattyp, imagfloatval)
		llvmvalue = llvm.ConstInsertValue(llvmvalue, llvmre, []uint32{0})
		llvmvalue = llvm.ConstInsertValue(llvmvalue, llvmim, []uint32{1})
		return c.NewValue(llvmvalue, typ)
	}

	// Special case for string -> [](byte|rune)
	if u, ok := typ.Underlying().(*types.Slice); ok && isInteger(u.Elem()) {
		if v.Kind() == exact.String {
			strval := c.NewConstValue(v, types.Typ[types.String])
			return strval.Convert(typ).(*LLVMValue)
		}
	}

	panic(fmt.Sprintf("unhandled: t=%s(%T), v=%v(%T)", c.types.TypeString(typ), typ, v, v))
}
Beispiel #29
0
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
}