func (tm *llvmTypeMap) basicLLVMType(b *types.Basic) llvm.Type { switch b.Kind() { case types.Bool: return llvm.Int1Type() case types.Int8, types.Uint8: return llvm.Int8Type() case types.Int16, types.Uint16: return llvm.Int16Type() case types.Int32, types.Uint32: return llvm.Int32Type() case types.Uint, types.Int: return tm.inttype case types.Int64, types.Uint64: return llvm.Int64Type() case types.Float32: return llvm.FloatType() case types.Float64: return llvm.DoubleType() case types.UnsafePointer, types.Uintptr: return tm.target.IntPtrType() case types.Complex64: f32 := llvm.FloatType() elements := []llvm.Type{f32, f32} return llvm.StructType(elements, false) case types.Complex128: f64 := llvm.DoubleType() elements := []llvm.Type{f64, f64} return llvm.StructType(elements, false) case types.String: i8ptr := llvm.PointerType(llvm.Int8Type(), 0) elements := []llvm.Type{i8ptr, tm.inttype} return llvm.StructType(elements, false) } panic(fmt.Sprint("unhandled kind: ", b.Kind)) }
func (c *compiler) printValues(println_ bool, values ...Value) { var args []llvm.Value = nil if len(values) > 0 { format := "" args = make([]llvm.Value, 0, len(values)+1) for i, value := range values { llvm_value := value.LLVMValue() typ := value.Type().Underlying() if name, isname := typ.(*types.Named); isname { typ = name.Underlying() } if println_ && i > 0 { format += " " } switch typ := typ.(type) { case *types.Basic: switch typ.Kind() { case types.Uint8: format += "%hhu" case types.Uint16: format += "%hu" case types.Uint32: format += "%u" case types.Uintptr, types.Uint: format += "%lu" case types.Uint64: format += "%llu" // FIXME windows case types.Int: format += "%ld" case types.Int8: format += "%hhd" case types.Int16: format += "%hd" case types.Int32: format += "%d" case types.Int64: format += "%lld" // FIXME windows case types.Float32: llvm_value = c.builder.CreateFPExt(llvm_value, llvm.DoubleType(), "") fallthrough case types.Float64: printfloat := c.runtime.printfloat.LLVMValue() args := []llvm.Value{llvm_value} llvm_value = c.builder.CreateCall(printfloat, args, "") fallthrough case types.String, types.UntypedString: ptrval := c.builder.CreateExtractValue(llvm_value, 0, "") lenval := c.builder.CreateExtractValue(llvm_value, 1, "") llvm_value = ptrval args = append(args, lenval) format += "%.*s" case types.Bool: format += "%s" llvm_value = c.getBoolString(llvm_value) case types.UnsafePointer: format += "%p" default: panic(fmt.Sprint("Unhandled Basic Kind: ", typ.Kind)) } case *types.Interface: format += "(0x%lx,0x%lx)" ival := c.builder.CreateExtractValue(llvm_value, 0, "") itype := c.builder.CreateExtractValue(llvm_value, 1, "") args = append(args, ival) llvm_value = itype case *types.Slice, *types.Array: // If we see a constant array, we either: // Create an internal constant if it's a constant array, or // Create space on the stack and store it there. init_ := value.(*LLVMValue) init_value := init_.LLVMValue() llvm_value = c.builder.CreateAlloca(init_value.Type(), "") c.builder.CreateStore(init_value, llvm_value) // FIXME don't assume string... format += "%s" case *types.Pointer: format += "0x%lx" default: panic(fmt.Sprintf("Unhandled type kind: %s (%T)", typ, typ)) } args = append(args, llvm_value) } if println_ { format += "\n" } formatval := c.builder.CreateGlobalStringPtr(format, "") args = append([]llvm.Value{formatval}, args...) } else { var format string if println_ { format = "\n" } args = []llvm.Value{c.builder.CreateGlobalStringPtr(format, "")} } printf := getPrintf(c.module.Module) c.NewValue(c.builder.CreateCall(printf, args, ""), types.Typ[types.Int32]) fflush := getFflush(c.module.Module) fileptr := llvm.ConstNull(fflush.Type().ElementType().ParamTypes()[0]) c.builder.CreateCall(fflush, []llvm.Value{fileptr}, "") }
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.Identical(srctyp, dsttyp) { 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.Identical(srctyp, dsttyp) { return v.compiler.NewValue(v.LLVMValue(), origdsttyp) } } } 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.Identical(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.createMalloc(strlen) memcpy := c.runtime.memcpy.LLVMValue() c.builder.CreateCall(memcpy, []llvm.Value{ newdata, c.builder.CreatePtrToInt(strdata, c.target.IntPtrType(), ""), strlen, }, "") strdata = c.builder.CreateIntToPtr(newdata, strdata.Type(), "") 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.Identical(dsttyp, runeslice) { return v.stringToRuneSlice() } } // []byte -> string if types.Identical(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.createMalloc(len) memcpy := c.runtime.memcpy.LLVMValue() c.builder.CreateCall(memcpy, []llvm.Value{ newdata, c.builder.CreatePtrToInt(data, c.target.IntPtrType(), ""), len, }, "") data = c.builder.CreateIntToPtr(newdata, data.Type(), "") 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.Identical(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: 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 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(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(v.compiler.types.ToLLVM(dsttyp)) lv = b.CreateInsertValue(lv, realv, 0, "") lv = b.CreateInsertValue(lv, imagv, 1, "") return v.compiler.NewValue(lv, origdsttyp) } } panic(fmt.Sprintf("unimplemented conversion: %s (%s) -> %s", v.typ, lv.Type(), origdsttyp)) }