Beispiel #1
0
// makeMapLiteral makes a map with the specified keys and values.
func (c *compiler) makeMapLiteral(typ types.Type, keys, values []Value) *LLVMValue {
	var count, keysptr, valuesptr llvm.Value
	dyntyp := c.types.ToRuntime(typ)
	dyntyp = c.builder.CreatePtrToInt(dyntyp, c.target.IntPtrType(), "")
	if len(keys) == 0 {
		count = llvm.ConstNull(c.types.inttype)
		keysptr = llvm.ConstNull(c.target.IntPtrType())
		valuesptr = keysptr
	} else {
		maptyp := typ.Underlying().(*types.Map)
		keytyp := maptyp.Key()
		valtyp := maptyp.Elem()
		count = llvm.ConstInt(c.types.inttype, uint64(len(keys)), false)
		keysptr = c.builder.CreateArrayAlloca(c.types.ToLLVM(keytyp), count, "")
		valuesptr = c.builder.CreateArrayAlloca(c.types.ToLLVM(valtyp), count, "")
		for i := range keys {
			gepindices := []llvm.Value{llvm.ConstInt(c.types.inttype, uint64(i), false)}
			key := keys[i].Convert(keytyp).LLVMValue()
			ptr := c.builder.CreateGEP(keysptr, gepindices, "")
			c.builder.CreateStore(key, ptr)
			value := values[i].Convert(valtyp).LLVMValue()
			ptr = c.builder.CreateGEP(valuesptr, gepindices, "")
			c.builder.CreateStore(value, ptr)
		}
		keysptr = c.builder.CreatePtrToInt(keysptr, c.target.IntPtrType(), "")
		valuesptr = c.builder.CreatePtrToInt(valuesptr, c.target.IntPtrType(), "")
	}
	f := c.NamedFunction("runtime.makemap", "func(t uintptr, n int, keys, values uintptr) uintptr")
	mapval := c.builder.CreateCall(f, []llvm.Value{dyntyp, count, keysptr, valuesptr}, "")
	return c.NewValue(mapval, typ)
}
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) 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)
}
Beispiel #5
0
// mapLookup searches a map for a specified key, returning a pointer to the
// memory location for the value. If insert is given as true, and the key
// does not exist in the map, it will be added with an uninitialised value.
func (c *compiler) mapLookup(m *LLVMValue, key Value, insert bool) (elem *LLVMValue, notnull *LLVMValue) {
	mapType := m.Type().Underlying().(*types.Map)
	maplookup := c.NamedFunction("runtime.maplookup", "func f(t, m, k uintptr, insert bool) uintptr")
	ptrType := c.target.IntPtrType()
	args := make([]llvm.Value, 4)
	args[0] = llvm.ConstPtrToInt(c.types.ToRuntime(mapType), ptrType)
	args[1] = c.builder.CreatePtrToInt(m.LLVMValue(), ptrType, "")
	if insert {
		args[3] = llvm.ConstAllOnes(llvm.Int1Type())
	} else {
		args[3] = llvm.ConstNull(llvm.Int1Type())
	}

	if lv, islv := key.(*LLVMValue); islv && lv.pointer != nil {
		args[2] = c.builder.CreatePtrToInt(lv.pointer.LLVMValue(), ptrType, "")
	}
	if args[2].IsNil() {
		stackval := c.builder.CreateAlloca(c.types.ToLLVM(key.Type()), "")
		c.builder.CreateStore(key.LLVMValue(), stackval)
		args[2] = c.builder.CreatePtrToInt(stackval, ptrType, "")
	}

	eltPtrType := types.NewPointer(mapType.Elem())
	llvmtyp := c.types.ToLLVM(eltPtrType)
	zeroglobal := llvm.AddGlobal(c.module.Module, llvmtyp.ElementType(), "")
	zeroglobal.SetInitializer(llvm.ConstNull(llvmtyp.ElementType()))
	result := c.builder.CreateCall(maplookup, args, "")
	result = c.builder.CreateIntToPtr(result, llvmtyp, "")
	notnull_ := c.builder.CreateIsNotNull(result, "")
	result = c.builder.CreateSelect(notnull_, result, zeroglobal, "")
	value := c.NewValue(result, eltPtrType)
	return value.makePointee(), c.NewValue(notnull_, types.Typ[types.Bool])
}
Beispiel #6
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 #7
0
// convertI2V converts an interface to a value.
func (v *LLVMValue) convertI2V(typ types.Type) (result, success Value) {
	builder := v.compiler.builder
	predicate := v.interfaceTypeEquals(typ).LLVMValue()

	// 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.NewValue(successValue, types.Typ[types.Bool])

	resultValues := []llvm.Value{matchResultValue, nonmatchResultValue}
	resultBlocks := []llvm.BasicBlock{match, nonmatch}
	resultValue.AddIncoming(resultValues, resultBlocks)
	result = v.compiler.NewValue(resultValue, typ)
	return result, success
}
Beispiel #8
0
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)
}
Beispiel #9
0
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)
}
Beispiel #10
0
func (d *LocalVariableDescriptor) mdNode(info *DebugInfo) llvm.Value {
	return llvm.MDNode([]llvm.Value{
		llvm.ConstInt(llvm.Int32Type(), uint64(d.Tag())+llvm.LLVMDebugVersion, false),
		info.MDNode(d.Context),
		llvm.MDString(d.Name),
		info.mdFileNode(d.File),
		llvm.ConstInt(llvm.Int32Type(), uint64(d.Line)|(uint64(d.Argument)<<24), false),
		info.MDNode(d.Type),
		llvm.ConstNull(llvm.Int32Type()), // flags
		llvm.ConstNull(llvm.Int32Type()), // optional reference to inline location
	})
}
Beispiel #11
0
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)
}
Beispiel #12
0
func (tm *TypeMap) pointerRuntimeType(p *types.Pointer) (global, ptr llvm.Value) {
	// Is the base type a named type from another package? If so, we'll
	// create a reference to the externally defined symbol.
	var globalname string
	if n, ok := p.Base.(*types.Name); ok {
		pkgpath := n.Package
		if pkgpath == "" {
			pkgpath = "runtime"
		}
		globalname = "__llgo.type.*" + n.String()
		if pkgpath != tm.pkgpath {
			global := llvm.AddGlobal(tm.module, tm.runtimeType, globalname)
			global.SetInitializer(llvm.ConstNull(tm.runtimeType))
			global.SetLinkage(llvm.CommonLinkage)
			return global, global
		}
	}

	commonType := tm.makeCommonType(p, reflect.Ptr)
	if n, ok := p.Base.(*types.Name); ok {
		uncommonTypeInit := tm.uncommonType(n, true)
		uncommonType := llvm.AddGlobal(tm.module, uncommonTypeInit.Type(), "")
		uncommonType.SetInitializer(uncommonTypeInit)
		commonType = llvm.ConstInsertValue(commonType, uncommonType, []uint32{9})
	}

	baseTypeGlobal, baseTypePtr := tm.toRuntime(p.Base)
	ptrType := llvm.ConstNull(tm.runtimePtrType)
	ptrType = llvm.ConstInsertValue(ptrType, commonType, []uint32{0})
	ptrType = llvm.ConstInsertValue(ptrType, baseTypePtr, []uint32{1})
	global, ptr = tm.makeRuntimeTypeGlobal(ptrType)
	global.SetName(globalname)

	// Set ptrToThis in the base type's commonType.
	baseRuntimeType := baseTypeGlobal.Initializer()
	baseType := llvm.ConstExtractValue(baseRuntimeType, []uint32{1})
	if baseType.Type() == tm.runtimeCommonType {
		baseType = llvm.ConstInsertValue(baseType, ptr, []uint32{10})
	} else {
		commonType := llvm.ConstExtractValue(baseType, []uint32{0})
		commonType = llvm.ConstInsertValue(commonType, ptr, []uint32{10})
		baseType = llvm.ConstInsertValue(baseType, commonType, []uint32{0})
	}
	baseRuntimeType = llvm.ConstInsertValue(baseRuntimeType, baseType, []uint32{1})
	baseTypeGlobal.SetInitializer(baseRuntimeType)

	return global, ptr
}
Beispiel #13
0
func (c *compiler) makeInterface(v *LLVMValue, iface types.Type) *LLVMValue {
	llv := v.LLVMValue()
	lltyp := llv.Type()
	i8ptr := llvm.PointerType(llvm.Int8Type(), 0)
	if lltyp.TypeKind() == llvm.PointerTypeKind {
		llv = c.builder.CreateBitCast(llv, i8ptr, "")
	} else {
		// If the value fits exactly in a pointer, then we can just
		// bitcast it. Otherwise we need to malloc.
		if c.target.TypeStoreSize(lltyp) <= uint64(c.target.PointerSize()) {
			bits := c.target.TypeSizeInBits(lltyp)
			if bits > 0 {
				llv = coerce(c.builder, llv, llvm.IntType(int(bits)))
				llv = c.builder.CreateIntToPtr(llv, i8ptr, "")
			} else {
				llv = llvm.ConstNull(i8ptr)
			}
		} else {
			ptr := c.createTypeMalloc(lltyp)
			c.builder.CreateStore(llv, ptr)
			llv = c.builder.CreateBitCast(ptr, i8ptr, "")
		}
	}
	value := llvm.Undef(c.types.ToLLVM(iface))
	rtype := c.types.ToRuntime(v.Type())
	rtype = c.builder.CreateBitCast(rtype, llvm.PointerType(llvm.Int8Type(), 0), "")
	value = c.builder.CreateInsertValue(value, rtype, 0, "")
	value = c.builder.CreateInsertValue(value, llv, 1, "")
	if iface.Underlying().(*types.Interface).NumMethods() > 0 {
		result := c.NewValue(value, types.NewInterface(nil, nil))
		result, _ = result.convertE2I(iface)
		return result
	}
	return c.NewValue(value, iface)
}
Beispiel #14
0
func (c *compiler) compareStrings(lhs, rhs *LLVMValue, op token.Token) *LLVMValue {
	strcmp := c.NamedFunction("runtime.strcmp", "func(a, b _string) int32")
	_string := strcmp.Type().ElementType().ParamTypes()[0]
	lhsstr := c.coerceString(lhs.LLVMValue(), _string)
	rhsstr := c.coerceString(rhs.LLVMValue(), _string)
	args := []llvm.Value{lhsstr, rhsstr}
	result := c.builder.CreateCall(strcmp, args, "")
	zero := llvm.ConstNull(llvm.Int32Type())
	var pred llvm.IntPredicate
	switch op {
	case token.EQL:
		pred = llvm.IntEQ
	case token.LSS:
		pred = llvm.IntSLT
	case token.GTR:
		pred = llvm.IntSGT
	case token.LEQ:
		pred = llvm.IntSLE
	case token.GEQ:
		pred = llvm.IntSGE
	case token.NEQ:
		panic("NEQ is handled in LLVMValue.BinaryOp")
	default:
		panic("unreachable")
	}
	result = c.builder.CreateICmp(pred, result, zero, "")
	return c.NewValue(result, types.Typ[types.Bool])
}
Beispiel #15
0
// makeSlice allocates a new slice with the optional length and capacity,
// initialising its contents to their zero values.
func (c *compiler) makeSlice(elttyp types.Type, length, capacity Value) llvm.Value {
	var lengthValue llvm.Value
	if length != nil {
		lengthValue = length.Convert(types.Int32).LLVMValue()
	} else {
		lengthValue = llvm.ConstNull(llvm.Int32Type())
	}

	// TODO check capacity >= length
	capacityValue := lengthValue
	if capacity != nil {
		capacityValue = capacity.Convert(types.Int32).LLVMValue()
	}

	llvmelttyp := c.types.ToLLVM(elttyp)
	mem := c.builder.CreateArrayMalloc(llvmelttyp, capacityValue, "")
	sizeof := llvm.ConstTrunc(llvm.SizeOf(llvmelttyp), llvm.Int32Type())
	size := c.builder.CreateMul(capacityValue, sizeof, "")
	c.memsetZero(mem, size)

	slicetyp := types.Slice{Elt: elttyp}
	struct_ := llvm.Undef(c.types.ToLLVM(&slicetyp))
	struct_ = c.builder.CreateInsertValue(struct_, mem, 0, "")
	struct_ = c.builder.CreateInsertValue(struct_, lengthValue, 1, "")
	struct_ = c.builder.CreateInsertValue(struct_, capacityValue, 2, "")
	return struct_
}
Beispiel #16
0
func (tm *TypeMap) mapRuntimeType(m *types.Map) (global, ptr llvm.Value) {
	commonType := tm.makeCommonType(m, reflect.Map)
	mapType := llvm.ConstNull(tm.runtimeMapType)
	mapType = llvm.ConstInsertValue(mapType, commonType, []uint32{0})
	// TODO set key, elem
	return tm.makeRuntimeTypeGlobal(mapType)
}
Beispiel #17
0
func (tm *TypeMap) nameRuntimeType(n *types.Name) (global, ptr llvm.Value) {
	global, ptr = tm.makeRuntimeType(n.Underlying)
	globalInit := global.Initializer()

	// Locate the common type.
	underlyingRuntimeType := llvm.ConstExtractValue(globalInit, []uint32{1})
	commonType := underlyingRuntimeType
	if _, ok := n.Underlying.(*types.Basic); !ok {
		commonType = llvm.ConstExtractValue(commonType, []uint32{0})
	}

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

	// Update the global's initialiser.
	if _, ok := n.Underlying.(*types.Basic); !ok {
		underlyingRuntimeType = llvm.ConstInsertValue(underlyingRuntimeType, commonType, []uint32{0})
	} else {
		underlyingRuntimeType = commonType
	}
	globalInit = llvm.ConstInsertValue(globalInit, underlyingRuntimeType, []uint32{1})
	global.SetName("__llgo.reflect." + n.Obj.Name)
	return global, ptr
}
Beispiel #18
0
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)
}
Beispiel #19
0
func (tm *TypeMap) structRuntimeType(s *types.Struct) (global, ptr llvm.Value) {
	commonType := tm.makeCommonType(s, reflect.Struct)
	structType := llvm.ConstNull(tm.runtimeStructType)
	structType = llvm.ConstInsertValue(structType, commonType, []uint32{0})
	// TODO set fields
	return tm.makeRuntimeTypeGlobal(structType)
}
Beispiel #20
0
func (c *compiler) compareStrings(lhs, rhs *LLVMValue, op token.Token) *LLVMValue {
	strcmp := c.module.Module.NamedFunction("runtime.strcmp")
	if strcmp.IsNil() {
		string_type := c.types.ToLLVM(types.String)
		param_types := []llvm.Type{string_type, string_type}
		func_type := llvm.FunctionType(llvm.Int32Type(), param_types, false)
		strcmp = llvm.AddFunction(c.module.Module, "runtime.strcmp", func_type)
	}
	args := []llvm.Value{lhs.LLVMValue(), rhs.LLVMValue()}
	result := c.builder.CreateCall(strcmp, args, "")
	zero := llvm.ConstNull(llvm.Int32Type())
	var pred llvm.IntPredicate
	switch op {
	case token.EQL:
		pred = llvm.IntEQ
	case token.LSS:
		pred = llvm.IntSLT
	case token.GTR:
		pred = llvm.IntSGT
	case token.LEQ:
		pred = llvm.IntSLE
	case token.GEQ:
		pred = llvm.IntSGE
	case token.NEQ:
		panic("NEQ is handled in LLVMValue.BinaryOp")
	default:
		panic("unreachable")
	}
	result = c.builder.CreateICmp(pred, result, zero, "")
	return c.NewLLVMValue(result, types.Bool)
}
Beispiel #21
0
func (tm *TypeMap) pointerRuntimeType(p *types.Pointer) (global, ptr llvm.Value) {
	commonType := tm.makeCommonType(p, reflect.Map)
	ptrType := llvm.ConstNull(tm.runtimePtrType)
	ptrType = llvm.ConstInsertValue(ptrType, commonType, []uint32{0})
	ptrType = llvm.ConstInsertValue(ptrType, tm.ToRuntime(p.Base), []uint32{1})
	return tm.makeRuntimeTypeGlobal(ptrType)
}
Beispiel #22
0
// stringIterNext advances the iterator, and returns the tuple (ok, k, v).
func (c *compiler) stringIterNext(str *LLVMValue, preds []llvm.BasicBlock) *LLVMValue {
	// While Range/Next expresses a mutating operation, we represent them using
	// a Phi node where the first incoming branch (before the loop), and all
	// others take the previous value plus one.
	//
	// See ssa.go for comments on (and assertions of) our assumptions.
	index := c.builder.CreatePHI(c.types.inttype, "index")
	strnext := c.runtime.strnext.LLVMValue()
	args := []llvm.Value{
		c.coerceString(str.LLVMValue(), strnext.Type().ElementType().ParamTypes()[0]),
		index,
	}
	result := c.builder.CreateCall(strnext, args, "")
	nextindex := c.builder.CreateExtractValue(result, 0, "")
	runeval := c.builder.CreateExtractValue(result, 1, "")
	values := make([]llvm.Value, len(preds))
	values[0] = llvm.ConstNull(index.Type())
	for i, _ := range preds[1:] {
		values[i+1] = nextindex
	}
	index.AddIncoming(values, preds)

	// Create an (ok, index, rune) tuple.
	ok := c.builder.CreateIsNotNull(nextindex, "")
	typ := tupleType(types.Typ[types.Bool], types.Typ[types.Int], types.Typ[types.Rune])
	tuple := llvm.Undef(c.types.ToLLVM(typ))
	tuple = c.builder.CreateInsertValue(tuple, ok, 0, "")
	tuple = c.builder.CreateInsertValue(tuple, index, 1, "")
	tuple = c.builder.CreateInsertValue(tuple, runeval, 2, "")
	return c.NewValue(tuple, typ)
}
Beispiel #23
0
func (c *compiler) VisitMake(expr *ast.CallExpr) Value {
	typ := c.typeinfo.Types[expr]
	switch utyp := typ.Underlying().(type) {
	case *types.Slice:
		var length, capacity Value
		switch len(expr.Args) {
		case 3:
			capacity = c.VisitExpr(expr.Args[2])
			fallthrough
		case 2:
			length = c.VisitExpr(expr.Args[1])
		}
		slice := c.makeSlice(utyp.Elem(), length, capacity)
		return c.NewValue(slice, typ)
	case *types.Chan:
		f := c.NamedFunction("runtime.makechan", "func(t uintptr, cap int) uintptr")
		dyntyp := c.types.ToRuntime(typ)
		dyntyp = c.builder.CreatePtrToInt(dyntyp, c.target.IntPtrType(), "")
		var cap_ llvm.Value
		if len(expr.Args) > 1 {
			cap_ = c.VisitExpr(expr.Args[1]).LLVMValue()
		} else {
			cap_ = llvm.ConstNull(c.types.inttype)
		}
		args := []llvm.Value{dyntyp, cap_}
		ptr := c.builder.CreateCall(f, args, "")
		return c.NewValue(ptr, typ)
	case *types.Map:
		return c.makeMapLiteral(typ, nil, nil)
	}
	panic(fmt.Sprintf("unhandled type: %s", typ))
}
Beispiel #24
0
func (v *LLVMValue) UnaryOp(op token.Token) Value {
	b := v.compiler.builder
	switch op {
	case token.SUB:
		var value llvm.Value
		isfp := types.Identical(types.Underlying(v.typ), types.Float32) ||
			types.Identical(types.Underlying(v.typ), types.Float64)
		if isfp {
			zero := llvm.ConstNull(v.compiler.types.ToLLVM(v.Type()))
			value = b.CreateFSub(zero, v.LLVMValue(), "")
		} else {
			value = b.CreateNeg(v.LLVMValue(), "")
		}
		return v.compiler.NewLLVMValue(value, v.typ)
	case token.ADD:
		return v // No-op
	case token.AND:
		return v.pointer
	case token.NOT:
		value := b.CreateNot(v.LLVMValue(), "")
		return v.compiler.NewLLVMValue(value, v.typ)
	case token.XOR:
		lhs := v.LLVMValue()
		rhs := llvm.ConstAllOnes(lhs.Type())
		value := b.CreateXor(lhs, rhs, "")
		return v.compiler.NewLLVMValue(value, v.typ)
	default:
		panic("Unhandled operator: ") // + expr.Op)
	}
	panic("unreachable")
}
Beispiel #25
0
Datei: value.go Projekt: pcc/llgo
func (v *LLVMValue) UnaryOp(op token.Token) Value {
	b := v.compiler.builder
	switch op {
	case token.SUB:
		var value llvm.Value
		if isFloat(v.typ) {
			zero := llvm.ConstNull(v.compiler.types.ToLLVM(v.Type()))
			value = b.CreateFSub(zero, v.LLVMValue(), "")
		} else {
			value = b.CreateNeg(v.LLVMValue(), "")
		}
		return v.compiler.NewValue(value, v.typ)
	case token.ADD:
		return v // No-op
	case token.NOT:
		value := b.CreateNot(v.LLVMValue(), "")
		return v.compiler.NewValue(value, v.typ)
	case token.XOR:
		lhs := v.LLVMValue()
		rhs := llvm.ConstAllOnes(lhs.Type())
		value := b.CreateXor(lhs, rhs, "")
		return v.compiler.NewValue(value, v.typ)
	default:
		panic(fmt.Sprintf("Unhandled operator: %s", op))
	}
	panic("unreachable")
}
Beispiel #26
0
// basicRuntimeType creates the runtime type structure for
// a basic type. If underlying is true, then a new global
// is always created.
func (tm *TypeMap) basicRuntimeType(b *types.Basic, underlying bool) (global, ptr llvm.Value) {
	b = types.Typ[b.Kind()] // unalias
	var name string
	if !underlying {
		name = typeString(b)
		if tm.pkgpath != "runtime" {
			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
		}
	}
	rtype := tm.makeRtype(b, basicReflectKinds[b.Kind()])
	global, ptr = tm.makeRuntimeTypeGlobal(rtype, name)
	global.SetLinkage(llvm.ExternalLinkage)
	if !underlying {
		switch b.Kind() {
		case types.Int32:
			llvm.AddAlias(tm.module, global.Type(), global, typeSymbol("rune"))
		case types.Uint8:
			llvm.AddAlias(tm.module, global.Type(), global, typeSymbol("byte"))
		}
	}
	return global, ptr
}
Beispiel #27
0
// Binary logical operators are handled specially, outside of the Value
// type, because of the need to perform lazy evaluation.
//
// Binary logical operators are implemented using a Phi node, which takes
// on the appropriate value depending on which basic blocks branch to it.
func (c *compiler) compileLogicalOp(op token.Token, lhs Value, rhsFunc func() Value) Value {
	lhsBlock := c.builder.GetInsertBlock()
	resultBlock := llvm.AddBasicBlock(lhsBlock.Parent(), "")
	resultBlock.MoveAfter(lhsBlock)
	rhsBlock := llvm.InsertBasicBlock(resultBlock, "")
	falseBlock := llvm.InsertBasicBlock(resultBlock, "")

	if op == token.LOR {
		c.builder.CreateCondBr(lhs.LLVMValue(), resultBlock, rhsBlock)
	} else {
		c.builder.CreateCondBr(lhs.LLVMValue(), rhsBlock, falseBlock)
	}
	c.builder.SetInsertPointAtEnd(rhsBlock)
	rhs := rhsFunc()
	rhsBlock = c.builder.GetInsertBlock() // rhsFunc may create blocks
	c.builder.CreateCondBr(rhs.LLVMValue(), resultBlock, falseBlock)
	c.builder.SetInsertPointAtEnd(falseBlock)
	c.builder.CreateBr(resultBlock)
	c.builder.SetInsertPointAtEnd(resultBlock)

	result := c.builder.CreatePHI(llvm.Int1Type(), "")
	trueValue := llvm.ConstAllOnes(llvm.Int1Type())
	falseValue := llvm.ConstNull(llvm.Int1Type())
	var values []llvm.Value
	var blocks []llvm.BasicBlock
	if op == token.LOR {
		values = []llvm.Value{trueValue, trueValue, falseValue}
		blocks = []llvm.BasicBlock{lhsBlock, rhsBlock, falseBlock}
	} else {
		values = []llvm.Value{trueValue, falseValue}
		blocks = []llvm.BasicBlock{rhsBlock, falseBlock}
	}
	result.AddIncoming(values, blocks)
	return c.NewLLVMValue(result, types.Bool)
}
Beispiel #28
0
func (lhs *LLVMValue) compareI2V(rhs *LLVMValue) Value {
	c := lhs.compiler
	predicate := lhs.interfaceTypeEquals(rhs.typ).LLVMValue()

	end := llvm.InsertBasicBlock(c.builder.GetInsertBlock(), "end")
	end.MoveAfter(c.builder.GetInsertBlock())
	nonmatch := llvm.InsertBasicBlock(end, "nonmatch")
	match := llvm.InsertBasicBlock(nonmatch, "match")
	c.builder.CreateCondBr(predicate, match, nonmatch)

	c.builder.SetInsertPointAtEnd(match)
	lhsValue := lhs.loadI2V(rhs.typ)
	matchResultValue := lhsValue.BinaryOp(token.EQL, rhs).LLVMValue()
	c.builder.CreateBr(end)

	c.builder.SetInsertPointAtEnd(nonmatch)
	nonmatchResultValue := llvm.ConstNull(llvm.Int1Type())
	c.builder.CreateBr(end)

	c.builder.SetInsertPointAtEnd(end)
	resultValue := c.builder.CreatePHI(matchResultValue.Type(), "")
	resultValues := []llvm.Value{matchResultValue, nonmatchResultValue}
	resultBlocks := []llvm.BasicBlock{match, nonmatch}
	resultValue.AddIncoming(resultValues, resultBlocks)
	return c.NewValue(resultValue, types.Typ[types.Bool])
}
Beispiel #29
0
// makeSlice allocates a new slice with the optional length and capacity,
// initialising its contents to their zero values.
func (c *compiler) makeSlice(elttyp types.Type, length, capacity Value) llvm.Value {
	var lengthValue llvm.Value
	if length != nil {
		lengthValue = length.Convert(types.Typ[types.Int]).LLVMValue()
	} else {
		lengthValue = llvm.ConstNull(c.llvmtypes.inttype)
	}

	// TODO check capacity >= length
	capacityValue := lengthValue
	if capacity != nil {
		capacityValue = capacity.Convert(types.Typ[types.Int]).LLVMValue()
	}

	eltType := c.types.ToLLVM(elttyp)
	sizeof := llvm.ConstTruncOrBitCast(llvm.SizeOf(eltType), c.types.inttype)
	size := c.builder.CreateMul(capacityValue, sizeof, "")
	mem := c.createMalloc(size)
	mem = c.builder.CreateIntToPtr(mem, llvm.PointerType(eltType, 0), "")
	c.memsetZero(mem, size)

	slicetyp := types.NewSlice(elttyp)
	struct_ := llvm.Undef(c.types.ToLLVM(slicetyp))
	struct_ = c.builder.CreateInsertValue(struct_, mem, 0, "")
	struct_ = c.builder.CreateInsertValue(struct_, lengthValue, 1, "")
	struct_ = c.builder.CreateInsertValue(struct_, capacityValue, 2, "")
	return struct_
}
Beispiel #30
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
}