func (v *LLVMValue) UnaryOp(op token.Token) Value { b := v.compiler.builder switch op { case token.SUB: var value llvm.Value isfp := types.Identical(types.Underlying(v.typ), types.Float32) || types.Identical(types.Underlying(v.typ), types.Float64) if isfp { zero := llvm.ConstNull(v.compiler.types.ToLLVM(v.Type())) value = b.CreateFSub(zero, v.LLVMValue(), "") } else { value = b.CreateNeg(v.LLVMValue(), "") } return v.compiler.NewLLVMValue(value, v.typ) case token.ADD: return v // No-op case token.AND: return v.pointer case token.NOT: value := b.CreateNot(v.LLVMValue(), "") return v.compiler.NewLLVMValue(value, v.typ) case token.XOR: lhs := v.LLVMValue() rhs := llvm.ConstAllOnes(lhs.Type()) value := b.CreateXor(lhs, rhs, "") return v.compiler.NewLLVMValue(value, v.typ) default: panic("Unhandled operator: ") // + expr.Op) } panic("unreachable") }
func (v ConstValue) Convert(dst_typ types.Type) Value { // Get the underlying type, if any. if name, isname := dst_typ.(*types.Name); isname { dst_typ = types.Underlying(name) } if !types.Identical(v.typ, dst_typ) { // Get the Basic type. isBasic := false if name, isname := types.Underlying(dst_typ).(*types.Name); isname { _, isBasic = name.Underlying.(*types.Basic) } compiler := v.compiler if isBasic { return ConstValue{*v.Const.Convert(&dst_typ), compiler, dst_typ} } else { return compiler.NewLLVMValue(v.LLVMValue(), v.Type()).Convert(dst_typ) //panic(fmt.Errorf("unhandled conversion from %v to %v", v.typ, dst_typ)) } } else { // TODO convert to dst type. ConstValue may need to change to allow // storage of types other than Basic. } return v }
func (v ConstValue) Convert(dstTyp types.Type) Value { // Get the underlying type, if any. origDstTyp := dstTyp dstTyp = types.Underlying(dstTyp) if !types.Identical(v.typ, dstTyp) { isBasic := false if name, isname := types.Underlying(dstTyp).(*types.Name); isname { _, isBasic = name.Underlying.(*types.Basic) } compiler := v.compiler if isBasic { return ConstValue{v.Const.Convert(&dstTyp), compiler, origDstTyp} } else { return compiler.NewLLVMValue(v.LLVMValue(), v.Type()).Convert(origDstTyp) //panic(fmt.Errorf("unhandled conversion from %v to %v", v.typ, dstTyp)) } } else { v.typ = origDstTyp } return v }
func (c *compiler) VisitSelectorExpr(expr *ast.SelectorExpr) Value { lhs := c.VisitExpr(expr.X) if lhs == nil { // The only time we should get a nil result is if the object is // a package. obj := expr.Sel.Obj if obj.Kind == ast.Typ { return TypeValue{obj.Type.(types.Type)} } return c.Resolve(obj) } // Method expression. Returns an unbound function pointer. // FIXME this is just the most basic case. It's also possible to // create a pointer-receiver function from a method that has a // value receiver (see Method Expressions in spec). name := expr.Sel.Name if _, ok := lhs.(TypeValue); ok { methodobj := expr.Sel.Obj value := c.Resolve(methodobj).(*LLVMValue) ftyp := value.typ.(*types.Func) methodParams := make(types.ObjList, len(ftyp.Params)+1) methodParams[0] = ftyp.Recv copy(methodParams[1:], ftyp.Params) ftyp = &types.Func{ Recv: nil, Params: methodParams, Results: ftyp.Results, IsVariadic: ftyp.IsVariadic, } return c.NewLLVMValue(value.value, ftyp) } // TODO(?) record path to field/method during typechecking, so we don't // have to search again here. if iface, ok := types.Underlying(lhs.Type()).(*types.Interface); ok { i := sort.Search(len(iface.Methods), func(i int) bool { return iface.Methods[i].Name >= name }) structValue := lhs.LLVMValue() receiver := c.builder.CreateExtractValue(structValue, 1, "") f := c.builder.CreateExtractValue(structValue, i+2, "") i8ptr := &types.Pointer{Base: types.Int8} ftype := iface.Methods[i].Type.(*types.Func) ftype.Recv = ast.NewObj(ast.Var, "") ftype.Recv.Type = i8ptr f = c.builder.CreateBitCast(f, c.types.ToLLVM(ftype), "") ftype.Recv = nil method := c.NewLLVMValue(f, ftype) method.receiver = c.NewLLVMValue(receiver, i8ptr) return method } // Search through embedded types for field/method. var result selectorCandidate curr := []selectorCandidate{{nil, lhs.Type()}} for result.Type == nil && len(curr) > 0 { var next []selectorCandidate for _, candidate := range curr { indices := candidate.Indices[0:] t := candidate.Type if p, ok := types.Underlying(t).(*types.Pointer); ok { if _, ok := types.Underlying(p.Base).(*types.Struct); ok { t = p.Base } } if n, ok := t.(*types.Name); ok { i := sort.Search(len(n.Methods), func(i int) bool { return n.Methods[i].Name >= name }) if i < len(n.Methods) && n.Methods[i].Name == name { result.Indices = indices result.Type = t } } if t, ok := types.Underlying(t).(*types.Struct); ok { if i, ok := t.FieldIndices[name]; ok { result.Indices = append(indices, int(i)) result.Type = t } else { // Add embedded types to the next set of types // to check. for i, field := range t.Fields { if field.Name == "" { indices = append(indices[0:], i) t := field.Type.(types.Type) candidate := selectorCandidate{indices, t} next = append(next, candidate) } } } } } curr = next } // Get a pointer to the field/receiver. recvValue := lhs.(*LLVMValue) if len(result.Indices) > 0 { if _, ok := types.Underlying(lhs.Type()).(*types.Pointer); !ok { recvValue = recvValue.pointer //recvValue = c.NewLLVMValue(recvValue.LLVMValue(), recvValue.Type()) } for _, v := range result.Indices { ptr := recvValue.LLVMValue() field := types.Underlying(types.Deref(recvValue.typ)).(*types.Struct).Fields[v] fieldPtr := c.builder.CreateStructGEP(ptr, v, "") fieldPtrTyp := &types.Pointer{Base: field.Type.(types.Type)} recvValue = c.NewLLVMValue(fieldPtr, fieldPtrTyp) // GEP returns a pointer; if the field is a pointer, // we must load our pointer-to-a-pointer. if _, ok := field.Type.(*types.Pointer); ok { recvValue = recvValue.makePointee() } } } // Method? if expr.Sel.Obj.Kind == ast.Fun { method := c.Resolve(expr.Sel.Obj).(*LLVMValue) methodType := expr.Sel.Obj.Type.(*types.Func) receiverType := methodType.Recv.Type.(types.Type) if types.Identical(recvValue.Type(), receiverType) { method.receiver = recvValue } else if types.Identical(&types.Pointer{Base: recvValue.Type()}, receiverType) { method.receiver = recvValue.pointer } else { method.receiver = recvValue.makePointee() } return method } else { resultType := expr.Sel.Obj.Type.(types.Type) if types.Identical(recvValue.Type(), resultType) { // no-op } else if types.Identical(&types.Pointer{Base: recvValue.Type()}, resultType) { recvValue = recvValue.pointer } else { recvValue = recvValue.makePointee() } return recvValue } panic("unreachable") }
func (c *compiler) VisitSelectorExpr(expr *ast.SelectorExpr) Value { lhs := c.VisitExpr(expr.X) if lhs == nil { // The only time we should get a nil result is if the object is // a package. obj := expr.Sel.Obj if obj.Kind == ast.Typ { return TypeValue{obj.Type.(types.Type)} } return c.Resolve(obj) } // TODO(?) record path to field/method during typechecking, so we don't // have to search again here. name := expr.Sel.Name if iface, ok := types.Underlying(lhs.Type()).(*types.Interface); ok { // validity checked during typechecking. i := sort.Search(len(iface.Methods), func(i int) bool { return iface.Methods[i].Name >= name }) struct_value := lhs.LLVMValue() receiver_value := c.builder.CreateStructGEP(struct_value, 0, "") fn_value := c.builder.CreateStructGEP(struct_value, i+2, "") method_type := c.ObjGetType(iface.Methods[i]).(*types.Func) method := c.NewLLVMValue( c.builder.CreateBitCast( c.builder.CreateLoad(fn_value, ""), c.types.ToLLVM(method_type), ""), method_type) method.receiver = c.NewLLVMValue( c.builder.CreateLoad(receiver_value, ""), method_type.Recv.Type.(types.Type)) return method } // Search through embedded types for field/method. var result selectorCandidate curr := []selectorCandidate{{nil, lhs.Type()}} for result.Type == nil && len(curr) > 0 { var next []selectorCandidate for _, candidate := range curr { indices := candidate.Indices[0:] t := candidate.Type if p, ok := types.Underlying(t).(*types.Pointer); ok { if _, ok := types.Underlying(p.Base).(*types.Struct); ok { indices = append(indices, 0) t = p.Base } } if n, ok := t.(*types.Name); ok { i := sort.Search(len(n.Methods), func(i int) bool { return n.Methods[i].Name >= name }) if i < len(n.Methods) && n.Methods[i].Name == name { result.Indices = indices result.Type = t } } if t, ok := types.Underlying(t).(*types.Struct); ok { if i, ok := t.FieldIndices[name]; ok { result.Indices = append(indices, i) result.Type = t } else { // Add embedded types to the next set of types // to check. for i, field := range t.Fields { if field.Name == "" { indices = append(indices[0:], uint64(i)) t := field.Type.(types.Type) candidate := selectorCandidate{indices, t} next = append(next, candidate) } } } } } curr = next } // Get a pointer to the field/struct for field/method invocation. indices := make([]llvm.Value, len(result.Indices)) for i, v := range result.Indices { indices[i] = llvm.ConstInt(llvm.Int32Type(), v, false) } // Method? if expr.Sel.Obj.Kind == ast.Fun { method := c.Resolve(expr.Sel.Obj).(*LLVMValue) methodType := expr.Sel.Obj.Type.(*types.Func) receiverType := methodType.Recv.Type.(types.Type) if len(indices) > 0 { receiverValue := c.builder.CreateGEP(lhs.LLVMValue(), indices, "") if types.Identical(result.Type, receiverType) { receiverValue = c.builder.CreateLoad(receiverValue, "") } method.receiver = c.NewLLVMValue(receiverValue, receiverType) } else { lhs := lhs.(*LLVMValue) if types.Identical(result.Type, receiverType) { method.receiver = lhs } else if types.Identical(result.Type, &types.Pointer{Base: receiverType}) { method.receiver = lhs.makePointee() } else if types.Identical(&types.Pointer{Base: result.Type}, receiverType) { method.receiver = lhs.pointer } } return method } else { var ptr llvm.Value if _, ok := types.Underlying(lhs.Type()).(*types.Pointer); ok { ptr = lhs.LLVMValue() } else { if lhs, ok := lhs.(*LLVMValue); ok && lhs.pointer != nil { ptr = lhs.pointer.LLVMValue() zero := llvm.ConstNull(llvm.Int32Type()) indices = append([]llvm.Value{zero}, indices...) } else { // TODO handle struct literal selectors. panic("selectors on struct literals unimplemented") } } fieldValue := c.builder.CreateGEP(ptr, indices, "") fieldType := &types.Pointer{Base: expr.Sel.Obj.Type.(types.Type)} return c.NewLLVMValue(fieldValue, fieldType).makePointee() } panic("unreachable") }
// convertV2I converts a value to an interface. func (v *LLVMValue) convertV2I(iface *types.Interface) Value { // TODO deref indirect value, then use 'pointer' as pointer value. var srcname *types.Name srctyp := v.Type() if name, isname := srctyp.(*types.Name); isname { srcname = name srctyp = name.Underlying } if p, fromptr := srctyp.(*types.Pointer); fromptr { srctyp = p.Base if name, isname := srctyp.(*types.Name); isname { srcname = name srctyp = name.Underlying } } iface_struct_type := v.compiler.types.ToLLVM(iface) element_types := iface_struct_type.StructElementTypes() zero_iface_struct := llvm.ConstNull(iface_struct_type) iface_struct := zero_iface_struct builder := v.compiler.builder var ptr llvm.Value lv := v.LLVMValue() var overwide bool if lv.Type().TypeKind() == llvm.PointerTypeKind { ptr = builder.CreateBitCast(lv, element_types[1], "") } else { // If the value fits exactly in a pointer, then we can just // bitcast it. Otherwise we need to malloc, and create a shim // function to load the receiver. c := v.compiler ptrsize := c.target.PointerSize() if c.target.TypeStoreSize(lv.Type()) <= uint64(ptrsize) { bits := c.target.TypeSizeInBits(lv.Type()) if bits > 0 { lv = c.coerce(lv, llvm.IntType(int(bits))) ptr = builder.CreateIntToPtr(lv, element_types[1], "") } else { ptr = llvm.ConstNull(element_types[1]) } } else { ptr = c.createTypeMalloc(v.compiler.types.ToLLVM(srctyp)) builder.CreateStore(lv, ptr) ptr = builder.CreateBitCast(ptr, element_types[1], "") overwide = true } } runtimeType := v.compiler.types.ToRuntime(v.Type()) runtimeType = builder.CreateBitCast(runtimeType, element_types[0], "") iface_struct = builder.CreateInsertValue(iface_struct, runtimeType, 0, "") iface_struct = builder.CreateInsertValue(iface_struct, ptr, 1, "") // TODO assert either source is a named type (or pointer to), or the // interface has an empty methodset. if srcname != nil { // TODO check whether the functions in the struct take // value or pointer receivers. // Look up the method by name. // TODO check embedded types. for i, m := range iface.Methods { // TODO make this loop linear by iterating through the // interface methods and type methods together. var methodobj *ast.Object curr := []types.Type{srcname} for methodobj == nil && len(curr) > 0 { var next []types.Type for _, typ := range curr { if p, ok := types.Underlying(typ).(*types.Pointer); ok { if _, ok := types.Underlying(p.Base).(*types.Struct); ok { typ = p.Base } } if n, ok := typ.(*types.Name); ok { methods := n.Methods mi := sort.Search(len(methods), func(i int) bool { return methods[i].Name >= m.Name }) if mi < len(methods) && methods[mi].Name == m.Name { methodobj = methods[mi] break } } if typ, ok := types.Underlying(typ).(*types.Struct); ok { for _, field := range typ.Fields { if field.Name == "" { typ := field.Type.(types.Type) next = append(next, typ) } } } } curr = next } if methodobj == nil { msg := fmt.Sprintf("Failed to locate (%s).%s", srcname.Obj.Name, m.Name) panic(msg) } method := v.compiler.Resolve(methodobj).(*LLVMValue) llvm_value := method.LLVMValue() // If we have a receiver wider than a word, or a pointer // receiver value and non-pointer receiver method, then // we must use the "wrapper" pointer method. fntyp := methodobj.Type.(*types.Func) recvtyp := fntyp.Recv.Type.(types.Type) needload := overwide if !needload { // TODO handle embedded types here. //needload = types.Identical(v.Type(), recvtyp) if p, ok := v.Type().(*types.Pointer); ok { needload = types.Identical(p.Base, recvtyp) } } if needload { ifname := fmt.Sprintf("*%s.%s", recvtyp, methodobj.Name) llvm_value = v.compiler.module.NamedFunction(ifname) } llvm_value = builder.CreateBitCast(llvm_value, element_types[i+2], "") iface_struct = builder.CreateInsertValue(iface_struct, llvm_value, i+2, "") } } return v.compiler.NewLLVMValue(iface_struct, iface) }
func (v *LLVMValue) Convert(dst_typ types.Type) Value { // 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 if name, isname := dst_typ.(*types.Name); isname { dst_typ = types.Underlying(name) } // Get the underlying type, if any. if name, isname := src_typ.(*types.Name); isname { src_typ = types.Underlying(name) } // Identical (underlying) types? Just swap in the destination type. if types.Identical(src_typ, dst_typ) { dst_typ = orig_dst_typ // TODO avoid load here by reusing pointer value, if exists. return v.compiler.NewLLVMValue(v.LLVMValue(), dst_typ) } // Convert from an interface type. if _, isinterface := src_typ.(*types.Interface); isinterface { if interface_, isinterface := dst_typ.(*types.Interface); isinterface { return v.convertI2I(interface_) } else { return v.convertI2V(dst_typ) } } // 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) } // TODO other special conversions, e.g. int->string. 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 := v.compiler.builder.CreatePtrToInt(v.LLVMValue(), llvm_type, "") return v.compiler.NewLLVMValue(value, dst_typ) } else if src_typ == types.Uintptr { return v.compiler.NewLLVMValue(v.LLVMValue(), dst_typ) } } else if src_typ == types.UnsafePointer { // unsafe.Pointer -> X if _, isptr := dst_typ.(*types.Pointer); isptr { value := v.compiler.builder.CreateIntToPtr(v.LLVMValue(), llvm_type, "") return v.compiler.NewLLVMValue(value, dst_typ) } else if dst_typ == types.Uintptr { return v.compiler.NewLLVMValue(v.LLVMValue(), 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 = v.compiler.builder.CreateZExt(lv, llvm_type, "") case delta > 0: lv = v.compiler.builder.CreateTrunc(lv, llvm_type, "") } return v.compiler.NewLLVMValue(lv, dst_typ) } case llvm.DoubleTypeKind: switch llvm_type.TypeKind() { case llvm.FloatTypeKind: lv = v.compiler.builder.CreateFPTrunc(lv, llvm_type, "") return v.compiler.NewLLVMValue(lv, dst_typ) } case llvm.FloatTypeKind: switch llvm_type.TypeKind() { case llvm.DoubleTypeKind: lv = v.compiler.builder.CreateFPExt(lv, llvm_type, "") return v.compiler.NewLLVMValue(lv, dst_typ) } } //bitcast_value := v.compiler.builder.CreateBitCast(lv, llvm_type, "") /* value_type := value.Type() switch value_type.TypeKind() { case llvm.IntegerTypeKind: switch totype.TypeKind() { case llvm.IntegerTypeKind: //delta := value_type.IntTypeWidth() - totype.IntTypeWidth() //var switch { case delta == 0: return value // TODO handle signed/unsigned (SExt/ZExt) case delta < 0: return c.compiler.builder.CreateZExt(value, totype, "") case delta > 0: return c.compiler.builder.CreateTrunc(value, totype, "") } return LLVMValue{lhs.compiler.builder, value} } } */ panic(fmt.Sprint("unimplemented conversion: ", v.typ, " -> ", orig_dst_typ)) }
func (lhs *LLVMValue) BinaryOp(op token.Token, rhs_ Value) Value { if op == token.NEQ { result := lhs.BinaryOp(token.EQL, rhs_) return result.UnaryOp(token.NOT) } var result llvm.Value c := lhs.compiler b := lhs.compiler.builder // Later we can do better by treating constants specially. For now, let's // convert to LLVMValue's. var rhs *LLVMValue rhsisnil := false switch rhs_ := rhs_.(type) { case *LLVMValue: rhs = rhs_ case NilValue: rhsisnil = true switch rhs_ := rhs_.Convert(lhs.Type()).(type) { case ConstValue: rhs = c.NewLLVMValue(rhs_.LLVMValue(), rhs_.Type()) case *LLVMValue: rhs = rhs_ } case ConstValue: value := rhs_.Convert(lhs.Type()) rhs = c.NewLLVMValue(value.LLVMValue(), value.Type()) } switch typ := types.Underlying(lhs.typ).(type) { case *types.Struct: // TODO check types are the same. element_types_count := lhs.LLVMValue().Type().StructElementTypesCount() struct_fields := typ.Fields if element_types_count > 0 { t := c.ObjGetType(struct_fields[0]) first_lhs := c.NewLLVMValue(b.CreateExtractValue(lhs.LLVMValue(), 0, ""), t) first_rhs := c.NewLLVMValue(b.CreateExtractValue(rhs.LLVMValue(), 0, ""), t) first := first_lhs.BinaryOp(op, first_rhs) logical_op := token.LAND if op == token.NEQ { logical_op = token.LOR } result := first for i := 1; i < element_types_count; i++ { t := c.ObjGetType(struct_fields[i]) next_lhs := c.NewLLVMValue(b.CreateExtractValue(lhs.LLVMValue(), i, ""), t) next_rhs := c.NewLLVMValue(b.CreateExtractValue(rhs.LLVMValue(), i, ""), t) next := next_lhs.BinaryOp(op, next_rhs) result = result.BinaryOp(logical_op, next) } return result } case *types.Interface: if rhsisnil { valueNull := b.CreateIsNull(b.CreateExtractValue(lhs.LLVMValue(), 0, ""), "") typeNull := b.CreateIsNull(b.CreateExtractValue(lhs.LLVMValue(), 1, ""), "") result := b.CreateAnd(typeNull, valueNull, "") return c.NewLLVMValue(result, types.Bool) } // TODO check for interface/interface comparison vs. interface/value comparison. return lhs.compareI2I(rhs) case *types.Slice: // []T == nil isnil := b.CreateIsNull(b.CreateExtractValue(lhs.LLVMValue(), 0, ""), "") return c.NewLLVMValue(isnil, types.Bool) } // Strings. if types.Underlying(lhs.typ) == types.String { if types.Underlying(rhs.typ) == types.String { switch op { case token.ADD: return c.concatenateStrings(lhs, rhs) case token.EQL, token.LSS, token.GTR, token.LEQ, token.GEQ: return c.compareStrings(lhs, rhs, op) default: panic(fmt.Sprint("Unimplemented operator: ", op)) } } panic("unimplemented") } // Determine whether to use integer or floating point instructions. // TODO determine the NaN rules. isfp := types.Identical(types.Underlying(lhs.typ), types.Float32) || types.Identical(types.Underlying(lhs.typ), types.Float64) switch op { case token.MUL: if isfp { result = b.CreateFMul(lhs.LLVMValue(), rhs.LLVMValue(), "") } else { result = b.CreateMul(lhs.LLVMValue(), rhs.LLVMValue(), "") } return lhs.compiler.NewLLVMValue(result, lhs.typ) case token.QUO: if isfp { result = b.CreateFDiv(lhs.LLVMValue(), rhs.LLVMValue(), "") } else { result = b.CreateUDiv(lhs.LLVMValue(), rhs.LLVMValue(), "") } return lhs.compiler.NewLLVMValue(result, lhs.typ) case token.REM: if isfp { result = b.CreateFRem(lhs.LLVMValue(), rhs.LLVMValue(), "") } else { result = b.CreateURem(lhs.LLVMValue(), rhs.LLVMValue(), "") } return lhs.compiler.NewLLVMValue(result, lhs.typ) case token.ADD: if isfp { result = b.CreateFAdd(lhs.LLVMValue(), rhs.LLVMValue(), "") } else { result = b.CreateAdd(lhs.LLVMValue(), rhs.LLVMValue(), "") } return lhs.compiler.NewLLVMValue(result, lhs.typ) case token.SUB: if isfp { result = b.CreateFSub(lhs.LLVMValue(), rhs.LLVMValue(), "") } else { result = b.CreateSub(lhs.LLVMValue(), rhs.LLVMValue(), "") } return lhs.compiler.NewLLVMValue(result, lhs.typ) case token.SHL: rhs = rhs.Convert(lhs.Type()).(*LLVMValue) result = b.CreateShl(lhs.LLVMValue(), rhs.LLVMValue(), "") return lhs.compiler.NewLLVMValue(result, lhs.typ) case token.SHR: rhs = rhs.Convert(lhs.Type()).(*LLVMValue) result = b.CreateAShr(lhs.LLVMValue(), rhs.LLVMValue(), "") return lhs.compiler.NewLLVMValue(result, lhs.typ) case token.NEQ: if isfp { result = b.CreateFCmp(llvm.FloatONE, lhs.LLVMValue(), rhs.LLVMValue(), "") } else { result = b.CreateICmp(llvm.IntNE, lhs.LLVMValue(), rhs.LLVMValue(), "") } return lhs.compiler.NewLLVMValue(result, types.Bool) case token.EQL: if isfp { result = b.CreateFCmp(llvm.FloatOEQ, lhs.LLVMValue(), rhs.LLVMValue(), "") } else { result = b.CreateICmp(llvm.IntEQ, lhs.LLVMValue(), rhs.LLVMValue(), "") } return lhs.compiler.NewLLVMValue(result, types.Bool) case token.LSS: if isfp { result = b.CreateFCmp(llvm.FloatOLT, lhs.LLVMValue(), rhs.LLVMValue(), "") } else { result = b.CreateICmp(llvm.IntULT, lhs.LLVMValue(), rhs.LLVMValue(), "") } return lhs.compiler.NewLLVMValue(result, types.Bool) case token.LEQ: // TODO signed/unsigned if isfp { result = b.CreateFCmp(llvm.FloatOLE, lhs.LLVMValue(), rhs.LLVMValue(), "") } else { result = b.CreateICmp(llvm.IntULE, lhs.LLVMValue(), rhs.LLVMValue(), "") } return lhs.compiler.NewLLVMValue(result, types.Bool) case token.GTR: if isfp { result = b.CreateFCmp(llvm.FloatOGT, lhs.LLVMValue(), rhs.LLVMValue(), "") } else { result = b.CreateICmp(llvm.IntUGT, lhs.LLVMValue(), rhs.LLVMValue(), "") } return lhs.compiler.NewLLVMValue(result, types.Bool) case token.GEQ: if isfp { result = b.CreateFCmp(llvm.FloatOGE, lhs.LLVMValue(), rhs.LLVMValue(), "") } else { result = b.CreateICmp(llvm.IntUGE, lhs.LLVMValue(), rhs.LLVMValue(), "") } return lhs.compiler.NewLLVMValue(result, types.Bool) case token.AND: // a & b result = b.CreateAnd(lhs.LLVMValue(), rhs.LLVMValue(), "") return lhs.compiler.NewLLVMValue(result, lhs.typ) case token.OR: // a | b result = b.CreateOr(lhs.LLVMValue(), rhs.LLVMValue(), "") return lhs.compiler.NewLLVMValue(result, lhs.typ) case token.XOR: // a ^ b result = b.CreateXor(lhs.LLVMValue(), rhs.LLVMValue(), "") return lhs.compiler.NewLLVMValue(result, lhs.typ) default: panic(fmt.Sprint("Unimplemented operator: ", op)) } panic("unreachable") }
func (c *compiler) VisitSelectorExpr(expr *ast.SelectorExpr) Value { lhs := c.VisitExpr(expr.X) if lhs == nil { // The only time we should get a nil result is if the object is // a package. obj := expr.Sel.Obj if obj.Kind == ast.Typ { return TypeValue{obj.Type.(types.Type)} } return c.Resolve(obj) } // TODO(?) record path to field/method during typechecking, so we don't // have to search again here. name := expr.Sel.Name if iface, ok := types.Underlying(lhs.Type()).(*types.Interface); ok { i := sort.Search(len(iface.Methods), func(i int) bool { return iface.Methods[i].Name >= name }) structValue := lhs.LLVMValue() receiver := c.builder.CreateExtractValue(structValue, 0, "") f := c.builder.CreateExtractValue(structValue, i+2, "") ftype := c.ObjGetType(iface.Methods[i]).(*types.Func) method := c.NewLLVMValue(c.builder.CreateBitCast(f, c.types.ToLLVM(ftype), ""), ftype) method.receiver = c.NewLLVMValue(receiver, ftype.Recv.Type.(types.Type)) return method } // Search through embedded types for field/method. var result selectorCandidate curr := []selectorCandidate{{nil, lhs.Type()}} for result.Type == nil && len(curr) > 0 { var next []selectorCandidate for _, candidate := range curr { indices := candidate.Indices[0:] t := candidate.Type if p, ok := types.Underlying(t).(*types.Pointer); ok { if _, ok := types.Underlying(p.Base).(*types.Struct); ok { t = p.Base } } if n, ok := t.(*types.Name); ok { i := sort.Search(len(n.Methods), func(i int) bool { return n.Methods[i].Name >= name }) if i < len(n.Methods) && n.Methods[i].Name == name { result.Indices = indices result.Type = t } } if t, ok := types.Underlying(t).(*types.Struct); ok { if i, ok := t.FieldIndices[name]; ok { result.Indices = append(indices, int(i)) result.Type = t } else { // Add embedded types to the next set of types // to check. for i, field := range t.Fields { if field.Name == "" { indices = append(indices[0:], i) t := field.Type.(types.Type) candidate := selectorCandidate{indices, t} next = append(next, candidate) } } } } } curr = next } // Get a pointer to the field/receiver. recvValue := lhs.(*LLVMValue) if _, ok := types.Underlying(lhs.Type()).(*types.Pointer); !ok { recvValue = recvValue.pointer } recvValue = c.NewLLVMValue(recvValue.LLVMValue(), recvValue.Type()) if len(result.Indices) > 0 { for _, v := range result.Indices { ptr := recvValue.LLVMValue() field := types.Underlying(types.Deref(recvValue.typ)).(*types.Struct).Fields[v] fieldPtr := c.builder.CreateStructGEP(ptr, v, "") fieldPtrTyp := &types.Pointer{Base: field.Type.(types.Type)} recvValue = c.NewLLVMValue(fieldPtr, fieldPtrTyp) // GEP returns a pointer; if the field is a pointer, // we must load our pointer-to-a-pointer. if _, ok := field.Type.(*types.Pointer); ok { recvValue = recvValue.makePointee() } } } if !types.Identical(recvValue.typ, expr.Sel.Obj.Type.(types.Type)) { recvValue = recvValue.makePointee() } // Method? if expr.Sel.Obj.Kind == ast.Fun { method := c.Resolve(expr.Sel.Obj).(*LLVMValue) methodType := expr.Sel.Obj.Type.(*types.Func) receiverType := methodType.Recv.Type.(types.Type) if types.Identical(recvValue.Type(), receiverType) { method.receiver = recvValue } else if types.Identical(&types.Pointer{Base: recvValue.Type()}, receiverType) { method.receiver = recvValue.pointer } else { method.receiver = recvValue.makePointee() } return method } else { return recvValue } panic("unreachable") }
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 (lhs *LLVMValue) BinaryOp(op token.Token, rhs_ Value) Value { if op == token.NEQ { result := lhs.BinaryOp(token.EQL, rhs_) return result.UnaryOp(token.NOT) } var result llvm.Value c := lhs.compiler b := lhs.compiler.builder // Later we can do better by treating constants specially. For now, let's // convert to LLVMValue's. var rhs *LLVMValue switch rhs_ := rhs_.(type) { case *LLVMValue: rhs = rhs_ case NilValue: switch rhs_ := rhs_.Convert(lhs.Type()).(type) { case ConstValue: rhs = c.NewLLVMValue(rhs_.LLVMValue(), rhs_.Type()) case *LLVMValue: rhs = rhs_ } case ConstValue: value := rhs_.Convert(lhs.Type()) rhs = c.NewLLVMValue(value.LLVMValue(), value.Type()) } // Special case for structs. // TODO handle strings as an even more special case. if struct_type, ok := types.Underlying(lhs.typ).(*types.Struct); ok { // TODO check types are the same. element_types_count := lhs.LLVMValue().Type().StructElementTypesCount() struct_fields := struct_type.Fields if element_types_count > 0 { t := c.ObjGetType(struct_fields[0]) first_lhs := c.NewLLVMValue(b.CreateExtractValue(lhs.LLVMValue(), 0, ""), t) first_rhs := c.NewLLVMValue(b.CreateExtractValue(rhs.LLVMValue(), 0, ""), t) first := first_lhs.BinaryOp(op, first_rhs) logical_op := token.LAND if op == token.NEQ { logical_op = token.LOR } result := first for i := 1; i < element_types_count; i++ { t := c.ObjGetType(struct_fields[i]) next_lhs := c.NewLLVMValue(b.CreateExtractValue(lhs.LLVMValue(), i, ""), t) next_rhs := c.NewLLVMValue(b.CreateExtractValue(rhs.LLVMValue(), i, ""), t) next := next_lhs.BinaryOp(op, next_rhs) result = result.BinaryOp(logical_op, next) } return result } } // Interfaces. if _, ok := types.Underlying(lhs.typ).(*types.Interface); ok { // TODO check for interface/interface comparison vs. interface/value comparison. // nil comparison if /*rhs.LLVMValue().IsConstant() &&*/ rhs.LLVMValue().IsNull() { var result llvm.Value if op == token.EQL { valueNull := b.CreateIsNull(b.CreateExtractValue(lhs.LLVMValue(), 0, ""), "") typeNull := b.CreateIsNull(b.CreateExtractValue(lhs.LLVMValue(), 1, ""), "") result = b.CreateAnd(typeNull, valueNull, "") } else { valueNotNull := b.CreateIsNotNull(b.CreateExtractValue(lhs.LLVMValue(), 0, ""), "") typeNotNull := b.CreateIsNotNull(b.CreateExtractValue(lhs.LLVMValue(), 1, ""), "") result = b.CreateOr(typeNotNull, valueNotNull, "") } return c.NewLLVMValue(result, types.Bool) } // First, check that the dynamic types are identical. // FIXME provide runtime function for type identity comparison, and // value comparisons. lhsType := b.CreateExtractValue(lhs.LLVMValue(), 1, "") rhsType := b.CreateExtractValue(rhs.LLVMValue(), 1, "") diff := b.CreatePtrDiff(lhsType, rhsType, "") zero := llvm.ConstNull(diff.Type()) var result llvm.Value if op == token.EQL { typesIdentical := b.CreateICmp(llvm.IntEQ, diff, zero, "") //valuesEqual := ... //result = b.CreateAnd(typesIdentical, valuesEqual, "") result = typesIdentical } else { typesDifferent := b.CreateICmp(llvm.IntNE, diff, zero, "") //valuesUnequal := ... //result = b.CreateOr(typesDifferent, valuesUnequal, "") result = typesDifferent } return c.NewLLVMValue(result, types.Bool) } if types.Underlying(lhs.typ) == types.String { if types.Underlying(rhs.typ) == types.String { switch op { case token.ADD: return c.concatenateStrings(lhs, rhs) case token.EQL, token.LSS, token.GTR, token.LEQ, token.GEQ: return c.compareStrings(lhs, rhs, op) default: panic(fmt.Sprint("Unimplemented operator: ", op)) } } panic("unimplemented") } // Determine whether to use integer or floating point instructions. // TODO determine the NaN rules. isfp := types.Identical(types.Underlying(lhs.typ), types.Float32) || types.Identical(types.Underlying(lhs.typ), types.Float64) switch op { case token.MUL: result = b.CreateMul(lhs.LLVMValue(), rhs.LLVMValue(), "") return lhs.compiler.NewLLVMValue(result, lhs.typ) case token.QUO: result = b.CreateUDiv(lhs.LLVMValue(), rhs.LLVMValue(), "") return lhs.compiler.NewLLVMValue(result, lhs.typ) case token.ADD: result = b.CreateAdd(lhs.LLVMValue(), rhs.LLVMValue(), "") return lhs.compiler.NewLLVMValue(result, lhs.typ) case token.SUB: result = b.CreateSub(lhs.LLVMValue(), rhs.LLVMValue(), "") return lhs.compiler.NewLLVMValue(result, lhs.typ) case token.NEQ: if isfp { result = b.CreateFCmp(llvm.FloatONE, lhs.LLVMValue(), rhs.LLVMValue(), "") } else { result = b.CreateICmp(llvm.IntNE, lhs.LLVMValue(), rhs.LLVMValue(), "") } return lhs.compiler.NewLLVMValue(result, types.Bool) case token.EQL: result = b.CreateICmp(llvm.IntEQ, lhs.LLVMValue(), rhs.LLVMValue(), "") return lhs.compiler.NewLLVMValue(result, types.Bool) case token.LSS: result = b.CreateICmp(llvm.IntULT, lhs.LLVMValue(), rhs.LLVMValue(), "") return lhs.compiler.NewLLVMValue(result, types.Bool) case token.LEQ: // TODO signed/unsigned result = b.CreateICmp(llvm.IntULE, lhs.LLVMValue(), rhs.LLVMValue(), "") return lhs.compiler.NewLLVMValue(result, types.Bool) case token.GTR: result = b.CreateICmp(llvm.IntUGT, lhs.LLVMValue(), rhs.LLVMValue(), "") return lhs.compiler.NewLLVMValue(result, types.Bool) case token.GEQ: result = b.CreateICmp(llvm.IntUGE, lhs.LLVMValue(), rhs.LLVMValue(), "") return lhs.compiler.NewLLVMValue(result, types.Bool) case token.LAND: // FIXME change this to branch result = b.CreateAnd(lhs.LLVMValue(), rhs.LLVMValue(), "") return lhs.compiler.NewLLVMValue(result, types.Bool) case token.LOR: // FIXME change this to branch result = b.CreateOr(lhs.LLVMValue(), rhs.LLVMValue(), "") return lhs.compiler.NewLLVMValue(result, types.Bool) default: panic(fmt.Sprint("Unimplemented operator: ", op)) } panic("unreachable") }
func (tm *TypeMap) uncommonType(n *types.Name, ptr bool) llvm.Value { uncommonTypeInit := llvm.ConstNull(tm.runtimeUncommonType) namePtr := tm.globalStringPtr(n.Obj.Name) uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, namePtr, []uint32{0}) var pkgpathPtr llvm.Value if n.Package != "" { pkgpathPtr = tm.globalStringPtr(n.Package) uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, pkgpathPtr, []uint32{1}) } // Store methods. methods := make([]llvm.Value, 0, len(n.Methods)) for _, m := range n.Methods { ftyp := m.Type.(*types.Func) ptrrecv := !types.Identical(ftyp.Recv.Type.(types.Type), n) if !ptr && ptrrecv { // For a type T, we only store methods where the // receiver is T and not *T. For *T we store both. continue } method := llvm.ConstNull(tm.runtimeMethod) name := tm.globalStringPtr(m.Name) name = llvm.ConstBitCast(name, tm.runtimeMethod.StructElementTypes()[0]) // name method = llvm.ConstInsertValue(method, name, []uint32{0}) // pkgPath method = llvm.ConstInsertValue(method, pkgpathPtr, []uint32{1}) // mtyp (method type, no receiver) { recv := ftyp.Recv ftyp.Recv = nil mtyp := tm.ToRuntime(ftyp) method = llvm.ConstInsertValue(method, mtyp, []uint32{2}) ftyp.Recv = recv } // typ (function type, with receiver) typ := tm.ToRuntime(ftyp) method = llvm.ConstInsertValue(method, typ, []uint32{3}) // tfn (standard method/function pointer for plain method calls) tfn := tm.resolver.Resolve(m).LLVMValue() tfn = llvm.ConstPtrToInt(tfn, tm.target.IntPtrType()) // ifn (single-word receiver function pointer for interface calls) ifn := tfn needload := ptr && !ptrrecv if !needload { recvtyp := tm.ToLLVM(ftyp.Recv.Type.(types.Type)) needload = int(tm.target.TypeAllocSize(recvtyp)) > tm.target.PointerSize() } if needload { // If the receiver type is wider than a word, we // need to use an intermediate function which takes // a pointer-receiver, loads it, and then calls the // standard receiver function. fname := fmt.Sprintf("*%s.%s", ftyp.Recv.Type, m.Name) ifn = tm.module.NamedFunction(fname) ifn = llvm.ConstPtrToInt(ifn, tm.target.IntPtrType()) } method = llvm.ConstInsertValue(method, ifn, []uint32{4}) method = llvm.ConstInsertValue(method, tfn, []uint32{5}) methods = append(methods, method) } var methodsGlobalPtr llvm.Value if len(methods) > 0 { methodsArray := llvm.ConstArray(tm.runtimeMethod, methods) methodsGlobalPtr = llvm.AddGlobal(tm.module, methodsArray.Type(), "") methodsGlobalPtr.SetInitializer(methodsArray) i32zero := llvm.ConstNull(llvm.Int32Type()) methodsGlobalPtr = llvm.ConstGEP(methodsGlobalPtr, []llvm.Value{i32zero, i32zero}) } else { methodsGlobalPtr = llvm.ConstNull(llvm.PointerType(tm.runtimeMethod, 0)) } len_ := llvm.ConstInt(llvm.Int32Type(), uint64(len(methods)), false) methodsSliceType := tm.runtimeUncommonType.StructElementTypes()[2] methodsSlice := llvm.ConstNull(methodsSliceType) methodsSlice = llvm.ConstInsertValue(methodsSlice, methodsGlobalPtr, []uint32{0}) methodsSlice = llvm.ConstInsertValue(methodsSlice, len_, []uint32{1}) methodsSlice = llvm.ConstInsertValue(methodsSlice, len_, []uint32{2}) uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, methodsSlice, []uint32{2}) return uncommonTypeInit }