예제 #1
0
파일: interfaces.go 프로젝트: rvedam/llgo
// interfaceMethod returns a function pointer for the specified
// interface and method pair.
func (c *compiler) interfaceMethod(iface *LLVMValue, method *types.Func) *LLVMValue {
	lliface := iface.LLVMValue()
	llitab := c.builder.CreateExtractValue(lliface, 0, "")
	llvalue := c.builder.CreateExtractValue(lliface, 1, "")
	sig := method.Type().(*types.Signature)
	methodset := c.types.MethodSet(sig.Recv().Type())
	// TODO(axw) cache ordered method index
	var index int
	for i := 0; i < methodset.Len(); i++ {
		if methodset.At(i).Obj() == method {
			index = i
			break
		}
	}
	llitab = c.builder.CreateBitCast(llitab, llvm.PointerType(c.runtime.itab.llvm, 0), "")
	llifn := c.builder.CreateGEP(llitab, []llvm.Value{
		llvm.ConstInt(llvm.Int32Type(), 0, false),
		llvm.ConstInt(llvm.Int32Type(), 5, false), // index of itab.fun
	}, "")
	_ = index
	llifn = c.builder.CreateGEP(llifn, []llvm.Value{
		llvm.ConstInt(llvm.Int32Type(), uint64(index), false),
	}, "")
	llifn = c.builder.CreateLoad(llifn, "")
	// Strip receiver.
	sig = types.NewSignature(nil, nil, sig.Params(), sig.Results(), sig.Variadic())
	llfn := llvm.Undef(c.types.ToLLVM(sig))
	llifn = c.builder.CreateIntToPtr(llifn, llfn.Type().StructElementTypes()[0], "")
	llfn = c.builder.CreateInsertValue(llfn, llifn, 0, "")
	llfn = c.builder.CreateInsertValue(llfn, llvalue, 1, "")
	return c.NewValue(llfn, sig)
}
예제 #2
0
파일: descriptors.go 프로젝트: rvedam/llgo
func (d subrangeDescriptor) mdNode(info *DebugInfo) llvm.Value {
	return llvm.MDNode([]llvm.Value{
		llvm.ConstInt(llvm.Int32Type(), uint64(d.Tag())+llvm.LLVMDebugVersion, false),
		llvm.ConstInt(llvm.Int64Type(), uint64(d.low), true),
		llvm.ConstInt(llvm.Int64Type(), uint64(d.high), true),
	})
}
예제 #3
0
파일: debug.go 프로젝트: rvedam/llgo
func (d *debugInfo) setLocation(b llvm.Builder, pos token.Pos) {
	position := d.Fset.Position(pos)
	b.SetCurrentDebugLocation(llvm.MDNode([]llvm.Value{
		llvm.ConstInt(llvm.Int32Type(), uint64(position.Line), true),
		llvm.ConstInt(llvm.Int32Type(), uint64(position.Column), true),
		d.MDNode(d.context()),
		llvm.Value{},
	}))
}
예제 #4
0
파일: descriptors.go 프로젝트: rvedam/llgo
func (d *BlockDescriptor) mdNode(info *DebugInfo) llvm.Value {
	return llvm.MDNode([]llvm.Value{
		llvm.ConstInt(llvm.Int32Type(), uint64(d.Tag())+llvm.LLVMDebugVersion, false),
		info.mdFileNode(d.File),
		info.MDNode(d.Context),
		llvm.ConstInt(llvm.Int32Type(), uint64(d.Line), false),
		llvm.ConstInt(llvm.Int32Type(), uint64(d.Column), false),
		llvm.ConstInt(llvm.Int32Type(), uint64(d.Id), false),
	})
}
예제 #5
0
파일: descriptors.go 프로젝트: rvedam/llgo
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
	})
}
예제 #6
0
파일: descriptors.go 프로젝트: rvedam/llgo
func (d *GlobalVariableDescriptor) mdNode(info *DebugInfo) llvm.Value {
	return llvm.MDNode([]llvm.Value{
		llvm.ConstInt(llvm.Int32Type(), uint64(d.Tag())+llvm.LLVMDebugVersion, false),
		llvm.ConstNull(llvm.Int32Type()),
		info.MDNode(d.Context),
		llvm.MDString(d.Name),
		llvm.MDString(d.DisplayName),
		llvm.MDNode(nil),
		info.mdFileNode(d.File),
		llvm.ConstInt(llvm.Int32Type(), uint64(d.Line), false),
		info.MDNode(d.Type),
		constInt1(d.Local),
		constInt1(!d.External),
		d.Value})
}
예제 #7
0
파일: builtins.go 프로젝트: rvedam/llgo
func (c *compiler) callCap(arg *LLVMValue) *LLVMValue {
	var v llvm.Value
	switch typ := arg.Type().Underlying().(type) {
	case *types.Array:
		v = llvm.ConstInt(c.llvmtypes.inttype, uint64(typ.Len()), false)
	case *types.Pointer:
		atyp := typ.Elem().Underlying().(*types.Array)
		v = llvm.ConstInt(c.llvmtypes.inttype, uint64(atyp.Len()), false)
	case *types.Slice:
		v = c.builder.CreateExtractValue(arg.LLVMValue(), 2, "")
	case *types.Chan:
		f := c.runtime.chancap.LLVMValue()
		v = c.builder.CreateCall(f, []llvm.Value{arg.LLVMValue()}, "")
	}
	return c.NewValue(v, types.Typ[types.Int])
}
예제 #8
0
파일: slice.go 프로젝트: rvedam/llgo
func (c *compiler) slice(x, low, high *LLVMValue) *LLVMValue {
	if low != nil {
		low = low.Convert(types.Typ[types.Int]).(*LLVMValue)
	} else {
		low = c.NewValue(llvm.ConstNull(c.types.inttype), types.Typ[types.Int])
	}

	if high != nil {
		high = high.Convert(types.Typ[types.Int]).(*LLVMValue)
	} else {
		// all bits set is -1
		high = c.NewValue(llvm.ConstAllOnes(c.types.inttype), types.Typ[types.Int])
	}

	switch typ := x.Type().Underlying().(type) {
	case *types.Pointer: // *array
		sliceslice := c.runtime.sliceslice.LLVMValue()
		i8slice := sliceslice.Type().ElementType().ReturnType()
		sliceValue := llvm.Undef(i8slice) // temporary slice
		arraytyp := typ.Elem().Underlying().(*types.Array)
		arrayptr := x.LLVMValue()
		arrayptr = c.builder.CreateBitCast(arrayptr, i8slice.StructElementTypes()[0], "")
		arraylen := llvm.ConstInt(c.llvmtypes.inttype, uint64(arraytyp.Len()), false)
		sliceValue = c.builder.CreateInsertValue(sliceValue, arrayptr, 0, "")
		sliceValue = c.builder.CreateInsertValue(sliceValue, arraylen, 1, "")
		sliceValue = c.builder.CreateInsertValue(sliceValue, arraylen, 2, "")
		sliceTyp := types.NewSlice(arraytyp.Elem())
		runtimeTyp := c.types.ToRuntime(sliceTyp)
		runtimeTyp = c.builder.CreatePtrToInt(runtimeTyp, c.target.IntPtrType(), "")
		args := []llvm.Value{runtimeTyp, sliceValue, low.LLVMValue(), high.LLVMValue()}
		result := c.builder.CreateCall(sliceslice, args, "")
		llvmSliceTyp := c.types.ToLLVM(sliceTyp)
		return c.NewValue(c.coerceSlice(result, llvmSliceTyp), sliceTyp)
	case *types.Slice:
		sliceslice := c.runtime.sliceslice.LLVMValue()
		i8slice := sliceslice.Type().ElementType().ReturnType()
		sliceValue := x.LLVMValue()
		sliceTyp := sliceValue.Type()
		sliceValue = c.coerceSlice(sliceValue, i8slice)
		runtimeTyp := c.types.ToRuntime(x.Type())
		runtimeTyp = c.builder.CreatePtrToInt(runtimeTyp, c.target.IntPtrType(), "")
		args := []llvm.Value{runtimeTyp, sliceValue, low.LLVMValue(), high.LLVMValue()}
		result := c.builder.CreateCall(sliceslice, args, "")
		return c.NewValue(c.coerceSlice(result, sliceTyp), x.Type())
	case *types.Basic:
		stringslice := c.runtime.stringslice.LLVMValue()
		llv := x.LLVMValue()
		args := []llvm.Value{
			c.coerceString(llv, stringslice.Type().ElementType().ParamTypes()[0]),
			low.LLVMValue(),
			high.LLVMValue(),
		}
		result := c.builder.CreateCall(stringslice, args, "")
		return c.NewValue(c.coerceString(result, llv.Type()), x.Type())
	default:
		panic("unimplemented")
	}
	panic("unreachable")
}
예제 #9
0
파일: descriptors.go 프로젝트: rvedam/llgo
func (d *CompileUnitDescriptor) mdNode(info *DebugInfo) llvm.Value {
	return llvm.MDNode([]llvm.Value{
		llvm.ConstInt(llvm.Int32Type(), uint64(d.Tag())+llvm.LLVMDebugVersion, false),
		d.Path.path(),
		llvm.ConstInt(llvm.Int32Type(), uint64(d.Language), false),
		llvm.MDString(d.Producer),
		constInt1(d.Optimized),
		llvm.MDString(d.CompilerFlags),
		llvm.ConstInt(llvm.Int32Type(), uint64(d.Runtime), false),
		d.mdNodeList(info, d.EnumTypes),
		d.mdNodeList(info, d.RetainedTypes),
		d.mdNodeList(info, d.Subprograms),
		d.mdNodeList(info, d.GlobalVariables),
		d.mdNodeList(info, nil), // List of imported entities
		llvm.MDString(""),       // Split debug filename
	})
}
예제 #10
0
파일: descriptors.go 프로젝트: rvedam/llgo
func (d FileDescriptor) mdNode(info *DebugInfo) llvm.Value {
	if d == "" {
		return llvm.Value{}
	}
	return llvm.MDNode([]llvm.Value{
		llvm.ConstInt(llvm.Int32Type(), llvm.LLVMDebugVersion+uint64(d.Tag()), false),
		d.path(),
	})
}
예제 #11
0
파일: slice.go 프로젝트: rvedam/llgo
// makeLiteralSlice allocates a new slice, storing in it the provided elements.
func (c *compiler) makeLiteralSlice(v []llvm.Value, elttyp types.Type) llvm.Value {
	n := llvm.ConstInt(c.types.inttype, uint64(len(v)), false)
	eltType := c.types.ToLLVM(elttyp)
	arrayType := llvm.ArrayType(eltType, len(v))
	mem := c.createMalloc(llvm.SizeOf(arrayType))
	mem = c.builder.CreateIntToPtr(mem, llvm.PointerType(eltType, 0), "")
	for i, value := range v {
		indices := []llvm.Value{llvm.ConstInt(llvm.Int32Type(), uint64(i), false)}
		ep := c.builder.CreateGEP(mem, indices, "")
		c.builder.CreateStore(value, ep)
	}
	slicetyp := types.NewSlice(elttyp)
	struct_ := llvm.Undef(c.types.ToLLVM(slicetyp))
	struct_ = c.builder.CreateInsertValue(struct_, mem, 0, "")
	struct_ = c.builder.CreateInsertValue(struct_, n, 1, "")
	struct_ = c.builder.CreateInsertValue(struct_, n, 2, "")
	return struct_
}
예제 #12
0
파일: typemap.go 프로젝트: rvedam/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
}
예제 #13
0
파일: typemap.go 프로젝트: rvedam/llgo
func (tm *TypeMap) arrayRuntimeType(a *types.Array) (global, ptr llvm.Value) {
	rtype := tm.makeRtype(a, reflect.Array)
	elemRuntimeType := tm.ToRuntime(a.Elem())
	sliceRuntimeType := tm.ToRuntime(types.NewSlice(a.Elem()))
	uintptrlen := llvm.ConstInt(tm.target.IntPtrType(), uint64(a.Len()), false)
	arrayType := llvm.ConstNull(tm.runtime.arrayType.llvm)
	arrayType = llvm.ConstInsertValue(arrayType, rtype, []uint32{0})
	arrayType = llvm.ConstInsertValue(arrayType, elemRuntimeType, []uint32{1})
	arrayType = llvm.ConstInsertValue(arrayType, sliceRuntimeType, []uint32{2})
	arrayType = llvm.ConstInsertValue(arrayType, uintptrlen, []uint32{3})
	return tm.makeRuntimeTypeGlobal(arrayType, typeString(a))
}
예제 #14
0
파일: builtins.go 프로젝트: rvedam/llgo
func (c *compiler) callLen(arg *LLVMValue) *LLVMValue {
	var lenvalue llvm.Value
	switch typ := arg.Type().Underlying().(type) {
	case *types.Array:
		lenvalue = llvm.ConstInt(c.llvmtypes.inttype, uint64(typ.Len()), false)
	case *types.Pointer:
		atyp := typ.Elem().Underlying().(*types.Array)
		lenvalue = llvm.ConstInt(c.llvmtypes.inttype, uint64(atyp.Len()), false)
	case *types.Slice:
		lenvalue = c.builder.CreateExtractValue(arg.LLVMValue(), 1, "")
	case *types.Map:
		f := c.runtime.maplen.LLVMValue()
		lenvalue = c.builder.CreateCall(f, []llvm.Value{arg.LLVMValue()}, "")
	case *types.Basic:
		if isString(typ) {
			lenvalue = c.builder.CreateExtractValue(arg.LLVMValue(), 1, "")
		}
	case *types.Chan:
		f := c.runtime.chanlen.LLVMValue()
		lenvalue = c.builder.CreateCall(f, []llvm.Value{arg.LLVMValue()}, "")
	}
	return c.NewValue(lenvalue, types.Typ[types.Int])
}
예제 #15
0
파일: descriptors.go 프로젝트: rvedam/llgo
func (d *BasicTypeDescriptor) mdNode(info *DebugInfo) llvm.Value {
	return llvm.MDNode([]llvm.Value{
		llvm.ConstInt(llvm.Int32Type(), llvm.LLVMDebugVersion+uint64(d.Tag()), false),
		FileDescriptor(d.File).path(),
		info.MDNode(d.Context),
		llvm.MDString(d.Name),
		llvm.ConstInt(llvm.Int32Type(), uint64(d.Line), false),
		llvm.ConstInt(llvm.Int64Type(), d.Size, false),
		llvm.ConstInt(llvm.Int64Type(), d.Alignment, false),
		llvm.ConstInt(llvm.Int64Type(), d.Offset, false),
		llvm.ConstInt(llvm.Int32Type(), uint64(d.Flags), false),
		llvm.ConstInt(llvm.Int32Type(), uint64(d.TypeEncoding), false)})
}
예제 #16
0
파일: descriptors.go 프로젝트: rvedam/llgo
func (d *CompositeTypeDescriptor) mdNode(info *DebugInfo) llvm.Value {
	return llvm.MDNode([]llvm.Value{
		llvm.ConstInt(llvm.Int32Type(), llvm.LLVMDebugVersion+uint64(d.Tag()), false),
		FileDescriptor(d.File).path(),
		info.MDNode(d.Context),
		llvm.MDString(d.Name),
		llvm.ConstInt(llvm.Int32Type(), uint64(d.Line), false),
		llvm.ConstInt(llvm.Int64Type(), d.Size, false),
		llvm.ConstInt(llvm.Int64Type(), d.Alignment, false),
		llvm.ConstInt(llvm.Int64Type(), d.Offset, false),
		llvm.ConstInt(llvm.Int32Type(), uint64(d.Flags), false),
		info.MDNode(d.Base), // reference type derived from
		llvm.MDNode(info.MDNodes(d.Members)),
		llvm.ConstInt(llvm.Int32Type(), uint64(0), false), // Runtime language
		llvm.ConstInt(llvm.Int32Type(), uint64(0), false), // Base type containing the vtable pointer for this type
	})
}
예제 #17
0
파일: typemap.go 프로젝트: rvedam/llgo
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.
	typ := llvm.ConstNull(tm.runtime.rtype.llvm)
	elementTypes := tm.runtime.rtype.llvm.StructElementTypes()

	// Size.
	size := llvm.ConstInt(elementTypes[0], uint64(tm.Sizeof(t)), false)
	typ = llvm.ConstInsertValue(typ, size, []uint32{0})

	// TODO hash
	// TODO padding

	// Alignment.
	align := llvm.ConstInt(llvm.Int8Type(), uint64(tm.Alignof(t)), false)
	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(t.String())
	typ = llvm.ConstInsertValue(typ, stringrep, []uint32{8})

	// TODO gc
	return typ
}
예제 #18
0
파일: descriptors.go 프로젝트: rvedam/llgo
func (d *SubprogramDescriptor) mdNode(info *DebugInfo) llvm.Value {
	return llvm.MDNode([]llvm.Value{
		llvm.ConstInt(llvm.Int32Type(), llvm.LLVMDebugVersion+uint64(d.Tag()), false),
		FileDescriptor(d.File).path(),
		info.MDNode(d.Context),
		llvm.MDString(d.Name),
		llvm.MDString(d.DisplayName),
		llvm.MDString(""), // mips linkage name
		llvm.ConstInt(llvm.Int32Type(), uint64(d.Line), false),
		info.MDNode(d.Type),
		llvm.ConstNull(llvm.Int1Type()),           // not static
		llvm.ConstAllOnes(llvm.Int1Type()),        // locally defined (not extern)
		llvm.ConstNull(llvm.Int32Type()),          // virtuality
		llvm.ConstNull(llvm.Int32Type()),          // index into a virtual function
		info.MDNode(nil),                          // basetype containing the vtable pointer
		llvm.ConstInt(llvm.Int32Type(), 0, false), // flags
		llvm.ConstNull(llvm.Int1Type()),           // not optimised
		d.Function,
		info.MDNode(nil),                                            // Template parameters
		info.MDNode(nil),                                            // function declaration descriptor
		llvm.MDNode(nil),                                            // function variables
		llvm.ConstInt(llvm.Int32Type(), uint64(d.ScopeLine), false), // Line number where the scope of the subprogram begins
	})
}
예제 #19
0
파일: typemap.go 프로젝트: rvedam/llgo
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
}
예제 #20
0
파일: typemap.go 프로젝트: rvedam/llgo
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
}
예제 #21
0
파일: typemap.go 프로젝트: rvedam/llgo
func (tm *TypeMap) funcRuntimeType(f *types.Signature) (global, ptr llvm.Value) {
	rtype := tm.makeRtype(f, reflect.Func)
	funcType := llvm.ConstNull(tm.runtime.funcType.llvm)
	global, ptr = tm.makeRuntimeTypeGlobal(funcType, typeString(f))
	tm.types.Set(f, runtimeTypeInfo{global, ptr})
	funcType = llvm.ConstInsertValue(funcType, rtype, []uint32{0})
	// dotdotdot
	if f.Variadic() {
		variadic := llvm.ConstInt(llvm.Int1Type(), 1, false)
		funcType = llvm.ConstInsertValue(funcType, variadic, []uint32{1})
	}
	// in
	intypes := tm.rtypeSlice(f.Params())
	funcType = llvm.ConstInsertValue(funcType, intypes, []uint32{2})
	// out
	outtypes := tm.rtypeSlice(f.Results())
	funcType = llvm.ConstInsertValue(funcType, outtypes, []uint32{3})
	global.SetInitializer(funcType)
	return global, ptr
}
예제 #22
0
파일: typemap.go 프로젝트: rvedam/llgo
func (tm *TypeMap) chanRuntimeType(c *types.Chan) (global, ptr llvm.Value) {
	rtype := tm.makeRtype(c, reflect.Chan)
	chanType := llvm.ConstNull(tm.runtime.chanType.llvm)
	chanType = llvm.ConstInsertValue(chanType, rtype, []uint32{0})
	chanType = llvm.ConstInsertValue(chanType, tm.ToRuntime(c.Elem()), []uint32{1})

	// go/ast and reflect disagree on values for direction.
	var dir reflect.ChanDir
	switch c.Dir() {
	case types.SendOnly:
		dir = reflect.SendDir
	case types.RecvOnly:
		dir = reflect.RecvDir
	case types.SendRecv:
		dir = reflect.SendDir | reflect.RecvDir
	}
	uintptrdir := llvm.ConstInt(tm.target.IntPtrType(), uint64(dir), false)
	chanType = llvm.ConstInsertValue(chanType, uintptrdir, []uint32{2})
	return tm.makeRuntimeTypeGlobal(chanType, typeString(c))
}
예제 #23
0
파일: value.go 프로젝트: rvedam/llgo
func (lhs *LLVMValue) shift(rhs *LLVMValue, op token.Token) *LLVMValue {
	rhs = rhs.Convert(lhs.Type()).(*LLVMValue)
	lhsval := lhs.LLVMValue()
	bits := rhs.LLVMValue()
	unsigned := isUnsigned(lhs.Type())
	b := lhs.compiler.builder
	// Shifting >= width of lhs yields undefined behaviour, so we must select.
	max := llvm.ConstInt(bits.Type(), uint64(lhsval.Type().IntTypeWidth()-1), false)
	var result llvm.Value
	if !unsigned && op == token.SHR {
		bits := b.CreateSelect(b.CreateICmp(llvm.IntULE, bits, max, ""), bits, max, "")
		result = b.CreateAShr(lhsval, bits, "")
	} else {
		if op == token.SHL {
			result = b.CreateShl(lhsval, bits, "")
		} else {
			result = b.CreateLShr(lhsval, bits, "")
		}
		zero := llvm.ConstNull(lhsval.Type())
		result = b.CreateSelect(b.CreateICmp(llvm.IntULE, bits, max, ""), result, zero, "")
	}
	return lhs.compiler.NewValue(result, lhs.typ)
}
예제 #24
0
파일: indirect.go 프로젝트: rvedam/llgo
// indirectFunction creates an indirect function from a
// given function and arguments, suitable for use with
// "defer" and "go".
func (c *compiler) indirectFunction(fn *LLVMValue, args []*LLVMValue) *LLVMValue {
	nilarytyp := types.NewSignature(nil, nil, nil, nil, false)
	if len(args) == 0 {
		val := fn.LLVMValue()
		ptr := c.builder.CreateExtractValue(val, 0, "")
		ctx := c.builder.CreateExtractValue(val, 1, "")
		fnval := llvm.Undef(c.types.ToLLVM(nilarytyp))
		ptr = c.builder.CreateBitCast(ptr, fnval.Type().StructElementTypes()[0], "")
		ctx = c.builder.CreateBitCast(ctx, fnval.Type().StructElementTypes()[1], "")
		fnval = c.builder.CreateInsertValue(fnval, ptr, 0, "")
		fnval = c.builder.CreateInsertValue(fnval, ctx, 1, "")
		return c.NewValue(fnval, nilarytyp)
	}

	// Check if function pointer or context pointer is global/null.
	fnval := fn.LLVMValue()
	fnptr := fnval
	var nctx int
	var fnctx llvm.Value
	var fnctxindex uint64
	var globalfn bool
	if fnptr.Type().TypeKind() == llvm.StructTypeKind {
		fnptr = c.builder.CreateExtractValue(fnval, 0, "")
		fnctx = c.builder.CreateExtractValue(fnval, 1, "")
		globalfn = !fnptr.IsAFunction().IsNil()
		if !globalfn {
			nctx++
		}
		if !fnctx.IsNull() {
			fnctxindex = uint64(nctx)
			nctx++
		}
	} else {
		// We've got a raw global function pointer. Convert to <ptr,ctx>.
		fnval = llvm.ConstNull(c.types.ToLLVM(fn.Type()))
		fnval = llvm.ConstInsertValue(fnval, fnptr, []uint32{0})
		fn = c.NewValue(fnval, fn.Type())
		fnctx = llvm.ConstExtractValue(fnval, []uint32{1})
		globalfn = true
	}

	i8ptr := llvm.PointerType(llvm.Int8Type(), 0)
	llvmargs := make([]llvm.Value, len(args)+nctx)
	llvmargtypes := make([]llvm.Type, len(args)+nctx)
	for i, arg := range args {
		llvmargs[i+nctx] = arg.LLVMValue()
		llvmargtypes[i+nctx] = llvmargs[i+nctx].Type()
	}
	if !globalfn {
		llvmargtypes[0] = fnptr.Type()
		llvmargs[0] = fnptr
	}
	if !fnctx.IsNull() {
		llvmargtypes[fnctxindex] = fnctx.Type()
		llvmargs[fnctxindex] = fnctx
	}

	// TODO(axw) investigate an option for go statements
	// to allocate argument structure on the stack in the
	// initiator, and block until the spawned goroutine
	// has loaded the arguments from it.
	structtyp := llvm.StructType(llvmargtypes, false)
	argstruct := c.createTypeMalloc(structtyp)
	for i, llvmarg := range llvmargs {
		argptr := c.builder.CreateGEP(argstruct, []llvm.Value{
			llvm.ConstInt(llvm.Int32Type(), 0, false),
			llvm.ConstInt(llvm.Int32Type(), uint64(i), false)}, "")
		c.builder.CreateStore(llvmarg, argptr)
	}

	// Create a function that will take a pointer to a structure of the type
	// defined above, or no parameters if there are none to pass.
	fntype := llvm.FunctionType(llvm.VoidType(), []llvm.Type{argstruct.Type()}, false)
	indirectfn := llvm.AddFunction(c.module.Module, "", fntype)
	i8argstruct := c.builder.CreateBitCast(argstruct, i8ptr, "")
	currblock := c.builder.GetInsertBlock()
	c.builder.SetInsertPointAtEnd(llvm.AddBasicBlock(indirectfn, "entry"))
	argstruct = indirectfn.Param(0)
	newargs := make([]*LLVMValue, len(args))
	for i := range llvmargs[nctx:] {
		argptr := c.builder.CreateGEP(argstruct, []llvm.Value{
			llvm.ConstInt(llvm.Int32Type(), 0, false),
			llvm.ConstInt(llvm.Int32Type(), uint64(i+nctx), false)}, "")
		newargs[i] = c.NewValue(c.builder.CreateLoad(argptr, ""), args[i].Type())
	}

	// Unless we've got a global function, extract the
	// function pointer from the context.
	if !globalfn {
		fnval = llvm.Undef(fnval.Type())
		fnptrptr := c.builder.CreateGEP(argstruct, []llvm.Value{
			llvm.ConstInt(llvm.Int32Type(), 0, false),
			llvm.ConstInt(llvm.Int32Type(), 0, false)}, "")
		fnptr = c.builder.CreateLoad(fnptrptr, "")
		fnval = c.builder.CreateInsertValue(fnval, fnptr, 0, "")
	}
	if !fnctx.IsNull() {
		fnctxptr := c.builder.CreateGEP(argstruct, []llvm.Value{
			llvm.ConstInt(llvm.Int32Type(), 0, false),
			llvm.ConstInt(llvm.Int32Type(), fnctxindex, false)}, "")
		fnctx = c.builder.CreateLoad(fnctxptr, "")
		fnval = c.builder.CreateInsertValue(fnval, fnctx, 1, "")
		fn = c.NewValue(fnval, fn.Type())
	}
	c.createCall(fn, newargs)

	// Indirect function calls' return values are always ignored.
	c.builder.CreateRetVoid()
	c.builder.SetInsertPointAtEnd(currblock)

	fnval = llvm.Undef(c.types.ToLLVM(nilarytyp))
	indirectfn = c.builder.CreateBitCast(indirectfn, fnval.Type().StructElementTypes()[0], "")
	fnval = c.builder.CreateInsertValue(fnval, indirectfn, 0, "")
	fnval = c.builder.CreateInsertValue(fnval, i8argstruct, 1, "")
	fn = c.NewValue(fnval, nilarytyp)
	return fn
}
예제 #25
0
파일: value.go 프로젝트: rvedam/llgo
func (c *compiler) NewConstValue(v exact.Value, typ types.Type) *LLVMValue {
	switch {
	case v == nil:
		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)", typ, typ, v, v))
}
예제 #26
0
파일: factorial.go 프로젝트: go-llvm/llvm
func test() {
	llvm.LinkInMCJIT()
	llvm.InitializeNativeTarget()
	llvm.InitializeNativeAsmPrinter()

	mod := llvm.NewModule("fac_module")

	// don't do that, because ExecutionEngine takes ownership over module
	//defer mod.Dispose()

	fac_args := []llvm.Type{llvm.Int32Type()}
	fac_type := llvm.FunctionType(llvm.Int32Type(), fac_args, false)
	fac := llvm.AddFunction(mod, "fac", fac_type)
	fac.SetFunctionCallConv(llvm.CCallConv)
	n := fac.Param(0)

	entry := llvm.AddBasicBlock(fac, "entry")
	iftrue := llvm.AddBasicBlock(fac, "iftrue")
	iffalse := llvm.AddBasicBlock(fac, "iffalse")
	end := llvm.AddBasicBlock(fac, "end")

	builder := llvm.NewBuilder()
	defer builder.Dispose()

	builder.SetInsertPointAtEnd(entry)
	If := builder.CreateICmp(llvm.IntEQ, n, llvm.ConstInt(llvm.Int32Type(), 0, false), "cmptmp")
	builder.CreateCondBr(If, iftrue, iffalse)

	builder.SetInsertPointAtEnd(iftrue)
	res_iftrue := llvm.ConstInt(llvm.Int32Type(), 1, false)
	builder.CreateBr(end)

	builder.SetInsertPointAtEnd(iffalse)
	n_minus := builder.CreateSub(n, llvm.ConstInt(llvm.Int32Type(), 1, false), "subtmp")
	call_fac_args := []llvm.Value{n_minus}
	call_fac := builder.CreateCall(fac, call_fac_args, "calltmp")
	res_iffalse := builder.CreateMul(n, call_fac, "multmp")
	builder.CreateBr(end)

	builder.SetInsertPointAtEnd(end)
	res := builder.CreatePHI(llvm.Int32Type(), "result")
	phi_vals := []llvm.Value{res_iftrue, res_iffalse}
	phi_blocks := []llvm.BasicBlock{iftrue, iffalse}
	res.AddIncoming(phi_vals, phi_blocks)
	builder.CreateRet(res)

	err := llvm.VerifyModule(mod, llvm.ReturnStatusAction)
	if err != nil {
		fmt.Println(err)
		return
	}

	engine, err := llvm.NewMCJITCompiler(mod, llvm.MCJITCompilerOptions{OptLevel: 2})
	if err != nil {
		fmt.Println(err)
		return
	}
	defer engine.Dispose()

	pass := llvm.NewPassManager()
	defer pass.Dispose()

	pass.Add(engine.TargetData())
	pass.AddConstantPropagationPass()
	pass.AddInstructionCombiningPass()
	pass.AddPromoteMemoryToRegisterPass()
	pass.AddGVNPass()
	pass.AddCFGSimplificationPass()
	pass.Run(mod)

	mod.Dump()

	exec_args := []llvm.GenericValue{llvm.NewGenericValueFromInt(llvm.Int32Type(), 10, false)}
	exec_res := engine.RunFunction(fac, exec_args)
	fmt.Println("-----------------------------------------")
	fmt.Println("Running fac(10) with JIT...")
	fmt.Printf("Result: %d\n", exec_res.Int(false))
}
예제 #27
0
파일: channels.go 프로젝트: rvedam/llgo
func (c *compiler) chanSelect(states []selectState, blocking bool) *LLVMValue {
	stackptr := c.stacksave()
	defer c.stackrestore(stackptr)

	n := uint64(len(states))
	if !blocking {
		// blocking means there's no default case
		n++
	}
	lln := llvm.ConstInt(llvm.Int32Type(), n, false)
	allocsize := c.builder.CreateCall(c.runtime.selectsize.LLVMValue(), []llvm.Value{lln}, "")
	selectp := c.builder.CreateArrayAlloca(llvm.Int8Type(), allocsize, "selectp")
	c.memsetZero(selectp, allocsize)
	selectp = c.builder.CreatePtrToInt(selectp, c.target.IntPtrType(), "")
	c.builder.CreateCall(c.runtime.selectinit.LLVMValue(), []llvm.Value{lln, selectp}, "")

	// Allocate stack for the values to send/receive.
	//
	// TODO(axw) request optimisation in ssa to special-
	// case receive cases with no assignment, so we know
	// not to allocate stack space or do a copy.
	resTypes := []types.Type{types.Typ[types.Int], types.Typ[types.Bool]}
	for _, state := range states {
		if state.Dir == types.RecvOnly {
			chantyp := state.Chan.Type().Underlying().(*types.Chan)
			resTypes = append(resTypes, chantyp.Elem())
		}
	}
	resType := tupleType(resTypes...)
	llResType := c.types.ToLLVM(resType)
	tupleptr := c.builder.CreateAlloca(llResType, "")
	c.memsetZero(tupleptr, llvm.SizeOf(llResType))

	var recvindex int
	ptrs := make([]llvm.Value, len(states))
	for i, state := range states {
		chantyp := state.Chan.Type().Underlying().(*types.Chan)
		elemtyp := c.types.ToLLVM(chantyp.Elem())
		if state.Dir == types.SendOnly {
			ptrs[i] = c.builder.CreateAlloca(elemtyp, "")
			c.builder.CreateStore(state.Send.LLVMValue(), ptrs[i])
		} else {
			ptrs[i] = c.builder.CreateStructGEP(tupleptr, recvindex+2, "")
			recvindex++
		}
		ptrs[i] = c.builder.CreatePtrToInt(ptrs[i], c.target.IntPtrType(), "")
	}

	// Create select{send,recv} calls.
	selectsend := c.runtime.selectsend.LLVMValue()
	selectrecv := c.runtime.selectrecv.LLVMValue()
	var received llvm.Value
	if recvindex > 0 {
		received = c.builder.CreateStructGEP(tupleptr, 1, "")
	}
	if !blocking {
		c.builder.CreateCall(c.runtime.selectdefault.LLVMValue(), []llvm.Value{selectp}, "")
	}
	for i, state := range states {
		ch := state.Chan.LLVMValue()
		if state.Dir == types.SendOnly {
			c.builder.CreateCall(selectsend, []llvm.Value{selectp, ch, ptrs[i]}, "")
		} else {
			c.builder.CreateCall(selectrecv, []llvm.Value{selectp, ch, ptrs[i], received}, "")
		}
	}

	// Fire off the select.
	index := c.builder.CreateCall(c.runtime.selectgo.LLVMValue(), []llvm.Value{selectp}, "")
	tuple := c.builder.CreateLoad(tupleptr, "")
	tuple = c.builder.CreateInsertValue(tuple, index, 0, "")
	return c.NewValue(tuple, resType)
}