func (v *LLVMValue) Convert(dsttyp 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. 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.IsIdentical(srctyp, dsttyp) { // A method converted to a function type without the // receiver is where we convert a "method value" into a // function. if srctyp, ok := srctyp.(*types.Signature); ok && srctyp.Recv() != nil { if dsttyp, ok := dsttyp.(*types.Signature); ok && dsttyp.Recv() == nil { return v.convertMethodValue(origdsttyp) } } // TODO avoid load here by reusing pointer value, if exists. return v.compiler.NewValue(v.LLVMValue(), 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.IsIdentical(srctyp, dsttyp) { return v.compiler.NewValue(v.LLVMValue(), origdsttyp) } } } // Convert from an interface type. if _, isinterface := srctyp.(*types.Interface); isinterface { if interface_, isinterface := dsttyp.(*types.Interface); isinterface { return v.mustConvertI2I(interface_) } else { return v.mustConvertI2V(origdsttyp) } } // Converting to an interface type. if interface_, isinterface := dsttyp.(*types.Interface); isinterface { return v.convertV2I(interface_) } byteslice := types.NewSlice(types.Typ[types.Byte]) runeslice := types.NewSlice(types.Typ[types.Rune]) // string -> if isString(srctyp) { // (untyped) string -> string // XXX should untyped strings be able to escape go/types? if isString(dsttyp) { return v.compiler.NewValue(v.LLVMValue(), origdsttyp) } // string -> []byte if types.IsIdentical(dsttyp, byteslice) { c := v.compiler value := v.LLVMValue() strdata := c.builder.CreateExtractValue(value, 0, "") strlen := c.builder.CreateExtractValue(value, 1, "") // Data must be copied, to prevent changes in // the byte slice from mutating the string. newdata := c.builder.CreateArrayMalloc(strdata.Type().ElementType(), strlen, "") memcpy := c.NamedFunction("runtime.memcpy", "func(uintptr, uintptr, uintptr)") c.builder.CreateCall(memcpy, []llvm.Value{ c.builder.CreatePtrToInt(newdata, c.target.IntPtrType(), ""), c.builder.CreatePtrToInt(strdata, c.target.IntPtrType(), ""), strlen, }, "") strdata = newdata 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.NewValue(struct_, byteslice) } // string -> []rune if types.IsIdentical(dsttyp, runeslice) { return v.stringToRuneSlice() } } // []byte -> string if types.IsIdentical(srctyp, byteslice) && isString(dsttyp) { c := v.compiler value := v.LLVMValue() data := c.builder.CreateExtractValue(value, 0, "") len := c.builder.CreateExtractValue(value, 1, "") // Data must be copied, to prevent changes in // the byte slice from mutating the string. newdata := c.builder.CreateArrayMalloc(data.Type().ElementType(), len, "") memcpy := c.NamedFunction("runtime.memcpy", "func(uintptr, uintptr, uintptr)") c.builder.CreateCall(memcpy, []llvm.Value{ c.builder.CreatePtrToInt(newdata, c.target.IntPtrType(), ""), c.builder.CreatePtrToInt(data, c.target.IntPtrType(), ""), len, }, "") data = newdata struct_ := llvm.Undef(c.types.ToLLVM(types.Typ[types.String])) struct_ = c.builder.CreateInsertValue(struct_, data, 0, "") struct_ = c.builder.CreateInsertValue(struct_, len, 1, "") return c.NewValue(struct_, types.Typ[types.String]) } // []rune -> string if types.IsIdentical(srctyp, runeslice) && isString(dsttyp) { return v.runeSliceToString() } // rune -> string if isString(dsttyp) && isInteger(srctyp) { return v.runeToString() } // TODO other special conversions? llvm_type := v.compiler.types.ToLLVM(dsttyp) // Unsafe pointer conversions. if dsttyp == types.Typ[types.UnsafePointer] { // X -> unsafe.Pointer if _, isptr := srctyp.(*types.Pointer); isptr { value := b.CreatePtrToInt(v.LLVMValue(), llvm_type, "") return v.compiler.NewValue(value, origdsttyp) } else if srctyp == types.Typ[types.Uintptr] { return v.compiler.NewValue(v.LLVMValue(), origdsttyp) } } else if srctyp == types.Typ[types.UnsafePointer] { // unsafe.Pointer -> X if _, isptr := dsttyp.(*types.Pointer); isptr { value := b.CreateIntToPtr(v.LLVMValue(), llvm_type, "") return v.compiler.NewValue(value, origdsttyp) } else if dsttyp == types.Typ[types.Uintptr] { return v.compiler.NewValue(v.LLVMValue(), origdsttyp) } } lv := v.LLVMValue() 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: // 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.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 v.compiler.NewValue(lv, origdsttyp) } case llvm.DoubleTypeKind: switch llvm_type.TypeKind() { case llvm.FloatTypeKind: lv = b.CreateFPTrunc(lv, llvm_type, "") return v.compiler.NewValue(lv, origdsttyp) case llvm.IntegerTypeKind: if !isUnsigned(dsttyp) { lv = b.CreateFPToSI(lv, llvm_type, "") } else { lv = b.CreateFPToUI(lv, llvm_type, "") } return v.compiler.NewValue(lv, origdsttyp) } case llvm.FloatTypeKind: switch llvm_type.TypeKind() { case llvm.DoubleTypeKind: lv = b.CreateFPExt(lv, llvm_type, "") return v.compiler.NewValue(lv, origdsttyp) case llvm.IntegerTypeKind: if !isUnsigned(dsttyp) { lv = b.CreateFPToSI(lv, llvm_type, "") } else { lv = b.CreateFPToUI(lv, llvm_type, "") } return v.compiler.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(*Builder, llvm.Value, llvm.Type, string) llvm.Value var fptype llvm.Type if srctyp == types.Typ[types.Complex64] { fpcast = (*Builder).CreateFPExt fptype = llvm.DoubleType() } else { fpcast = (*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(dsttyp)) lv = b.CreateInsertValue(lv, realv, 0, "") lv = b.CreateInsertValue(lv, imagv, 1, "") return v.compiler.NewValue(lv, origdsttyp) } } srcstr := v.compiler.types.TypeString(v.typ) dststr := v.compiler.types.TypeString(origdsttyp) panic(fmt.Sprintf("unimplemented conversion: %s -> %s", srcstr, dststr)) }