Beispiel #1
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 #2
0
func (v ConstValue) Convert(dst_typ types.Type) Value {
	// Get the underlying type, if any.
	if name, isname := dst_typ.(*types.Name); isname {
		dst_typ = types.Underlying(name)
	}

	if !types.Identical(v.typ, dst_typ) {
		// Get the Basic type.
		isBasic := false
		if name, isname := types.Underlying(dst_typ).(*types.Name); isname {
			_, isBasic = name.Underlying.(*types.Basic)
		}

		compiler := v.compiler
		if isBasic {
			return ConstValue{*v.Const.Convert(&dst_typ), compiler, dst_typ}
		} else {
			return compiler.NewLLVMValue(v.LLVMValue(), v.Type()).Convert(dst_typ)
			//panic(fmt.Errorf("unhandled conversion from %v to %v", v.typ, dst_typ))
		}
	} else {
		// TODO convert to dst type. ConstValue may need to change to allow
		// storage of types other than Basic.
	}
	return v
}
Beispiel #3
0
func (v ConstValue) Convert(dstTyp types.Type) Value {
	// Get the underlying type, if any.
	origDstTyp := dstTyp
	dstTyp = types.Underlying(dstTyp)

	if !types.Identical(v.typ, dstTyp) {
		isBasic := false
		if name, isname := types.Underlying(dstTyp).(*types.Name); isname {
			_, isBasic = name.Underlying.(*types.Basic)
		}

		compiler := v.compiler
		if isBasic {
			return ConstValue{v.Const.Convert(&dstTyp), compiler, origDstTyp}
		} else {
			return compiler.NewLLVMValue(v.LLVMValue(), v.Type()).Convert(origDstTyp)
			//panic(fmt.Errorf("unhandled conversion from %v to %v", v.typ, dstTyp))
		}
	} else {
		v.typ = origDstTyp
	}
	return v
}
Beispiel #4
0
func (c *compiler) VisitSelectorExpr(expr *ast.SelectorExpr) Value {
	lhs := c.VisitExpr(expr.X)
	if lhs == nil {
		// The only time we should get a nil result is if the object is
		// a package.
		obj := expr.Sel.Obj
		if obj.Kind == ast.Typ {
			return TypeValue{obj.Type.(types.Type)}
		}
		return c.Resolve(obj)
	}

	// Method expression. Returns an unbound function pointer.
	// FIXME this is just the most basic case. It's also possible to
	// create a pointer-receiver function from a method that has a
	// value receiver (see Method Expressions in spec).
	name := expr.Sel.Name
	if _, ok := lhs.(TypeValue); ok {
		methodobj := expr.Sel.Obj
		value := c.Resolve(methodobj).(*LLVMValue)
		ftyp := value.typ.(*types.Func)
		methodParams := make(types.ObjList, len(ftyp.Params)+1)
		methodParams[0] = ftyp.Recv
		copy(methodParams[1:], ftyp.Params)
		ftyp = &types.Func{
			Recv:       nil,
			Params:     methodParams,
			Results:    ftyp.Results,
			IsVariadic: ftyp.IsVariadic,
		}
		return c.NewLLVMValue(value.value, ftyp)
	}

	// TODO(?) record path to field/method during typechecking, so we don't
	// have to search again here.

	if iface, ok := types.Underlying(lhs.Type()).(*types.Interface); ok {
		i := sort.Search(len(iface.Methods), func(i int) bool {
			return iface.Methods[i].Name >= name
		})
		structValue := lhs.LLVMValue()
		receiver := c.builder.CreateExtractValue(structValue, 1, "")
		f := c.builder.CreateExtractValue(structValue, i+2, "")
		i8ptr := &types.Pointer{Base: types.Int8}
		ftype := iface.Methods[i].Type.(*types.Func)
		ftype.Recv = ast.NewObj(ast.Var, "")
		ftype.Recv.Type = i8ptr
		f = c.builder.CreateBitCast(f, c.types.ToLLVM(ftype), "")
		ftype.Recv = nil
		method := c.NewLLVMValue(f, ftype)
		method.receiver = c.NewLLVMValue(receiver, i8ptr)
		return method
	}

	// Search through embedded types for field/method.
	var result selectorCandidate
	curr := []selectorCandidate{{nil, lhs.Type()}}
	for result.Type == nil && len(curr) > 0 {
		var next []selectorCandidate
		for _, candidate := range curr {
			indices := candidate.Indices[0:]
			t := candidate.Type

			if p, ok := types.Underlying(t).(*types.Pointer); ok {
				if _, ok := types.Underlying(p.Base).(*types.Struct); ok {
					t = p.Base
				}
			}

			if n, ok := t.(*types.Name); ok {
				i := sort.Search(len(n.Methods), func(i int) bool {
					return n.Methods[i].Name >= name
				})
				if i < len(n.Methods) && n.Methods[i].Name == name {
					result.Indices = indices
					result.Type = t
				}
			}

			if t, ok := types.Underlying(t).(*types.Struct); ok {
				if i, ok := t.FieldIndices[name]; ok {
					result.Indices = append(indices, int(i))
					result.Type = t
				} else {
					// Add embedded types to the next set of types
					// to check.
					for i, field := range t.Fields {
						if field.Name == "" {
							indices = append(indices[0:], i)
							t := field.Type.(types.Type)
							candidate := selectorCandidate{indices, t}
							next = append(next, candidate)
						}
					}
				}
			}
		}
		curr = next
	}

	// Get a pointer to the field/receiver.
	recvValue := lhs.(*LLVMValue)
	if len(result.Indices) > 0 {
		if _, ok := types.Underlying(lhs.Type()).(*types.Pointer); !ok {
			recvValue = recvValue.pointer
			//recvValue = c.NewLLVMValue(recvValue.LLVMValue(), recvValue.Type())
		}
		for _, v := range result.Indices {
			ptr := recvValue.LLVMValue()
			field := types.Underlying(types.Deref(recvValue.typ)).(*types.Struct).Fields[v]
			fieldPtr := c.builder.CreateStructGEP(ptr, v, "")
			fieldPtrTyp := &types.Pointer{Base: field.Type.(types.Type)}
			recvValue = c.NewLLVMValue(fieldPtr, fieldPtrTyp)

			// GEP returns a pointer; if the field is a pointer,
			// we must load our pointer-to-a-pointer.
			if _, ok := field.Type.(*types.Pointer); ok {
				recvValue = recvValue.makePointee()
			}
		}
	}

	// Method?
	if expr.Sel.Obj.Kind == ast.Fun {
		method := c.Resolve(expr.Sel.Obj).(*LLVMValue)
		methodType := expr.Sel.Obj.Type.(*types.Func)
		receiverType := methodType.Recv.Type.(types.Type)
		if types.Identical(recvValue.Type(), receiverType) {
			method.receiver = recvValue
		} else if types.Identical(&types.Pointer{Base: recvValue.Type()}, receiverType) {
			method.receiver = recvValue.pointer
		} else {
			method.receiver = recvValue.makePointee()
		}
		return method
	} else {
		resultType := expr.Sel.Obj.Type.(types.Type)
		if types.Identical(recvValue.Type(), resultType) {
			// no-op
		} else if types.Identical(&types.Pointer{Base: recvValue.Type()}, resultType) {
			recvValue = recvValue.pointer
		} else {
			recvValue = recvValue.makePointee()
		}
		return recvValue
	}
	panic("unreachable")
}
Beispiel #5
0
func (c *compiler) VisitSelectorExpr(expr *ast.SelectorExpr) Value {
	lhs := c.VisitExpr(expr.X)
	if lhs == nil {
		// The only time we should get a nil result is if the object is
		// a package.
		obj := expr.Sel.Obj
		if obj.Kind == ast.Typ {
			return TypeValue{obj.Type.(types.Type)}
		}
		return c.Resolve(obj)
	}

	// TODO(?) record path to field/method during typechecking, so we don't
	// have to search again here.

	name := expr.Sel.Name
	if iface, ok := types.Underlying(lhs.Type()).(*types.Interface); ok {
		// validity checked during typechecking.
		i := sort.Search(len(iface.Methods), func(i int) bool {
			return iface.Methods[i].Name >= name
		})
		struct_value := lhs.LLVMValue()
		receiver_value := c.builder.CreateStructGEP(struct_value, 0, "")
		fn_value := c.builder.CreateStructGEP(struct_value, i+2, "")
		method_type := c.ObjGetType(iface.Methods[i]).(*types.Func)
		method := c.NewLLVMValue(
			c.builder.CreateBitCast(
				c.builder.CreateLoad(fn_value, ""),
				c.types.ToLLVM(method_type), ""), method_type)
		method.receiver = c.NewLLVMValue(
			c.builder.CreateLoad(receiver_value, ""),
			method_type.Recv.Type.(types.Type))
		return method
	}

	// Search through embedded types for field/method.
	var result selectorCandidate
	curr := []selectorCandidate{{nil, lhs.Type()}}
	for result.Type == nil && len(curr) > 0 {
		var next []selectorCandidate
		for _, candidate := range curr {
			indices := candidate.Indices[0:]
			t := candidate.Type

			if p, ok := types.Underlying(t).(*types.Pointer); ok {
				if _, ok := types.Underlying(p.Base).(*types.Struct); ok {
					indices = append(indices, 0)
					t = p.Base
				}
			}

			if n, ok := t.(*types.Name); ok {
				i := sort.Search(len(n.Methods), func(i int) bool {
					return n.Methods[i].Name >= name
				})
				if i < len(n.Methods) && n.Methods[i].Name == name {
					result.Indices = indices
					result.Type = t
				}
			}

			if t, ok := types.Underlying(t).(*types.Struct); ok {
				if i, ok := t.FieldIndices[name]; ok {
					result.Indices = append(indices, i)
					result.Type = t
				} else {
					// Add embedded types to the next set of types
					// to check.
					for i, field := range t.Fields {
						if field.Name == "" {
							indices = append(indices[0:], uint64(i))
							t := field.Type.(types.Type)
							candidate := selectorCandidate{indices, t}
							next = append(next, candidate)
						}
					}
				}
			}
		}
		curr = next
	}

	// Get a pointer to the field/struct for field/method invocation.
	indices := make([]llvm.Value, len(result.Indices))
	for i, v := range result.Indices {
		indices[i] = llvm.ConstInt(llvm.Int32Type(), v, false)
	}

	// Method?
	if expr.Sel.Obj.Kind == ast.Fun {
		method := c.Resolve(expr.Sel.Obj).(*LLVMValue)
		methodType := expr.Sel.Obj.Type.(*types.Func)
		receiverType := methodType.Recv.Type.(types.Type)
		if len(indices) > 0 {
			receiverValue := c.builder.CreateGEP(lhs.LLVMValue(), indices, "")
			if types.Identical(result.Type, receiverType) {
				receiverValue = c.builder.CreateLoad(receiverValue, "")
			}
			method.receiver = c.NewLLVMValue(receiverValue, receiverType)
		} else {
			lhs := lhs.(*LLVMValue)
			if types.Identical(result.Type, receiverType) {
				method.receiver = lhs
			} else if types.Identical(result.Type, &types.Pointer{Base: receiverType}) {
				method.receiver = lhs.makePointee()
			} else if types.Identical(&types.Pointer{Base: result.Type}, receiverType) {
				method.receiver = lhs.pointer
			}
		}
		return method
	} else {
		var ptr llvm.Value
		if _, ok := types.Underlying(lhs.Type()).(*types.Pointer); ok {
			ptr = lhs.LLVMValue()
		} else {
			if lhs, ok := lhs.(*LLVMValue); ok && lhs.pointer != nil {
				ptr = lhs.pointer.LLVMValue()
				zero := llvm.ConstNull(llvm.Int32Type())
				indices = append([]llvm.Value{zero}, indices...)
			} else {
				// TODO handle struct literal selectors.
				panic("selectors on struct literals unimplemented")
			}
		}
		fieldValue := c.builder.CreateGEP(ptr, indices, "")
		fieldType := &types.Pointer{Base: expr.Sel.Obj.Type.(types.Type)}
		return c.NewLLVMValue(fieldValue, fieldType).makePointee()
	}
	panic("unreachable")
}
Beispiel #6
0
// convertV2I converts a value to an interface.
func (v *LLVMValue) convertV2I(iface *types.Interface) Value {
	// TODO deref indirect value, then use 'pointer' as pointer value.
	var srcname *types.Name
	srctyp := v.Type()
	if name, isname := srctyp.(*types.Name); isname {
		srcname = name
		srctyp = name.Underlying
	}

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

	iface_struct_type := v.compiler.types.ToLLVM(iface)
	element_types := iface_struct_type.StructElementTypes()
	zero_iface_struct := llvm.ConstNull(iface_struct_type)
	iface_struct := zero_iface_struct

	builder := v.compiler.builder
	var ptr llvm.Value
	lv := v.LLVMValue()
	var overwide bool
	if lv.Type().TypeKind() == llvm.PointerTypeKind {
		ptr = builder.CreateBitCast(lv, element_types[1], "")
	} else {
		// If the value fits exactly in a pointer, then we can just
		// bitcast it. Otherwise we need to malloc, and create a shim
		// function to load the receiver.
		c := v.compiler
		ptrsize := c.target.PointerSize()
		if c.target.TypeStoreSize(lv.Type()) <= uint64(ptrsize) {
			bits := c.target.TypeSizeInBits(lv.Type())
			if bits > 0 {
				lv = c.coerce(lv, llvm.IntType(int(bits)))
				ptr = builder.CreateIntToPtr(lv, element_types[1], "")
			} else {
				ptr = llvm.ConstNull(element_types[1])
			}
		} else {
			ptr = c.createTypeMalloc(v.compiler.types.ToLLVM(srctyp))
			builder.CreateStore(lv, ptr)
			ptr = builder.CreateBitCast(ptr, element_types[1], "")
			overwide = true
		}
	}
	runtimeType := v.compiler.types.ToRuntime(v.Type())
	runtimeType = builder.CreateBitCast(runtimeType, element_types[0], "")
	iface_struct = builder.CreateInsertValue(iface_struct, runtimeType, 0, "")
	iface_struct = builder.CreateInsertValue(iface_struct, ptr, 1, "")

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

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

		// Look up the method by name.
		// TODO check embedded types.
		for i, m := range iface.Methods {
			// TODO make this loop linear by iterating through the
			// interface methods and type methods together.
			var methodobj *ast.Object
			curr := []types.Type{srcname}
			for methodobj == nil && len(curr) > 0 {
				var next []types.Type
				for _, typ := range curr {
					if p, ok := types.Underlying(typ).(*types.Pointer); ok {
						if _, ok := types.Underlying(p.Base).(*types.Struct); ok {
							typ = p.Base
						}
					}
					if n, ok := typ.(*types.Name); ok {
						methods := n.Methods
						mi := sort.Search(len(methods), func(i int) bool {
							return methods[i].Name >= m.Name
						})
						if mi < len(methods) && methods[mi].Name == m.Name {
							methodobj = methods[mi]
							break
						}
					}
					if typ, ok := types.Underlying(typ).(*types.Struct); ok {
						for _, field := range typ.Fields {
							if field.Name == "" {
								typ := field.Type.(types.Type)
								next = append(next, typ)
							}
						}
					}
				}
				curr = next
			}
			if methodobj == nil {
				msg := fmt.Sprintf("Failed to locate (%s).%s", srcname.Obj.Name, m.Name)
				panic(msg)
			}
			method := v.compiler.Resolve(methodobj).(*LLVMValue)
			llvm_value := method.LLVMValue()

			// If we have a receiver wider than a word, or a pointer
			// receiver value and non-pointer receiver method, then
			// we must use the "wrapper" pointer method.
			fntyp := methodobj.Type.(*types.Func)
			recvtyp := fntyp.Recv.Type.(types.Type)
			needload := overwide
			if !needload {
				// TODO handle embedded types here.
				//needload = types.Identical(v.Type(), recvtyp)
				if p, ok := v.Type().(*types.Pointer); ok {
					needload = types.Identical(p.Base, recvtyp)
				}
			}
			if needload {
				ifname := fmt.Sprintf("*%s.%s", recvtyp, methodobj.Name)
				llvm_value = v.compiler.module.NamedFunction(ifname)
			}
			llvm_value = builder.CreateBitCast(llvm_value, element_types[i+2], "")
			iface_struct = builder.CreateInsertValue(iface_struct, llvm_value, i+2, "")
		}
	}

	return v.compiler.NewLLVMValue(iface_struct, iface)
}
Beispiel #7
0
func (v *LLVMValue) Convert(dst_typ types.Type) Value {
	// If it's a stack allocated value, we'll want to compare the
	// value type, not the pointer type.
	src_typ := v.typ

	// Get the underlying type, if any.
	orig_dst_typ := dst_typ
	if name, isname := dst_typ.(*types.Name); isname {
		dst_typ = types.Underlying(name)
	}

	// Get the underlying type, if any.
	if name, isname := src_typ.(*types.Name); isname {
		src_typ = types.Underlying(name)
	}

	// Identical (underlying) types? Just swap in the destination type.
	if types.Identical(src_typ, dst_typ) {
		dst_typ = orig_dst_typ
		// TODO avoid load here by reusing pointer value, if exists.
		return v.compiler.NewLLVMValue(v.LLVMValue(), dst_typ)
	}

	// Convert from an interface type.
	if _, isinterface := src_typ.(*types.Interface); isinterface {
		if interface_, isinterface := dst_typ.(*types.Interface); isinterface {
			return v.convertI2I(interface_)
		} else {
			return v.convertI2V(dst_typ)
		}
	}

	// Converting to an interface type.
	if interface_, isinterface := dst_typ.(*types.Interface); isinterface {
		return v.convertV2I(interface_)
	}

	// string -> []byte
	byteslice := &types.Slice{Elt: types.Byte}
	if src_typ == types.String && types.Identical(dst_typ, byteslice) {
		c := v.compiler
		value := v.LLVMValue()
		strdata := c.builder.CreateExtractValue(value, 0, "")
		strlen := c.builder.CreateExtractValue(value, 1, "")
		struct_ := llvm.Undef(c.types.ToLLVM(byteslice))
		struct_ = c.builder.CreateInsertValue(struct_, strdata, 0, "")
		struct_ = c.builder.CreateInsertValue(struct_, strlen, 1, "")
		struct_ = c.builder.CreateInsertValue(struct_, strlen, 2, "")
		return c.NewLLVMValue(struct_, byteslice)
	}
	// []byte -> string
	if types.Identical(src_typ, byteslice) && dst_typ == types.String {
		c := v.compiler
		value := v.LLVMValue()
		data := c.builder.CreateExtractValue(value, 0, "")
		len := c.builder.CreateExtractValue(value, 1, "")
		struct_ := llvm.Undef(c.types.ToLLVM(types.String))
		struct_ = c.builder.CreateInsertValue(struct_, data, 0, "")
		struct_ = c.builder.CreateInsertValue(struct_, len, 1, "")
		return c.NewLLVMValue(struct_, types.String)
	}

	// TODO other special conversions, e.g. int->string.
	llvm_type := v.compiler.types.ToLLVM(dst_typ)

	// Unsafe pointer conversions.
	if dst_typ == types.UnsafePointer { // X -> unsafe.Pointer
		if _, isptr := src_typ.(*types.Pointer); isptr {
			value := v.compiler.builder.CreatePtrToInt(v.LLVMValue(), llvm_type, "")
			return v.compiler.NewLLVMValue(value, dst_typ)
		} else if src_typ == types.Uintptr {
			return v.compiler.NewLLVMValue(v.LLVMValue(), dst_typ)
		}
	} else if src_typ == types.UnsafePointer { // unsafe.Pointer -> X
		if _, isptr := dst_typ.(*types.Pointer); isptr {
			value := v.compiler.builder.CreateIntToPtr(v.LLVMValue(), llvm_type, "")
			return v.compiler.NewLLVMValue(value, dst_typ)
		} else if dst_typ == types.Uintptr {
			return v.compiler.NewLLVMValue(v.LLVMValue(), dst_typ)
		}
	}

	// FIXME select the appropriate cast here, depending on size, type (int/float)
	// and sign.
	lv := v.LLVMValue()
	srcType := lv.Type()
	switch srcType.TypeKind() { // source type
	case llvm.IntegerTypeKind:
		switch llvm_type.TypeKind() {
		case llvm.IntegerTypeKind:
			srcBits := srcType.IntTypeWidth()
			dstBits := llvm_type.IntTypeWidth()
			delta := srcBits - dstBits
			switch {
			case delta < 0:
				// TODO check if (un)signed, use S/ZExt accordingly.
				lv = v.compiler.builder.CreateZExt(lv, llvm_type, "")
			case delta > 0:
				lv = v.compiler.builder.CreateTrunc(lv, llvm_type, "")
			}
			return v.compiler.NewLLVMValue(lv, dst_typ)
		}
	case llvm.DoubleTypeKind:
		switch llvm_type.TypeKind() {
		case llvm.FloatTypeKind:
			lv = v.compiler.builder.CreateFPTrunc(lv, llvm_type, "")
			return v.compiler.NewLLVMValue(lv, dst_typ)
		}
	case llvm.FloatTypeKind:
		switch llvm_type.TypeKind() {
		case llvm.DoubleTypeKind:
			lv = v.compiler.builder.CreateFPExt(lv, llvm_type, "")
			return v.compiler.NewLLVMValue(lv, dst_typ)
		}
	}
	//bitcast_value := v.compiler.builder.CreateBitCast(lv, llvm_type, "")

	/*
	   value_type := value.Type()
	   switch value_type.TypeKind() {
	   case llvm.IntegerTypeKind:
	       switch totype.TypeKind() {
	       case llvm.IntegerTypeKind:
	           //delta := value_type.IntTypeWidth() - totype.IntTypeWidth()
	           //var
	           switch {
	           case delta == 0: return value
	           // TODO handle signed/unsigned (SExt/ZExt)
	           case delta < 0: return c.compiler.builder.CreateZExt(value, totype, "")
	           case delta > 0: return c.compiler.builder.CreateTrunc(value, totype, "")
	           }
	           return LLVMValue{lhs.compiler.builder, value}
	       }
	   }
	*/
	panic(fmt.Sprint("unimplemented conversion: ", v.typ, " -> ", orig_dst_typ))
}
Beispiel #8
0
func (lhs *LLVMValue) BinaryOp(op token.Token, rhs_ Value) Value {
	if op == token.NEQ {
		result := lhs.BinaryOp(token.EQL, rhs_)
		return result.UnaryOp(token.NOT)
	}

	var result llvm.Value
	c := lhs.compiler
	b := lhs.compiler.builder

	// Later we can do better by treating constants specially. For now, let's
	// convert to LLVMValue's.
	var rhs *LLVMValue
	rhsisnil := false
	switch rhs_ := rhs_.(type) {
	case *LLVMValue:
		rhs = rhs_
	case NilValue:
		rhsisnil = true
		switch rhs_ := rhs_.Convert(lhs.Type()).(type) {
		case ConstValue:
			rhs = c.NewLLVMValue(rhs_.LLVMValue(), rhs_.Type())
		case *LLVMValue:
			rhs = rhs_
		}
	case ConstValue:
		value := rhs_.Convert(lhs.Type())
		rhs = c.NewLLVMValue(value.LLVMValue(), value.Type())
	}

	switch typ := types.Underlying(lhs.typ).(type) {
	case *types.Struct:
		// TODO check types are the same.
		element_types_count := lhs.LLVMValue().Type().StructElementTypesCount()
		struct_fields := typ.Fields
		if element_types_count > 0 {
			t := c.ObjGetType(struct_fields[0])
			first_lhs := c.NewLLVMValue(b.CreateExtractValue(lhs.LLVMValue(), 0, ""), t)
			first_rhs := c.NewLLVMValue(b.CreateExtractValue(rhs.LLVMValue(), 0, ""), t)
			first := first_lhs.BinaryOp(op, first_rhs)

			logical_op := token.LAND
			if op == token.NEQ {
				logical_op = token.LOR
			}

			result := first
			for i := 1; i < element_types_count; i++ {
				t := c.ObjGetType(struct_fields[i])
				next_lhs := c.NewLLVMValue(b.CreateExtractValue(lhs.LLVMValue(), i, ""), t)
				next_rhs := c.NewLLVMValue(b.CreateExtractValue(rhs.LLVMValue(), i, ""), t)
				next := next_lhs.BinaryOp(op, next_rhs)
				result = result.BinaryOp(logical_op, next)
			}
			return result
		}

	case *types.Interface:
		if rhsisnil {
			valueNull := b.CreateIsNull(b.CreateExtractValue(lhs.LLVMValue(), 0, ""), "")
			typeNull := b.CreateIsNull(b.CreateExtractValue(lhs.LLVMValue(), 1, ""), "")
			result := b.CreateAnd(typeNull, valueNull, "")
			return c.NewLLVMValue(result, types.Bool)
		}
		// TODO check for interface/interface comparison vs. interface/value comparison.
		return lhs.compareI2I(rhs)

	case *types.Slice:
		// []T == nil
		isnil := b.CreateIsNull(b.CreateExtractValue(lhs.LLVMValue(), 0, ""), "")
		return c.NewLLVMValue(isnil, types.Bool)
	}

	// Strings.
	if types.Underlying(lhs.typ) == types.String {
		if types.Underlying(rhs.typ) == types.String {
			switch op {
			case token.ADD:
				return c.concatenateStrings(lhs, rhs)
			case token.EQL, token.LSS, token.GTR, token.LEQ, token.GEQ:
				return c.compareStrings(lhs, rhs, op)
			default:
				panic(fmt.Sprint("Unimplemented operator: ", op))
			}
		}
		panic("unimplemented")
	}

	// Determine whether to use integer or floating point instructions.
	// TODO determine the NaN rules.
	isfp := types.Identical(types.Underlying(lhs.typ), types.Float32) ||
		types.Identical(types.Underlying(lhs.typ), types.Float64)

	switch op {
	case token.MUL:
		if isfp {
			result = b.CreateFMul(lhs.LLVMValue(), rhs.LLVMValue(), "")
		} else {
			result = b.CreateMul(lhs.LLVMValue(), rhs.LLVMValue(), "")
		}
		return lhs.compiler.NewLLVMValue(result, lhs.typ)
	case token.QUO:
		if isfp {
			result = b.CreateFDiv(lhs.LLVMValue(), rhs.LLVMValue(), "")
		} else {
			result = b.CreateUDiv(lhs.LLVMValue(), rhs.LLVMValue(), "")
		}
		return lhs.compiler.NewLLVMValue(result, lhs.typ)
	case token.REM:
		if isfp {
			result = b.CreateFRem(lhs.LLVMValue(), rhs.LLVMValue(), "")
		} else {
			result = b.CreateURem(lhs.LLVMValue(), rhs.LLVMValue(), "")
		}
		return lhs.compiler.NewLLVMValue(result, lhs.typ)
	case token.ADD:
		if isfp {
			result = b.CreateFAdd(lhs.LLVMValue(), rhs.LLVMValue(), "")
		} else {
			result = b.CreateAdd(lhs.LLVMValue(), rhs.LLVMValue(), "")
		}
		return lhs.compiler.NewLLVMValue(result, lhs.typ)
	case token.SUB:
		if isfp {
			result = b.CreateFSub(lhs.LLVMValue(), rhs.LLVMValue(), "")
		} else {
			result = b.CreateSub(lhs.LLVMValue(), rhs.LLVMValue(), "")
		}
		return lhs.compiler.NewLLVMValue(result, lhs.typ)
	case token.SHL:
		rhs = rhs.Convert(lhs.Type()).(*LLVMValue)
		result = b.CreateShl(lhs.LLVMValue(), rhs.LLVMValue(), "")
		return lhs.compiler.NewLLVMValue(result, lhs.typ)
	case token.SHR:
		rhs = rhs.Convert(lhs.Type()).(*LLVMValue)
		result = b.CreateAShr(lhs.LLVMValue(), rhs.LLVMValue(), "")
		return lhs.compiler.NewLLVMValue(result, lhs.typ)
	case token.NEQ:
		if isfp {
			result = b.CreateFCmp(llvm.FloatONE, lhs.LLVMValue(), rhs.LLVMValue(), "")
		} else {
			result = b.CreateICmp(llvm.IntNE, lhs.LLVMValue(), rhs.LLVMValue(), "")
		}
		return lhs.compiler.NewLLVMValue(result, types.Bool)
	case token.EQL:
		if isfp {
			result = b.CreateFCmp(llvm.FloatOEQ, lhs.LLVMValue(), rhs.LLVMValue(), "")
		} else {
			result = b.CreateICmp(llvm.IntEQ, lhs.LLVMValue(), rhs.LLVMValue(), "")
		}
		return lhs.compiler.NewLLVMValue(result, types.Bool)
	case token.LSS:
		if isfp {
			result = b.CreateFCmp(llvm.FloatOLT, lhs.LLVMValue(), rhs.LLVMValue(), "")
		} else {
			result = b.CreateICmp(llvm.IntULT, lhs.LLVMValue(), rhs.LLVMValue(), "")
		}
		return lhs.compiler.NewLLVMValue(result, types.Bool)
	case token.LEQ: // TODO signed/unsigned
		if isfp {
			result = b.CreateFCmp(llvm.FloatOLE, lhs.LLVMValue(), rhs.LLVMValue(), "")
		} else {
			result = b.CreateICmp(llvm.IntULE, lhs.LLVMValue(), rhs.LLVMValue(), "")
		}
		return lhs.compiler.NewLLVMValue(result, types.Bool)
	case token.GTR:
		if isfp {
			result = b.CreateFCmp(llvm.FloatOGT, lhs.LLVMValue(), rhs.LLVMValue(), "")
		} else {
			result = b.CreateICmp(llvm.IntUGT, lhs.LLVMValue(), rhs.LLVMValue(), "")
		}
		return lhs.compiler.NewLLVMValue(result, types.Bool)
	case token.GEQ:
		if isfp {
			result = b.CreateFCmp(llvm.FloatOGE, lhs.LLVMValue(), rhs.LLVMValue(), "")
		} else {
			result = b.CreateICmp(llvm.IntUGE, lhs.LLVMValue(), rhs.LLVMValue(), "")
		}
		return lhs.compiler.NewLLVMValue(result, types.Bool)
	case token.AND: // a & b
		result = b.CreateAnd(lhs.LLVMValue(), rhs.LLVMValue(), "")
		return lhs.compiler.NewLLVMValue(result, lhs.typ)
	case token.OR: // a | b
		result = b.CreateOr(lhs.LLVMValue(), rhs.LLVMValue(), "")
		return lhs.compiler.NewLLVMValue(result, lhs.typ)
	case token.XOR: // a ^ b
		result = b.CreateXor(lhs.LLVMValue(), rhs.LLVMValue(), "")
		return lhs.compiler.NewLLVMValue(result, lhs.typ)
	default:
		panic(fmt.Sprint("Unimplemented operator: ", op))
	}
	panic("unreachable")
}
Beispiel #9
0
func (c *compiler) VisitSelectorExpr(expr *ast.SelectorExpr) Value {
	lhs := c.VisitExpr(expr.X)
	if lhs == nil {
		// The only time we should get a nil result is if the object is
		// a package.
		obj := expr.Sel.Obj
		if obj.Kind == ast.Typ {
			return TypeValue{obj.Type.(types.Type)}
		}
		return c.Resolve(obj)
	}

	// TODO(?) record path to field/method during typechecking, so we don't
	// have to search again here.

	name := expr.Sel.Name
	if iface, ok := types.Underlying(lhs.Type()).(*types.Interface); ok {
		i := sort.Search(len(iface.Methods), func(i int) bool {
			return iface.Methods[i].Name >= name
		})
		structValue := lhs.LLVMValue()
		receiver := c.builder.CreateExtractValue(structValue, 0, "")
		f := c.builder.CreateExtractValue(structValue, i+2, "")
		ftype := c.ObjGetType(iface.Methods[i]).(*types.Func)
		method := c.NewLLVMValue(c.builder.CreateBitCast(f, c.types.ToLLVM(ftype), ""), ftype)
		method.receiver = c.NewLLVMValue(receiver, ftype.Recv.Type.(types.Type))
		return method
	}

	// Search through embedded types for field/method.
	var result selectorCandidate
	curr := []selectorCandidate{{nil, lhs.Type()}}
	for result.Type == nil && len(curr) > 0 {
		var next []selectorCandidate
		for _, candidate := range curr {
			indices := candidate.Indices[0:]
			t := candidate.Type

			if p, ok := types.Underlying(t).(*types.Pointer); ok {
				if _, ok := types.Underlying(p.Base).(*types.Struct); ok {
					t = p.Base
				}
			}

			if n, ok := t.(*types.Name); ok {
				i := sort.Search(len(n.Methods), func(i int) bool {
					return n.Methods[i].Name >= name
				})
				if i < len(n.Methods) && n.Methods[i].Name == name {
					result.Indices = indices
					result.Type = t
				}
			}

			if t, ok := types.Underlying(t).(*types.Struct); ok {
				if i, ok := t.FieldIndices[name]; ok {
					result.Indices = append(indices, int(i))
					result.Type = t
				} else {
					// Add embedded types to the next set of types
					// to check.
					for i, field := range t.Fields {
						if field.Name == "" {
							indices = append(indices[0:], i)
							t := field.Type.(types.Type)
							candidate := selectorCandidate{indices, t}
							next = append(next, candidate)
						}
					}
				}
			}
		}
		curr = next
	}

	// Get a pointer to the field/receiver.
	recvValue := lhs.(*LLVMValue)
	if _, ok := types.Underlying(lhs.Type()).(*types.Pointer); !ok {
		recvValue = recvValue.pointer
	}
	recvValue = c.NewLLVMValue(recvValue.LLVMValue(), recvValue.Type())
	if len(result.Indices) > 0 {
		for _, v := range result.Indices {
			ptr := recvValue.LLVMValue()
			field := types.Underlying(types.Deref(recvValue.typ)).(*types.Struct).Fields[v]
			fieldPtr := c.builder.CreateStructGEP(ptr, v, "")
			fieldPtrTyp := &types.Pointer{Base: field.Type.(types.Type)}
			recvValue = c.NewLLVMValue(fieldPtr, fieldPtrTyp)

			// GEP returns a pointer; if the field is a pointer,
			// we must load our pointer-to-a-pointer.
			if _, ok := field.Type.(*types.Pointer); ok {
				recvValue = recvValue.makePointee()
			}
		}
	}
	if !types.Identical(recvValue.typ, expr.Sel.Obj.Type.(types.Type)) {
		recvValue = recvValue.makePointee()
	}

	// Method?
	if expr.Sel.Obj.Kind == ast.Fun {
		method := c.Resolve(expr.Sel.Obj).(*LLVMValue)
		methodType := expr.Sel.Obj.Type.(*types.Func)
		receiverType := methodType.Recv.Type.(types.Type)
		if types.Identical(recvValue.Type(), receiverType) {
			method.receiver = recvValue
		} else if types.Identical(&types.Pointer{Base: recvValue.Type()}, receiverType) {
			method.receiver = recvValue.pointer
		} else {
			method.receiver = recvValue.makePointee()
		}
		return method
	} else {
		return recvValue
	}
	panic("unreachable")
}
Beispiel #10
0
func (v *LLVMValue) Convert(dst_typ types.Type) Value {
	b := v.compiler.builder

	// If it's a stack allocated value, we'll want to compare the
	// value type, not the pointer type.
	src_typ := v.typ

	// Get the underlying type, if any.
	orig_dst_typ := dst_typ
	dst_typ = types.Underlying(dst_typ)
	src_typ = types.Underlying(src_typ)

	// Identical (underlying) types? Just swap in the destination type.
	if types.Identical(src_typ, dst_typ) {
		// TODO avoid load here by reusing pointer value, if exists.
		return v.compiler.NewLLVMValue(v.LLVMValue(), orig_dst_typ)
	}

	// Both pointer types with identical underlying types? Same as above.
	if src_typ, ok := src_typ.(*types.Pointer); ok {
		if dst_typ, ok := dst_typ.(*types.Pointer); ok {
			src_typ := types.Underlying(src_typ.Base)
			dst_typ := types.Underlying(dst_typ.Base)
			if types.Identical(src_typ, dst_typ) {
				return v.compiler.NewLLVMValue(v.LLVMValue(), orig_dst_typ)
			}
		}
	}

	// Convert from an interface type.
	if _, isinterface := src_typ.(*types.Interface); isinterface {
		if interface_, isinterface := dst_typ.(*types.Interface); isinterface {
			result, _ := v.convertI2I(interface_)
			return result
		} else {
			result, _ := v.convertI2V(orig_dst_typ)
			return result
		}
	}

	// Converting to an interface type.
	if interface_, isinterface := dst_typ.(*types.Interface); isinterface {
		return v.convertV2I(interface_)
	}

	// string -> []byte
	byteslice := &types.Slice{Elt: types.Byte}
	if src_typ == types.String && types.Identical(dst_typ, byteslice) {
		c := v.compiler
		value := v.LLVMValue()
		strdata := c.builder.CreateExtractValue(value, 0, "")
		strlen := c.builder.CreateExtractValue(value, 1, "")
		struct_ := llvm.Undef(c.types.ToLLVM(byteslice))
		struct_ = c.builder.CreateInsertValue(struct_, strdata, 0, "")
		struct_ = c.builder.CreateInsertValue(struct_, strlen, 1, "")
		struct_ = c.builder.CreateInsertValue(struct_, strlen, 2, "")
		return c.NewLLVMValue(struct_, byteslice)
	}

	// []byte -> string
	if types.Identical(src_typ, byteslice) && dst_typ == types.String {
		c := v.compiler
		value := v.LLVMValue()
		data := c.builder.CreateExtractValue(value, 0, "")
		len := c.builder.CreateExtractValue(value, 1, "")
		struct_ := llvm.Undef(c.types.ToLLVM(types.String))
		struct_ = c.builder.CreateInsertValue(struct_, data, 0, "")
		struct_ = c.builder.CreateInsertValue(struct_, len, 1, "")
		return c.NewLLVMValue(struct_, types.String)
	}

	// Rune to string conversion.
	if dst_typ == types.String && isIntType(src_typ) {
		return v.runeToString()
	}

	// TODO other special conversions?
	llvm_type := v.compiler.types.ToLLVM(dst_typ)

	// Unsafe pointer conversions.
	if dst_typ == types.UnsafePointer { // X -> unsafe.Pointer
		if _, isptr := src_typ.(*types.Pointer); isptr {
			value := b.CreatePtrToInt(v.LLVMValue(), llvm_type, "")
			return v.compiler.NewLLVMValue(value, orig_dst_typ)
		} else if src_typ == types.Uintptr {
			return v.compiler.NewLLVMValue(v.LLVMValue(), orig_dst_typ)
		}
	} else if src_typ == types.UnsafePointer { // unsafe.Pointer -> X
		if _, isptr := dst_typ.(*types.Pointer); isptr {
			value := b.CreateIntToPtr(v.LLVMValue(), llvm_type, "")
			return v.compiler.NewLLVMValue(value, orig_dst_typ)
		} else if dst_typ == types.Uintptr {
			return v.compiler.NewLLVMValue(v.LLVMValue(), orig_dst_typ)
		}
	}

	// FIXME select the appropriate cast here, depending on size, type (int/float)
	// and sign.
	lv := v.LLVMValue()
	srcType := lv.Type()
	switch srcType.TypeKind() { // source type
	case llvm.IntegerTypeKind:
		switch llvm_type.TypeKind() {
		case llvm.IntegerTypeKind:
			srcBits := srcType.IntTypeWidth()
			dstBits := llvm_type.IntTypeWidth()
			delta := srcBits - dstBits
			switch {
			case delta < 0:
				// TODO check if (un)signed, use S/ZExt accordingly.
				lv = b.CreateZExt(lv, llvm_type, "")
			case delta > 0:
				lv = b.CreateTrunc(lv, llvm_type, "")
			}
			return v.compiler.NewLLVMValue(lv, orig_dst_typ)
		case llvm.FloatTypeKind, llvm.DoubleTypeKind:
			if signed(v.Type()) {
				lv = b.CreateSIToFP(lv, llvm_type, "")
			} else {
				lv = b.CreateUIToFP(lv, llvm_type, "")
			}
			return v.compiler.NewLLVMValue(lv, orig_dst_typ)
		}
	case llvm.DoubleTypeKind:
		switch llvm_type.TypeKind() {
		case llvm.FloatTypeKind:
			lv = b.CreateFPTrunc(lv, llvm_type, "")
			return v.compiler.NewLLVMValue(lv, orig_dst_typ)
		case llvm.IntegerTypeKind:
			if signed(dst_typ) {
				lv = b.CreateFPToSI(lv, llvm_type, "")
			} else {
				lv = b.CreateFPToUI(lv, llvm_type, "")
			}
			return v.compiler.NewLLVMValue(lv, orig_dst_typ)
		}
	case llvm.FloatTypeKind:
		switch llvm_type.TypeKind() {
		case llvm.DoubleTypeKind:
			lv = b.CreateFPExt(lv, llvm_type, "")
			return v.compiler.NewLLVMValue(lv, orig_dst_typ)
		case llvm.IntegerTypeKind:
			if signed(dst_typ) {
				lv = b.CreateFPToSI(lv, llvm_type, "")
			} else {
				lv = b.CreateFPToUI(lv, llvm_type, "")
			}
			return v.compiler.NewLLVMValue(lv, orig_dst_typ)
		}
	}

	// Complex -> complex. Complexes are only convertible to other
	// complexes, contant conversions aside. So we can just check the
	// source type here; given that the types are not identical
	// (checked above), we can assume the destination type is the alternate
	// complex type.
	if src_typ == types.Complex64 || src_typ == types.Complex128 {
		var fpcast func(llvm.Builder, llvm.Value, llvm.Type, string) llvm.Value
		var fptype llvm.Type
		if src_typ == types.Complex64 {
			fpcast = llvm.Builder.CreateFPExt
			fptype = llvm.DoubleType()
		} else {
			fpcast = llvm.Builder.CreateFPTrunc
			fptype = llvm.FloatType()
		}
		if fpcast != nil {
			realv := b.CreateExtractValue(lv, 0, "")
			imagv := b.CreateExtractValue(lv, 1, "")
			realv = fpcast(b, realv, fptype, "")
			imagv = fpcast(b, imagv, fptype, "")
			lv = llvm.Undef(v.compiler.types.ToLLVM(dst_typ))
			lv = b.CreateInsertValue(lv, realv, 0, "")
			lv = b.CreateInsertValue(lv, imagv, 1, "")
			return v.compiler.NewLLVMValue(lv, orig_dst_typ)
		}
	}

	panic(fmt.Sprint("unimplemented conversion: ", v.typ, " -> ", orig_dst_typ))
}
Beispiel #11
0
func (lhs *LLVMValue) BinaryOp(op token.Token, rhs_ Value) Value {
	if op == token.NEQ {
		result := lhs.BinaryOp(token.EQL, rhs_)
		return result.UnaryOp(token.NOT)
	}

	var result llvm.Value
	c := lhs.compiler
	b := lhs.compiler.builder

	// Later we can do better by treating constants specially. For now, let's
	// convert to LLVMValue's.
	var rhs *LLVMValue
	switch rhs_ := rhs_.(type) {
	case *LLVMValue:
		rhs = rhs_
	case NilValue:
		switch rhs_ := rhs_.Convert(lhs.Type()).(type) {
		case ConstValue:
			rhs = c.NewLLVMValue(rhs_.LLVMValue(), rhs_.Type())
		case *LLVMValue:
			rhs = rhs_
		}
	case ConstValue:
		value := rhs_.Convert(lhs.Type())
		rhs = c.NewLLVMValue(value.LLVMValue(), value.Type())
	}

	// Special case for structs.
	// TODO handle strings as an even more special case.
	if struct_type, ok := types.Underlying(lhs.typ).(*types.Struct); ok {
		// TODO check types are the same.

		element_types_count := lhs.LLVMValue().Type().StructElementTypesCount()
		struct_fields := struct_type.Fields

		if element_types_count > 0 {
			t := c.ObjGetType(struct_fields[0])
			first_lhs := c.NewLLVMValue(b.CreateExtractValue(lhs.LLVMValue(), 0, ""), t)
			first_rhs := c.NewLLVMValue(b.CreateExtractValue(rhs.LLVMValue(), 0, ""), t)
			first := first_lhs.BinaryOp(op, first_rhs)

			logical_op := token.LAND
			if op == token.NEQ {
				logical_op = token.LOR
			}

			result := first
			for i := 1; i < element_types_count; i++ {
				t := c.ObjGetType(struct_fields[i])
				next_lhs := c.NewLLVMValue(b.CreateExtractValue(lhs.LLVMValue(), i, ""), t)
				next_rhs := c.NewLLVMValue(b.CreateExtractValue(rhs.LLVMValue(), i, ""), t)
				next := next_lhs.BinaryOp(op, next_rhs)
				result = result.BinaryOp(logical_op, next)
			}
			return result
		}
	}

	// Interfaces.
	if _, ok := types.Underlying(lhs.typ).(*types.Interface); ok {
		// TODO check for interface/interface comparison vs. interface/value comparison.

		// nil comparison
		if /*rhs.LLVMValue().IsConstant() &&*/ rhs.LLVMValue().IsNull() {
			var result llvm.Value
			if op == token.EQL {
				valueNull := b.CreateIsNull(b.CreateExtractValue(lhs.LLVMValue(), 0, ""), "")
				typeNull := b.CreateIsNull(b.CreateExtractValue(lhs.LLVMValue(), 1, ""), "")
				result = b.CreateAnd(typeNull, valueNull, "")
			} else {
				valueNotNull := b.CreateIsNotNull(b.CreateExtractValue(lhs.LLVMValue(), 0, ""), "")
				typeNotNull := b.CreateIsNotNull(b.CreateExtractValue(lhs.LLVMValue(), 1, ""), "")
				result = b.CreateOr(typeNotNull, valueNotNull, "")
			}
			return c.NewLLVMValue(result, types.Bool)
		}

		// First, check that the dynamic types are identical.
		// FIXME provide runtime function for type identity comparison, and
		// value comparisons.
		lhsType := b.CreateExtractValue(lhs.LLVMValue(), 1, "")
		rhsType := b.CreateExtractValue(rhs.LLVMValue(), 1, "")
		diff := b.CreatePtrDiff(lhsType, rhsType, "")
		zero := llvm.ConstNull(diff.Type())

		var result llvm.Value
		if op == token.EQL {
			typesIdentical := b.CreateICmp(llvm.IntEQ, diff, zero, "")
			//valuesEqual := ...
			//result = b.CreateAnd(typesIdentical, valuesEqual, "")
			result = typesIdentical
		} else {
			typesDifferent := b.CreateICmp(llvm.IntNE, diff, zero, "")
			//valuesUnequal := ...
			//result = b.CreateOr(typesDifferent, valuesUnequal, "")
			result = typesDifferent
		}
		return c.NewLLVMValue(result, types.Bool)
	}

	if types.Underlying(lhs.typ) == types.String {
		if types.Underlying(rhs.typ) == types.String {
			switch op {
			case token.ADD:
				return c.concatenateStrings(lhs, rhs)
			case token.EQL, token.LSS, token.GTR, token.LEQ, token.GEQ:
				return c.compareStrings(lhs, rhs, op)
			default:
				panic(fmt.Sprint("Unimplemented operator: ", op))
			}
		}
		panic("unimplemented")
	}

	// Determine whether to use integer or floating point instructions.
	// TODO determine the NaN rules.
	isfp := types.Identical(types.Underlying(lhs.typ), types.Float32) ||
		types.Identical(types.Underlying(lhs.typ), types.Float64)

	switch op {
	case token.MUL:
		result = b.CreateMul(lhs.LLVMValue(), rhs.LLVMValue(), "")
		return lhs.compiler.NewLLVMValue(result, lhs.typ)
	case token.QUO:
		result = b.CreateUDiv(lhs.LLVMValue(), rhs.LLVMValue(), "")
		return lhs.compiler.NewLLVMValue(result, lhs.typ)
	case token.ADD:
		result = b.CreateAdd(lhs.LLVMValue(), rhs.LLVMValue(), "")
		return lhs.compiler.NewLLVMValue(result, lhs.typ)
	case token.SUB:
		result = b.CreateSub(lhs.LLVMValue(), rhs.LLVMValue(), "")
		return lhs.compiler.NewLLVMValue(result, lhs.typ)
	case token.NEQ:
		if isfp {
			result = b.CreateFCmp(llvm.FloatONE, lhs.LLVMValue(), rhs.LLVMValue(), "")
		} else {
			result = b.CreateICmp(llvm.IntNE, lhs.LLVMValue(), rhs.LLVMValue(), "")
		}
		return lhs.compiler.NewLLVMValue(result, types.Bool)
	case token.EQL:
		result = b.CreateICmp(llvm.IntEQ, lhs.LLVMValue(), rhs.LLVMValue(), "")
		return lhs.compiler.NewLLVMValue(result, types.Bool)
	case token.LSS:
		result = b.CreateICmp(llvm.IntULT, lhs.LLVMValue(), rhs.LLVMValue(), "")
		return lhs.compiler.NewLLVMValue(result, types.Bool)
	case token.LEQ: // TODO signed/unsigned
		result = b.CreateICmp(llvm.IntULE, lhs.LLVMValue(), rhs.LLVMValue(), "")
		return lhs.compiler.NewLLVMValue(result, types.Bool)
	case token.GTR:
		result = b.CreateICmp(llvm.IntUGT, lhs.LLVMValue(), rhs.LLVMValue(), "")
		return lhs.compiler.NewLLVMValue(result, types.Bool)
	case token.GEQ:
		result = b.CreateICmp(llvm.IntUGE, lhs.LLVMValue(), rhs.LLVMValue(), "")
		return lhs.compiler.NewLLVMValue(result, types.Bool)
	case token.LAND:
		// FIXME change this to branch
		result = b.CreateAnd(lhs.LLVMValue(), rhs.LLVMValue(), "")
		return lhs.compiler.NewLLVMValue(result, types.Bool)
	case token.LOR:
		// FIXME change this to branch
		result = b.CreateOr(lhs.LLVMValue(), rhs.LLVMValue(), "")
		return lhs.compiler.NewLLVMValue(result, types.Bool)
	default:
		panic(fmt.Sprint("Unimplemented operator: ", op))
	}
	panic("unreachable")
}
Beispiel #12
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
}