// genConv generates constraints for the conversion operation conv. func (a *analysis) genConv(conv *ssa.Convert, cgn *cgnode) { res := a.valueNode(conv) if res == 0 { return // result is non-pointerlike } tSrc := conv.X.Type() tDst := conv.Type() switch utSrc := tSrc.Underlying().(type) { case *types.Slice: // []byte/[]rune -> string? return case *types.Pointer: // *T -> unsafe.Pointer? if tDst.Underlying() == tUnsafePtr { return // we don't model unsafe aliasing (unsound) } case *types.Basic: switch tDst.Underlying().(type) { case *types.Pointer: // Treat unsafe.Pointer->*T conversions like // new(T) and create an unaliased object. if utSrc == tUnsafePtr { obj := a.addNodes(mustDeref(tDst), "unsafe.Pointer conversion") a.endObject(obj, cgn, conv) a.addressOf(tDst, res, obj) return } case *types.Slice: // string -> []byte/[]rune (or named aliases)? if utSrc.Info()&types.IsString != 0 { obj := a.addNodes(sliceToArray(tDst), "convert") a.endObject(obj, cgn, conv) a.addressOf(tDst, res, obj) return } case *types.Basic: // All basic-to-basic type conversions are no-ops. // This includes uintptr<->unsafe.Pointer conversions, // which we (unsoundly) ignore. return } } panic(fmt.Sprintf("illegal *ssa.Convert %s -> %s: %s", tSrc, tDst, conv.Parent())) }
func (f *Function) ConvertFromTo(instr *ssa.Convert, fromOpType, toOpType InstrOpType, fromXmm, toXmm XmmData) (string, *Error) { asm := "" ctx := context{f, instr} a, from, err := f.LoadValueSimple(instr, instr.X) if err != nil { return "", err } else { asm += a } a1, to := f.allocIdentReg(instr, f.Ident(instr), f.Ident(instr).size()) asm += a1 a, tmp := f.allocReg(instr, DATA_REG, sizeInt()) asm += a fromType := OpDataType{ op: fromOpType, InstrData: InstrData{signed: signed(instr.X.Type()), size: f.sizeof(instr.X)}, xmmvariant: fromXmm} toType := OpDataType{ op: toOpType, InstrData: InstrData{signed: signed(instr.Type()), size: f.sizeof(instr)}, xmmvariant: toXmm} // round uint64 to nearest int64 before converting to float32/float64 if isUint(instr.X.Type()) && f.sizeof(instr.X) == 8 && isFloat(instr.Type()) { var floatSize uint if isFloat32(instr.Type()) { floatSize = 32 } else if isFloat64(instr.Type()) { floatSize = 64 } else { ice("converting from uint64 to float") } asm += f.ConvertUint64ToFloat(instr, tmp, from, to, floatSize) } else { asm += ConvertOp(ctx, from, fromType, to, toType, tmp) } toIdent := f.identifiers[instr.Name()] if a, err := f.StoreValue(instr, toIdent, to); err != nil { return "", err } else { asm += a } f.freeReg(from) f.freeReg(to) f.freeReg(tmp) return asm, nil }
func (f *Function) Convert(instr *ssa.Convert) (string, *Error) { from := instr.X.Type() to := instr.Type() var fromType InstrOpType var toType InstrOpType var fromXmm XmmData var toXmm XmmData if isInteger(from) && isInteger(to) { fromType = OP_DATA toType = OP_DATA fromXmm = XMM_INVALID toXmm = XMM_INVALID } else if isInteger(from) && isFloat(to) { fromType = OP_DATA toType = OP_XMM fromXmm = XMM_INVALID toXmm = GetXmmVariant(to) } else if isFloat(from) && isInteger(to) { fromType = OP_XMM fromXmm = GetXmmVariant(from) toType = OP_DATA toXmm = XMM_INVALID } else if isFloat(from) && isFloat(to) { fromType = OP_XMM fromXmm = GetXmmVariant(from) toType = OP_XMM toXmm = GetXmmVariant(to) } else { fmtstr := "Cannot convert from (%v) to (%v)" msg := fmt.Sprintf(fmtstr, from.String(), to.String()) return ErrorMsg(msg) } return f.ConvertFromTo(instr, fromType, toType, fromXmm, toXmm) }