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 (tm *TypeMap) basicLLVMType(b *types.Basic) llvm.Type { switch b.Kind { case types.BoolKind: return llvm.Int1Type() case types.Int8Kind, types.Uint8Kind: return llvm.Int8Type() case types.Int16Kind, types.Uint16Kind: return llvm.Int16Type() case types.Int32Kind, types.Uint32Kind: return llvm.Int32Type() case types.Int64Kind, types.Uint64Kind: return llvm.Int64Type() case types.Float32Kind: return llvm.FloatType() case types.Float64Kind: return llvm.DoubleType() case types.UnsafePointerKind, types.UintptrKind, types.UintKind, types.IntKind: return tm.target.IntPtrType() //case Complex64: TODO //case Complex128: //case UntypedInt: //case UntypedFloat: //case UntypedComplex: case types.StringKind: i8ptr := llvm.PointerType(llvm.Int8Type(), 0) elements := []llvm.Type{i8ptr, llvm.Int32Type()} return llvm.StructType(elements, false) } panic(fmt.Sprint("unhandled kind: ", b.Kind)) }
func (v ConstValue) LLVMValue() llvm.Value { typ := types.Underlying(v.Type()) switch typ { case types.Int, types.Uint: return llvm.ConstInt(llvm.Int32Type(), uint64(v.Int64()), true) // TODO 32/64bit (probably wait for gc) //int_val := v.Val.(*big.Int) //if int_val.Cmp(maxBigInt32) > 0 || int_val.Cmp(minBigInt32) < 0 { // panic(fmt.Sprint("const ", int_val, " overflows int")) //} //return llvm.ConstInt(v.compiler.target.IntPtrType(), uint64(v.Int64()), true) case types.Uint: return llvm.ConstInt(llvm.Int32Type(), uint64(v.Int64()), false) case types.Int8: return llvm.ConstInt(llvm.Int8Type(), uint64(v.Int64()), true) case types.Uint8, types.Byte: return llvm.ConstInt(llvm.Int8Type(), uint64(v.Int64()), false) case types.Int16: return llvm.ConstInt(llvm.Int16Type(), uint64(v.Int64()), true) case types.Uint16: return llvm.ConstInt(llvm.Int16Type(), uint64(v.Int64()), false) case types.Int32, types.Rune: return llvm.ConstInt(llvm.Int32Type(), uint64(v.Int64()), true) case types.Uint32: return llvm.ConstInt(llvm.Int32Type(), uint64(v.Int64()), false) case types.Int64: return llvm.ConstInt(llvm.Int64Type(), uint64(v.Int64()), true) case types.Uint64: return llvm.ConstInt(llvm.Int64Type(), uint64(v.Int64()), true) case types.Float32: return llvm.ConstFloat(llvm.FloatType(), float64(v.Float64())) case types.Float64: return llvm.ConstFloat(llvm.DoubleType(), float64(v.Float64())) case types.UnsafePointer, types.Uintptr: inttype := v.compiler.target.IntPtrType() return llvm.ConstInt(inttype, uint64(v.Int64()), false) case types.String: strval := (v.Val).(string) ptr := v.compiler.builder.CreateGlobalStringPtr(strval, "") len_ := llvm.ConstInt(llvm.Int32Type(), uint64(len(strval)), false) return llvm.ConstStruct([]llvm.Value{ptr, len_}, false) case types.Bool: if v := v.Val.(bool); v { return llvm.ConstAllOnes(llvm.Int1Type()) } return llvm.ConstNull(llvm.Int1Type()) } panic(fmt.Errorf("Unhandled type: %v", typ)) //v.typ.Kind)) }
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)) }
func (c *compiler) printValues(println_ bool, values ...Value) 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.NamedFunction("runtime.printfloat", "func f(float64) string") 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) if init_.pointer != nil { llvm_value = init_.pointer.LLVMValue() } else { 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) result := c.NewValue(c.builder.CreateCall(printf, args, ""), types.Typ[types.Int32]) fflush := c.NamedFunction("fflush", "func f(*int32) int32") c.builder.CreateCall(fflush, []llvm.Value{llvm.ConstNull(llvm.PointerType(llvm.Int32Type(), 0))}, "") return result }
func (v ConstValue) LLVMValue() llvm.Value { typ := types.Underlying(v.Type()) if name, ok := typ.(*types.Name); ok { typ = name.Underlying } switch typ.(*types.Basic).Kind { case types.IntKind, types.UintKind: return llvm.ConstInt(llvm.Int32Type(), uint64(v.Int64()), true) // TODO 32/64bit (probably wait for gc) //int_val := v.Val.(*big.Int) //if int_val.Cmp(maxBigInt32) > 0 || int_val.Cmp(minBigInt32) < 0 { // panic(fmt.Sprint("const ", int_val, " overflows int")) //} //return llvm.ConstInt(v.compiler.target.IntPtrType(), uint64(v.Int64()), true) case types.Int8Kind: return llvm.ConstInt(llvm.Int8Type(), uint64(v.Int64()), true) case types.Uint8Kind: return llvm.ConstInt(llvm.Int8Type(), uint64(v.Int64()), false) case types.Int16Kind: return llvm.ConstInt(llvm.Int16Type(), uint64(v.Int64()), true) case types.Uint16Kind: return llvm.ConstInt(llvm.Int16Type(), uint64(v.Int64()), false) case types.Int32Kind: return llvm.ConstInt(llvm.Int32Type(), uint64(v.Int64()), true) case types.Uint32Kind: return llvm.ConstInt(llvm.Int32Type(), uint64(v.Int64()), false) case types.Int64Kind: return llvm.ConstInt(llvm.Int64Type(), uint64(v.Int64()), true) case types.Uint64Kind: return llvm.ConstInt(llvm.Int64Type(), uint64(v.Int64()), false) case types.Float32Kind: return llvm.ConstFloat(llvm.FloatType(), float64(v.Float64())) case types.Float64Kind: return llvm.ConstFloat(llvm.DoubleType(), float64(v.Float64())) case types.Complex64Kind: r_, i_ := v.Complex() r := llvm.ConstFloat(llvm.FloatType(), r_) i := llvm.ConstFloat(llvm.FloatType(), i_) return llvm.ConstStruct([]llvm.Value{r, i}, false) case types.Complex128Kind: r_, i_ := v.Complex() r := llvm.ConstFloat(llvm.DoubleType(), r_) i := llvm.ConstFloat(llvm.DoubleType(), i_) return llvm.ConstStruct([]llvm.Value{r, i}, false) case types.UnsafePointerKind, types.UintptrKind: inttype := v.compiler.target.IntPtrType() return llvm.ConstInt(inttype, uint64(v.Int64()), false) case types.StringKind: strval := (v.Val).(string) strlen := len(strval) i8ptr := llvm.PointerType(llvm.Int8Type(), 0) var ptr llvm.Value if strlen > 0 { ptr = v.compiler.builder.CreateGlobalStringPtr(strval, "") ptr = llvm.ConstBitCast(ptr, i8ptr) } else { ptr = llvm.ConstNull(i8ptr) } len_ := llvm.ConstInt(llvm.Int32Type(), uint64(strlen), false) return llvm.ConstStruct([]llvm.Value{ptr, len_}, false) case types.BoolKind: if v := v.Val.(bool); v { return llvm.ConstAllOnes(llvm.Int1Type()) } return llvm.ConstNull(llvm.Int1Type()) } panic(fmt.Errorf("Unhandled type: %v", typ)) //v.typ.Kind)) }
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)) }
func (c *compiler) printValues(println_ bool, values ...Value) 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 := types.Underlying(value.Type()) if name, isname := typ.(*types.Name); isname { typ = name.Underlying } if println_ && i > 0 { format += " " } switch typ := typ.(type) { case *types.Basic: switch typ.Kind { case types.UintKind: format += "%u" // TODO make 32/64-bit case types.Uint8Kind: format += "%hhu" case types.Uint16Kind: format += "%hu" case types.Uint32Kind, types.UintptrKind: // FIXME uintptr to become bitwidth dependent format += "%u" case types.Uint64Kind: format += "%llu" // FIXME windows case types.IntKind: format += "%d" // TODO make 32/64-bit case types.Int8Kind: format += "%hhd" case types.Int16Kind: format += "%hd" case types.Int32Kind: format += "%d" case types.Int64Kind: format += "%lld" // FIXME windows case types.Float32Kind: llvm_value = c.builder.CreateFPExt(llvm_value, llvm.DoubleType(), "") fallthrough case types.Float64Kind: // Doesn't match up with gc's formatting, which allocates // a minimum of three digits for the exponent. printfloat := c.NamedFunction("runtime.printfloat", "func f(float64) string") args := []llvm.Value{llvm_value} llvm_value = c.builder.CreateCall(printfloat, args, "") fallthrough case types.StringKind: 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.BoolKind: format += "%s" llvm_value = c.getBoolString(llvm_value) case types.UnsafePointerKind: 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 init_value := init_.LLVMValue() switch init_.(type) { case ConstValue: llvm_value = llvm.AddGlobal(c.module.Module, init_value.Type(), "") llvm_value.SetInitializer(init_value) llvm_value.SetGlobalConstant(true) case *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%x" 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) result := c.NewLLVMValue(c.builder.CreateCall(printf, args, ""), types.Int32) fflush := c.NamedFunction("fflush", "func f(*int32) int32") c.builder.CreateCall(fflush, []llvm.Value{llvm.ConstNull(llvm.PointerType(llvm.Int32Type(), 0))}, "") return result }