Exemplo n.º 1
0
Arquivo: cabi.go Projeto: hinike/llgo
func (ri *directRetInfo) encode(ctx llvm.Context, allocaBuilder llvm.Builder, builder llvm.Builder, vals []llvm.Value) {
	if len(ri.retTypes) == 0 {
		builder.CreateRetVoid()
		return
	}

	var val llvm.Value
	switch ri.numResults {
	case 1:
		val = vals[0]
	default:
		val = llvm.Undef(ri.resultsType)
		for i, v := range vals {
			val = builder.CreateInsertValue(val, v, i, "")
		}
	}

	args := make([]llvm.Value, len(ri.retTypes))
	directEncode(ctx, allocaBuilder, builder, ri.retTypes, args, val)

	var retval llvm.Value
	switch len(ri.retTypes) {
	case 1:
		retval = args[0]
	default:
		retval = llvm.Undef(ctx.StructType(ri.retTypes, false))
		for i, a := range args {
			retval = builder.CreateInsertValue(retval, a, i, "")
		}
	}
	builder.CreateRet(retval)
}
Exemplo n.º 2
0
Arquivo: value.go Projeto: hinike/llgo
func (fr *frame) unaryOp(v *govalue, op token.Token) *govalue {
	switch op {
	case token.SUB:
		var value llvm.Value
		if isComplex(v.typ) {
			realv := fr.builder.CreateExtractValue(v.value, 0, "")
			imagv := fr.builder.CreateExtractValue(v.value, 1, "")
			negzero := llvm.ConstFloatFromString(realv.Type(), "-0")
			realv = fr.builder.CreateFSub(negzero, realv, "")
			imagv = fr.builder.CreateFSub(negzero, imagv, "")
			value = llvm.Undef(v.value.Type())
			value = fr.builder.CreateInsertValue(value, realv, 0, "")
			value = fr.builder.CreateInsertValue(value, imagv, 1, "")
		} else if isFloat(v.typ) {
			negzero := llvm.ConstFloatFromString(fr.types.ToLLVM(v.Type()), "-0")
			value = fr.builder.CreateFSub(negzero, v.value, "")
		} else {
			value = fr.builder.CreateNeg(v.value, "")
		}
		return newValue(value, v.typ)
	case token.ADD:
		return v // No-op
	case token.NOT:
		value := fr.builder.CreateXor(v.value, boolLLVMValue(true), "")
		return newValue(value, v.typ)
	case token.XOR:
		lhs := v.value
		rhs := llvm.ConstAllOnes(lhs.Type())
		value := fr.builder.CreateXor(lhs, rhs, "")
		return newValue(value, v.typ)
	default:
		panic(fmt.Sprintf("Unhandled operator: %s", op))
	}
}
Exemplo n.º 3
0
func (c *Codegen) generateVarDecl(node *parser.VarDeclNode, global bool) {
	t := c.getLLVMType(node.Type)
	name := node.Name.Value
	if c.scope.Declared(name) {
		// Error name has already been declared
	}

	var alloc, val llvm.Value
	if node.Value == nil {
		if t.TypeKind() == llvm.PointerTypeKind {
			val = c.convert(c.scope.GetValue("null"), t)
		} else {
			val = llvm.Undef(t)
		}
	} else {
		val = c.convert(c.generateExpression(node.Value), t)
	}

	if !global {
		alloc = c.builder.CreateAlloca(t, name)
		c.builder.CreateStore(val, alloc)
	} else {
		alloc = llvm.AddGlobal(c.module, t, name)
		alloc.SetInitializer(val)
	}

	c.scope.AddVariable(name, alloc)
}
Exemplo n.º 4
0
Arquivo: codegen.go Projeto: vnev/ark
func (v *Codegen) genDefaultValue(typ parser.Type) llvm.Value {
	atyp := typ.ActualType()

	// Generate default struct values
	if structType, ok := atyp.(parser.StructType); ok {
		lit := createStructInitializer(typ)
		if lit != nil {
			return v.genStructLiteral(lit)
		} else {
			return llvm.Undef(v.typeToLLVMType(structType))
		}
	}

	if tupleType, ok := atyp.(parser.TupleType); ok {
		values := make([]llvm.Value, len(tupleType.Members))
		for idx, member := range tupleType.Members {
			values[idx] = v.genDefaultValue(member)
		}
		return llvm.ConstStruct(values, false)
	}

	if atyp.IsIntegerType() || atyp == parser.PRIMITIVE_bool {
		return llvm.ConstInt(v.typeToLLVMType(atyp), 0, false)
	}

	if atyp.IsFloatingType() {
		return llvm.ConstFloat(v.typeToLLVMType(atyp), 0)
	}

	panic("type does not have default value: " + atyp.TypeName())
}
Exemplo n.º 5
0
Arquivo: ssa.go Projeto: hinike/llgo
func (fr *frame) callBuiltin(typ types.Type, builtin *ssa.Builtin, args []ssa.Value) []*govalue {
	switch builtin.Name() {
	case "print", "println":
		llargs := make([]*govalue, len(args))
		for i, arg := range args {
			llargs[i] = fr.value(arg)
		}
		fr.printValues(builtin.Name() == "println", llargs...)
		return nil

	case "panic":
		fr.callPanic(fr.value(args[0]))
		return nil

	case "recover":
		return []*govalue{fr.callRecover(false)}

	case "append":
		return []*govalue{fr.callAppend(fr.value(args[0]), fr.value(args[1]))}

	case "close":
		fr.chanClose(fr.value(args[0]))
		return nil

	case "cap":
		return []*govalue{fr.callCap(fr.value(args[0]))}

	case "len":
		return []*govalue{fr.callLen(fr.value(args[0]))}

	case "copy":
		return []*govalue{fr.callCopy(fr.value(args[0]), fr.value(args[1]))}

	case "delete":
		fr.mapDelete(fr.value(args[0]), fr.value(args[1]))
		return nil

	case "real":
		return []*govalue{fr.extractRealValue(fr.value(args[0]))}

	case "imag":
		return []*govalue{fr.extractImagValue(fr.value(args[0]))}

	case "complex":
		r := fr.llvmvalue(args[0])
		i := fr.llvmvalue(args[1])
		cmplx := llvm.Undef(fr.llvmtypes.ToLLVM(typ))
		cmplx = fr.builder.CreateInsertValue(cmplx, r, 0, "")
		cmplx = fr.builder.CreateInsertValue(cmplx, i, 1, "")
		return []*govalue{newValue(cmplx, typ)}

	case "ssa:wrapnilchk":
		ptr := fr.value(args[0])
		fr.nilCheck(args[0], ptr.value)
		return []*govalue{ptr}

	default:
		panic("unimplemented: " + builtin.Name())
	}
}
Exemplo n.º 6
0
func (c *compiler) createInitMainFunction(mainPkg *ssa.Package) {
	int8ptr := llvm.PointerType(c.types.ctx.Int8Type(), 0)
	ftyp := llvm.FunctionType(llvm.VoidType(), []llvm.Type{int8ptr}, false)
	initMain := llvm.AddFunction(c.module.Module, "__go_init_main", ftyp)
	c.addCommonFunctionAttrs(initMain)
	entry := llvm.AddBasicBlock(initMain, "entry")

	builder := llvm.GlobalContext().NewBuilder()
	defer builder.Dispose()
	builder.SetInsertPointAtEnd(entry)

	args := []llvm.Value{llvm.Undef(int8ptr)}

	if !c.GccgoABI {
		initfn := c.module.Module.NamedFunction("main..import")
		if !initfn.IsNil() {
			builder.CreateCall(initfn, args, "")
		}
		builder.CreateRetVoid()
		return
	}

	initdata := c.buildPackageInitData(mainPkg)

	for _, init := range initdata.Inits {
		initfn := c.module.Module.NamedFunction(init.InitFunc)
		if initfn.IsNil() {
			initfn = llvm.AddFunction(c.module.Module, init.InitFunc, ftyp)
		}
		builder.CreateCall(initfn, args, "")
	}

	builder.CreateRetVoid()
}
Exemplo n.º 7
0
// emitInitPrologue emits the init-specific function prologue (guard check and
// initialization of dependent packages under the llgo native ABI), and returns
// the basic block into which the GC registration call should be emitted.
func (fr *frame) emitInitPrologue() llvm.BasicBlock {
	if fr.GccgoABI {
		return fr.builder.GetInsertBlock()
	}

	initGuard := llvm.AddGlobal(fr.module.Module, llvm.Int1Type(), "init$guard")
	initGuard.SetLinkage(llvm.InternalLinkage)
	initGuard.SetInitializer(llvm.ConstNull(llvm.Int1Type()))

	returnBlock := llvm.AddBasicBlock(fr.function, "")
	initBlock := llvm.AddBasicBlock(fr.function, "")

	initGuardVal := fr.builder.CreateLoad(initGuard, "")
	fr.builder.CreateCondBr(initGuardVal, returnBlock, initBlock)

	fr.builder.SetInsertPointAtEnd(returnBlock)
	fr.builder.CreateRetVoid()

	fr.builder.SetInsertPointAtEnd(initBlock)
	fr.builder.CreateStore(llvm.ConstInt(llvm.Int1Type(), 1, false), initGuard)
	int8ptr := llvm.PointerType(fr.types.ctx.Int8Type(), 0)
	ftyp := llvm.FunctionType(llvm.VoidType(), []llvm.Type{int8ptr}, false)
	for _, pkg := range fr.pkg.Object.Imports() {
		initname := ManglePackagePath(pkg.Path()) + "..import"
		initfn := fr.module.Module.NamedFunction(initname)
		if initfn.IsNil() {
			initfn = llvm.AddFunction(fr.module.Module, initname, ftyp)
		}
		args := []llvm.Value{llvm.Undef(int8ptr)}
		fr.builder.CreateCall(initfn, args, "")
	}

	return initBlock
}
Exemplo n.º 8
0
func (fr *frame) makeInterfaceFromPointer(vptr llvm.Value, vty types.Type, iface types.Type) *govalue {
	i8ptr := llvm.PointerType(llvm.Int8Type(), 0)
	llv := fr.builder.CreateBitCast(vptr, i8ptr, "")
	value := llvm.Undef(fr.types.ToLLVM(iface))
	itab := fr.types.getItabPointer(vty, iface.Underlying().(*types.Interface))
	value = fr.builder.CreateInsertValue(value, itab, 0, "")
	value = fr.builder.CreateInsertValue(value, llv, 1, "")
	return newValue(value, iface)
}
Exemplo n.º 9
0
// convertI2E converts a non-empty interface value to an empty interface.
func (fr *frame) convertI2E(v *govalue) *govalue {
	td := fr.getInterfaceTypeDescriptor(v)
	val := fr.builder.CreateExtractValue(v.value, 1, "")

	typ := types.NewInterface(nil, nil)
	intf := llvm.Undef(fr.types.ToLLVM(typ))
	intf = fr.builder.CreateInsertValue(intf, td, 0, "")
	intf = fr.builder.CreateInsertValue(intf, val, 1, "")
	return newValue(intf, typ)
}
Exemplo n.º 10
0
Arquivo: codegen.go Projeto: vnev/ark
func (v *Codegen) genTupleLiteral(n *parser.TupleLiteral) llvm.Value {
	tupleLLVMType := v.typeToLLVMType(n.Type)

	tupleValue := llvm.Undef(tupleLLVMType)
	for idx, mem := range n.Members {
		memberValue := v.genExpr(mem)

		if !v.inFunction() && !memberValue.IsConstant() {
			v.err("Encountered non-constant value in global tuple literal")
		}

		tupleValue = v.builder().CreateInsertValue(tupleValue, memberValue, idx, "")
	}

	return tupleValue
}
Exemplo n.º 11
0
func (fr *frame) changeInterface(v *govalue, ty types.Type, assert bool) *govalue {
	td := fr.getInterfaceTypeDescriptor(v)
	tytd := fr.types.ToRuntime(ty)
	var itab llvm.Value
	if assert {
		itab = fr.runtime.assertInterface.call(fr, tytd, td)[0]
	} else {
		itab = fr.runtime.convertInterface.call(fr, tytd, td)[0]
	}
	val := fr.builder.CreateExtractValue(v.value, 1, "")

	intf := llvm.Undef(fr.types.ToLLVM(ty))
	intf = fr.builder.CreateInsertValue(intf, itab, 0, "")
	intf = fr.builder.CreateInsertValue(intf, val, 1, "")
	return newValue(intf, ty)
}
Exemplo n.º 12
0
Arquivo: codegen.go Projeto: vnev/ark
func (v *Codegen) genEnumLiteral(n *parser.EnumLiteral) llvm.Value {
	enumType := n.Type.ActualType().(parser.EnumType)
	enumLLVMType := v.typeToLLVMType(n.Type)

	memberIdx := enumType.MemberIndex(n.Member)
	member := enumType.Members[memberIdx]

	if enumType.Simple {
		return llvm.ConstInt(enumLLVMType, uint64(member.Tag), false)
	}

	// TODO: Handle other integer size, maybe dynamic depending on max value?
	tagValue := llvm.ConstInt(llvm.IntType(32), uint64(member.Tag), false)

	enumValue := llvm.Undef(enumLLVMType)
	enumValue = v.builder().CreateInsertValue(enumValue, tagValue, 0, "")

	memberLLVMType := v.typeToLLVMType(member.Type)

	var memberValue llvm.Value
	if n.TupleLiteral != nil {
		memberValue = v.genTupleLiteral(n.TupleLiteral)
	} else if n.CompositeLiteral != nil {
		memberValue = v.genCompositeLiteral(n.CompositeLiteral)
	}

	if v.inFunction() {
		alloc := v.builder().CreateAlloca(enumLLVMType, "")

		tagGep := v.builder().CreateStructGEP(alloc, 0, "")
		v.builder().CreateStore(tagValue, tagGep)

		if !memberValue.IsNil() {
			dataGep := v.builder().CreateStructGEP(alloc, 1, "")

			dataGep = v.builder().CreateBitCast(dataGep, llvm.PointerType(memberLLVMType, 0), "")

			v.builder().CreateStore(memberValue, dataGep)
		}

		return v.builder().CreateLoad(alloc, "")
	} else {
		panic("unimplemented: global enum literal")
	}
}
Exemplo n.º 13
0
func (fi *functionTypeInfo) call(ctx llvm.Context, allocaBuilder llvm.Builder, builder llvm.Builder, callee llvm.Value, chain llvm.Value, args []llvm.Value) []llvm.Value {
	callArgs := make([]llvm.Value, len(fi.argAttrs))
	if chain.C == nil {
		chain = llvm.Undef(llvm.PointerType(ctx.Int8Type(), 0))
	}
	callArgs[fi.chainIndex] = chain
	for i, a := range args {
		fi.argInfos[i].encode(ctx, allocaBuilder, builder, callArgs, a)
	}
	fi.retInf.prepare(ctx, allocaBuilder, callArgs)
	typedCallee := builder.CreateBitCast(callee, llvm.PointerType(fi.functionType, 0), "")
	call := builder.CreateCall(typedCallee, callArgs, "")
	call.AddInstrAttribute(0, fi.retAttr)
	for i, a := range fi.argAttrs {
		call.AddInstrAttribute(i+1, a)
	}
	return fi.retInf.decode(ctx, allocaBuilder, builder, call)
}
Exemplo n.º 14
0
Arquivo: codegen.go Projeto: vnev/ark
// Allocates a literal array on the stack
func (v *Codegen) genArrayLiteral(n *parser.CompositeLiteral) llvm.Value {
	arrayLLVMType := v.typeToLLVMType(n.Type)
	memberLLVMType := v.typeToLLVMType(n.Type.ActualType().(parser.ArrayType).MemberType)

	arrayValues := make([]llvm.Value, len(n.Values))
	for idx, mem := range n.Values {
		value := v.genExpr(mem)
		if !v.inFunction() && !value.IsConstant() {
			v.err("Encountered non-constant value in global array")
		}
		arrayValues[idx] = value
	}

	lengthValue := llvm.ConstInt(v.typeToLLVMType(parser.PRIMITIVE_uint), uint64(len(n.Values)), false)
	var backingArrayPointer llvm.Value

	if v.inFunction() {
		// allocate backing array
		backingArray := v.builder().CreateAlloca(llvm.ArrayType(memberLLVMType, len(n.Values)), "")

		// copy the constant array to the backing array
		for idx, value := range arrayValues {
			gep := v.builder().CreateStructGEP(backingArray, idx, "")
			v.builder().CreateStore(value, gep)
		}

		backingArrayPointer = v.builder().CreateBitCast(backingArray, llvm.PointerType(memberLLVMType, 0), "")
	} else {
		backName := fmt.Sprintf("_globarr_back_%d", v.arrayIndex)
		v.arrayIndex++

		backingArray := llvm.AddGlobal(v.curFile.LlvmModule, llvm.ArrayType(memberLLVMType, len(n.Values)), backName)
		backingArray.SetLinkage(llvm.InternalLinkage)
		backingArray.SetGlobalConstant(false)
		backingArray.SetInitializer(llvm.ConstArray(memberLLVMType, arrayValues))

		backingArrayPointer = llvm.ConstBitCast(backingArray, llvm.PointerType(memberLLVMType, 0))
	}

	structValue := llvm.Undef(arrayLLVMType)
	structValue = v.builder().CreateInsertValue(structValue, lengthValue, 0, "")
	structValue = v.builder().CreateInsertValue(structValue, backingArrayPointer, 1, "")
	return structValue
}
Exemplo n.º 15
0
func (v *Codegen) genStructLiteral(n *parser.StructLiteral) llvm.Value {
	structType := n.Type.ActualType().(*parser.StructType)
	structLLVMType := v.typeToLLVMType(structType)

	structValue := llvm.Undef(structLLVMType)

	for name, value := range n.Values {
		vari := structType.GetVariableDecl(name).Variable
		idx := structType.VariableIndex(vari)

		memberValue := v.genExpr(value)
		if !v.inFunction && !memberValue.IsConstant() {
			v.err("Encountered non-constant value in global struct literal")
		}

		structValue = v.builder.CreateInsertValue(structValue, v.genExpr(value), idx, "")
	}

	return structValue
}
Exemplo n.º 16
0
Arquivo: codegen.go Projeto: vnev/ark
func (v *Codegen) genStringLiteral(n *parser.StringLiteral) llvm.Value {
	memberLLVMType := v.typeToLLVMType(parser.PRIMITIVE_u8)
	nullTerm := n.IsCString
	length := len(n.Value)
	if nullTerm {
		length++
	}

	var backingArrayPointer llvm.Value

	if v.inFunction() {
		// allocate backing array
		backingArray := v.builder().CreateAlloca(llvm.ArrayType(memberLLVMType, length), "stackstr")
		v.builder().CreateStore(llvm.ConstString(n.Value, nullTerm), backingArray)

		backingArrayPointer = v.builder().CreateBitCast(backingArray, llvm.PointerType(memberLLVMType, 0), "")
	} else {
		backName := fmt.Sprintf("_globarr_back_%d", v.arrayIndex)
		v.arrayIndex++

		backingArray := llvm.AddGlobal(v.curFile.LlvmModule, llvm.ArrayType(memberLLVMType, length), backName)
		backingArray.SetLinkage(llvm.InternalLinkage)
		backingArray.SetGlobalConstant(false)
		backingArray.SetInitializer(llvm.ConstString(n.Value, nullTerm))

		backingArrayPointer = llvm.ConstBitCast(backingArray, llvm.PointerType(memberLLVMType, 0))
	}

	if n.Type.ActualType().Equals(parser.ArrayOf(parser.PRIMITIVE_u8)) {
		lengthValue := llvm.ConstInt(v.typeToLLVMType(parser.PRIMITIVE_uint), uint64(length), false)
		structValue := llvm.Undef(v.typeToLLVMType(n.Type))
		structValue = v.builder().CreateInsertValue(structValue, lengthValue, 0, "")
		structValue = v.builder().CreateInsertValue(structValue, backingArrayPointer, 1, "")
		return structValue
	} else {
		return backingArrayPointer
	}
}
Exemplo n.º 17
0
func (fr *frame) slice(x llvm.Value, xtyp types.Type, low, high, max llvm.Value) llvm.Value {
	if !low.IsNil() {
		low = fr.createZExtOrTrunc(low, fr.types.inttype, "")
	} else {
		low = llvm.ConstNull(fr.types.inttype)
	}
	if !high.IsNil() {
		high = fr.createZExtOrTrunc(high, fr.types.inttype, "")
	}
	if !max.IsNil() {
		max = fr.createZExtOrTrunc(max, fr.types.inttype, "")
	}

	var arrayptr, arraylen, arraycap llvm.Value
	var elemtyp types.Type
	var errcode uint64
	switch typ := xtyp.Underlying().(type) {
	case *types.Pointer: // *array
		errcode = gccgoRuntimeErrorARRAY_SLICE_OUT_OF_BOUNDS
		arraytyp := typ.Elem().Underlying().(*types.Array)
		elemtyp = arraytyp.Elem()
		arrayptr = x
		arrayptr = fr.builder.CreateBitCast(arrayptr, llvm.PointerType(llvm.Int8Type(), 0), "")
		arraylen = llvm.ConstInt(fr.llvmtypes.inttype, uint64(arraytyp.Len()), false)
		arraycap = arraylen
	case *types.Slice:
		errcode = gccgoRuntimeErrorSLICE_SLICE_OUT_OF_BOUNDS
		elemtyp = typ.Elem()
		arrayptr = fr.builder.CreateExtractValue(x, 0, "")
		arraylen = fr.builder.CreateExtractValue(x, 1, "")
		arraycap = fr.builder.CreateExtractValue(x, 2, "")
	case *types.Basic:
		if high.IsNil() {
			high = llvm.ConstAllOnes(fr.types.inttype) // -1
		}
		result := fr.runtime.stringSlice.call(fr, x, low, high)
		return result[0]
	default:
		panic("unimplemented")
	}
	if high.IsNil() {
		high = arraylen
	}
	if max.IsNil() {
		max = arraycap
	}

	// Bounds checking: 0 <= low <= high <= max <= cap
	zero := llvm.ConstNull(fr.types.inttype)
	l0 := fr.builder.CreateICmp(llvm.IntSLT, low, zero, "")
	hl := fr.builder.CreateICmp(llvm.IntSLT, high, low, "")
	mh := fr.builder.CreateICmp(llvm.IntSLT, max, high, "")
	cm := fr.builder.CreateICmp(llvm.IntSLT, arraycap, max, "")

	cond := fr.builder.CreateOr(l0, hl, "")
	cond = fr.builder.CreateOr(cond, mh, "")
	cond = fr.builder.CreateOr(cond, cm, "")

	fr.condBrRuntimeError(cond, errcode)

	slicelen := fr.builder.CreateSub(high, low, "")
	slicecap := fr.builder.CreateSub(max, low, "")

	elemsize := llvm.ConstInt(fr.llvmtypes.inttype, uint64(fr.llvmtypes.Sizeof(elemtyp)), false)
	offset := fr.builder.CreateMul(low, elemsize, "")

	sliceptr := fr.builder.CreateInBoundsGEP(arrayptr, []llvm.Value{offset}, "")

	llslicetyp := fr.llvmtypes.sliceBackendType().ToLLVM(fr.llvmtypes.ctx)
	sliceValue := llvm.Undef(llslicetyp)
	sliceValue = fr.builder.CreateInsertValue(sliceValue, sliceptr, 0, "")
	sliceValue = fr.builder.CreateInsertValue(sliceValue, slicelen, 1, "")
	sliceValue = fr.builder.CreateInsertValue(sliceValue, slicecap, 2, "")

	return sliceValue
}
Exemplo n.º 18
0
Arquivo: value.go Projeto: hinike/llgo
// newValueFromConst converts a constant value to an LLVM value.
func (fr *frame) newValueFromConst(v exact.Value, typ types.Type) *govalue {
	switch {
	case v == nil:
		llvmtyp := fr.types.ToLLVM(typ)
		return newValue(llvm.ConstNull(llvmtyp), typ)

	case isString(typ):
		if isUntyped(typ) {
			typ = types.Typ[types.String]
		}
		llvmtyp := fr.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(fr.module.Module, init.Type(), "")
			ptr.SetInitializer(init)
			ptr.SetLinkage(llvm.InternalLinkage)
			ptr = llvm.ConstBitCast(ptr, i8ptr)
		} else {
			ptr = llvm.ConstNull(i8ptr)
		}
		len_ := llvm.ConstInt(fr.types.inttype, uint64(strlen), false)
		llvmvalue := llvm.Undef(llvmtyp)
		llvmvalue = llvm.ConstInsertValue(llvmvalue, ptr, []uint32{0})
		llvmvalue = llvm.ConstInsertValue(llvmvalue, len_, []uint32{1})
		return newValue(llvmvalue, typ)

	case isInteger(typ):
		if isUntyped(typ) {
			typ = types.Typ[types.Int]
		}
		llvmtyp := fr.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 newValue(llvmvalue, typ)

	case isBoolean(typ):
		if isUntyped(typ) {
			typ = types.Typ[types.Bool]
		}
		return newValue(boolLLVMValue(exact.BoolVal(v)), typ)

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

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

	case isComplex(typ):
		if isUntyped(typ) {
			typ = types.Typ[types.Complex128]
		}
		llvmtyp := fr.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 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 := fr.newValueFromConst(v, types.Typ[types.String])
			return fr.convert(strval, typ)
		}
	}

	panic(fmt.Sprintf("unhandled: t=%s(%T), v=%v(%T)", typ, typ, v, v))
}
Exemplo n.º 19
0
Arquivo: value.go Projeto: hinike/llgo
func (fr *frame) convert(v *govalue, dsttyp types.Type) *govalue {
	b := fr.builder

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

	// Get the underlying type, if any.
	origdsttyp := dsttyp
	dsttyp = dsttyp.Underlying()
	srctyp = srctyp.Underlying()

	// Identical (underlying) types? Just swap in the destination type.
	if types.Identical(srctyp, dsttyp) {
		return newValue(v.value, origdsttyp)
	}

	// Both pointer types with identical underlying types? Same as above.
	if srctyp, ok := srctyp.(*types.Pointer); ok {
		if dsttyp, ok := dsttyp.(*types.Pointer); ok {
			srctyp := srctyp.Elem().Underlying()
			dsttyp := dsttyp.Elem().Underlying()
			if types.Identical(srctyp, dsttyp) {
				return newValue(v.value, origdsttyp)
			}
		}
	}

	// string ->
	if isString(srctyp) {
		// (untyped) string -> string
		// XXX should untyped strings be able to escape go/types?
		if isString(dsttyp) {
			return newValue(v.value, origdsttyp)
		}

		// string -> []byte
		if isSlice(dsttyp, types.Byte) {
			value := v.value
			strdata := fr.builder.CreateExtractValue(value, 0, "")
			strlen := fr.builder.CreateExtractValue(value, 1, "")

			// Data must be copied, to prevent changes in
			// the byte slice from mutating the string.
			newdata := fr.createMalloc(strlen, false)
			fr.memcpy(newdata, strdata, strlen)

			struct_ := llvm.Undef(fr.types.ToLLVM(dsttyp))
			struct_ = fr.builder.CreateInsertValue(struct_, newdata, 0, "")
			struct_ = fr.builder.CreateInsertValue(struct_, strlen, 1, "")
			struct_ = fr.builder.CreateInsertValue(struct_, strlen, 2, "")
			return newValue(struct_, origdsttyp)
		}

		// string -> []rune
		if isSlice(dsttyp, types.Rune) {
			return fr.stringToRuneSlice(v)
		}
	}

	// []byte -> string
	if isSlice(srctyp, types.Byte) && isString(dsttyp) {
		value := v.value
		data := fr.builder.CreateExtractValue(value, 0, "")
		len := fr.builder.CreateExtractValue(value, 1, "")

		// Data must be copied, to prevent changes in
		// the byte slice from mutating the string.
		newdata := fr.createMalloc(len, false)
		fr.memcpy(newdata, data, len)

		struct_ := llvm.Undef(fr.types.ToLLVM(types.Typ[types.String]))
		struct_ = fr.builder.CreateInsertValue(struct_, newdata, 0, "")
		struct_ = fr.builder.CreateInsertValue(struct_, len, 1, "")
		return newValue(struct_, types.Typ[types.String])
	}

	// []rune -> string
	if isSlice(srctyp, types.Rune) && isString(dsttyp) {
		return fr.runeSliceToString(v)
	}

	// rune -> string
	if isString(dsttyp) && isInteger(srctyp) {
		return fr.runeToString(v)
	}

	// Unsafe pointer conversions.
	llvm_type := fr.types.ToLLVM(dsttyp)
	if dsttyp == types.Typ[types.UnsafePointer] { // X -> unsafe.Pointer
		if _, isptr := srctyp.(*types.Pointer); isptr {
			return newValue(v.value, origdsttyp)
		} else if srctyp == types.Typ[types.Uintptr] {
			value := b.CreateIntToPtr(v.value, llvm_type, "")
			return newValue(value, origdsttyp)
		}
	} else if srctyp == types.Typ[types.UnsafePointer] { // unsafe.Pointer -> X
		if _, isptr := dsttyp.(*types.Pointer); isptr {
			return newValue(v.value, origdsttyp)
		} else if dsttyp == types.Typ[types.Uintptr] {
			value := b.CreatePtrToInt(v.value, llvm_type, "")
			return newValue(value, origdsttyp)
		}
	}

	lv := v.value
	srcType := lv.Type()
	switch srcType.TypeKind() {
	case llvm.IntegerTypeKind:
		switch llvm_type.TypeKind() {
		case llvm.IntegerTypeKind:
			srcBits := srcType.IntTypeWidth()
			dstBits := llvm_type.IntTypeWidth()
			delta := srcBits - dstBits
			switch {
			case delta < 0:
				if !isUnsigned(srctyp) {
					lv = b.CreateSExt(lv, llvm_type, "")
				} else {
					lv = b.CreateZExt(lv, llvm_type, "")
				}
			case delta > 0:
				lv = b.CreateTrunc(lv, llvm_type, "")
			}
			return newValue(lv, origdsttyp)
		case llvm.FloatTypeKind, llvm.DoubleTypeKind:
			if !isUnsigned(v.Type()) {
				lv = b.CreateSIToFP(lv, llvm_type, "")
			} else {
				lv = b.CreateUIToFP(lv, llvm_type, "")
			}
			return newValue(lv, origdsttyp)
		}
	case llvm.DoubleTypeKind:
		switch llvm_type.TypeKind() {
		case llvm.FloatTypeKind:
			lv = b.CreateFPTrunc(lv, llvm_type, "")
			return newValue(lv, origdsttyp)
		case llvm.IntegerTypeKind:
			if !isUnsigned(dsttyp) {
				lv = b.CreateFPToSI(lv, llvm_type, "")
			} else {
				lv = b.CreateFPToUI(lv, llvm_type, "")
			}
			return newValue(lv, origdsttyp)
		}
	case llvm.FloatTypeKind:
		switch llvm_type.TypeKind() {
		case llvm.DoubleTypeKind:
			lv = b.CreateFPExt(lv, llvm_type, "")
			return newValue(lv, origdsttyp)
		case llvm.IntegerTypeKind:
			if !isUnsigned(dsttyp) {
				lv = b.CreateFPToSI(lv, llvm_type, "")
			} else {
				lv = b.CreateFPToUI(lv, llvm_type, "")
			}
			return newValue(lv, origdsttyp)
		}
	}

	// 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 isComplex(srctyp) {
		var fpcast func(llvm.Builder, llvm.Value, llvm.Type, string) llvm.Value
		var fptype llvm.Type
		if srctyp == types.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(fr.types.ToLLVM(dsttyp))
			lv = b.CreateInsertValue(lv, realv, 0, "")
			lv = b.CreateInsertValue(lv, imagv, 1, "")
			return newValue(lv, origdsttyp)
		}
	}
	panic(fmt.Sprintf("unimplemented conversion: %s (%s) -> %s", v.typ, lv.Type(), origdsttyp))
}