func primitiveTypeToLLVMType(typ parser.PrimitiveType) llvm.Type { switch typ { case parser.PRIMITIVE_int, parser.PRIMITIVE_uint: return llvm.IntType(intSize * 8) case parser.PRIMITIVE_s8, parser.PRIMITIVE_u8: return llvm.IntType(8) case parser.PRIMITIVE_s16, parser.PRIMITIVE_u16: return llvm.IntType(16) case parser.PRIMITIVE_s32, parser.PRIMITIVE_u32: return llvm.IntType(32) case parser.PRIMITIVE_s64, parser.PRIMITIVE_u64: return llvm.IntType(64) case parser.PRIMITIVE_i128, parser.PRIMITIVE_u128: return llvm.IntType(128) case parser.PRIMITIVE_f32: return llvm.FloatType() case parser.PRIMITIVE_f64: return llvm.DoubleType() case parser.PRIMITIVE_f128: return llvm.FP128Type() case parser.PRIMITIVE_rune: // runes are signed 32-bit int return llvm.IntType(32) case parser.PRIMITIVE_bool: return llvm.IntType(1) case parser.PRIMITIVE_str: return llvm.PointerType(llvm.IntType(8), 0) default: panic("Unimplemented primitive type in LLVM codegen") } }
func (v *Codegen) primitiveTypeToLLVMType(typ parser.PrimitiveType) llvm.Type { switch typ { case parser.PRIMITIVE_int, parser.PRIMITIVE_uint: return v.targetData.IntPtrType() case parser.PRIMITIVE_s8, parser.PRIMITIVE_u8: return llvm.IntType(8) case parser.PRIMITIVE_s16, parser.PRIMITIVE_u16: return llvm.IntType(16) case parser.PRIMITIVE_s32, parser.PRIMITIVE_u32: return llvm.IntType(32) case parser.PRIMITIVE_s64, parser.PRIMITIVE_u64: return llvm.IntType(64) case parser.PRIMITIVE_s128, parser.PRIMITIVE_u128: return llvm.IntType(128) case parser.PRIMITIVE_f32: return llvm.FloatType() case parser.PRIMITIVE_f64: return llvm.DoubleType() case parser.PRIMITIVE_f128: return llvm.FP128Type() case parser.PRIMITIVE_rune: // runes are signed 32-bit int return llvm.IntType(32) case parser.PRIMITIVE_bool: return llvm.IntType(1) case parser.PRIMITIVE_void: return llvm.VoidType() default: panic("Unimplemented primitive type in LLVM codegen") } }
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)) }
package codegen import ( "log" "github.com/furryfaust/lyca/src/parser" "llvm.org/llvm/bindings/go/llvm" ) var PRIMITIVE_TYPES = map[string]llvm.Type{ "int": llvm.Int32Type(), "char": llvm.Int8Type(), "float": llvm.FloatType(), "boolean": llvm.Int1Type(), } var null llvm.Value = llvm.Value{} func (c *Codegen) getLLVMFuncType(ret parser.Node, params []*parser.VarDeclNode, obj llvm.Type) llvm.Type { p := make([]llvm.Type, 0) if obj != llvm.VoidType() { p = append(p, obj) } for _, v := range params { p = append(p, c.getLLVMType(v.Type)) } return llvm.FunctionType(c.getLLVMType(ret), p, false) } func (c *Codegen) getLLVMType(node parser.Node) llvm.Type { switch t := node.(type) { /*