func (v Target) genConvert(a *allocator, instr *ssa.Convert) { op := ssa.GetOperands(instr)[0] checkTypeSupported(op.Type()) checkTypeSupported(instr.Type()) targetStoresz := TypeStoreSizeInBits(instr.Type()) targetsz := TypeSizeInBits(instr.Type()) opsz := TypeSizeInBits(op.Type()) switch instr.ConvertType() { case ssa.ConvertBitcast: v.moveValToVal(a, op, instr) case ssa.ConvertTrunc: v.moveIntToReg(a, op, "rax") if !isRegSizeBits(targetsz) { v.wop("andq $%d, #rax", (1<<uint(targetsz))-1) } v.wop("mov%s #%s, %s", sizeSuffixBits(targetStoresz), regToSize("rax", targetStoresz), a.valStr(instr)) case ssa.ConvertZExt: v.moveIntToReg(a, op, "rax") v.moveRegToVal(a, "rax", instr) case ssa.ConvertSExt: v.genSExt(a, instr, op, opsz, targetStoresz, targetsz) case ssa.ConvertIntToPtr, ssa.ConvertPtrToInt: v.moveIntToReg(a, op, "rax") v.moveRegToVal(a, "rax", instr) default: panic("unim") } }
// this function is bad func checkConvert(instr *ssa.Convert) error { ops := ssa.GetOperands(instr) srcType := ops[0].Type() destType := instr.Type() mustBeInt := make([]types.Type, 0, 2) mustBeFloat := make([]types.Type, 0, 2) mustBePointer := make([]types.Type, 0, 2) switch instr.ConvertType() { case ssa.ConvertSExt, ssa.ConvertZExt, ssa.ConvertTrunc: mustBeInt = append(mustBeInt, srcType, destType) case ssa.ConvertBitcast: mustBePointer = append(mustBePointer, srcType, destType) case ssa.ConvertFExt, ssa.ConvertFTrunc: mustBeFloat = append(mustBeFloat, srcType, destType) case ssa.ConvertFToUI, ssa.ConvertFToSI: mustBeFloat = append(mustBeFloat, srcType) mustBeInt = append(mustBeInt, destType) case ssa.ConvertUIToF, ssa.ConvertSIToF: mustBeFloat = append(mustBeFloat, destType) mustBeInt = append(mustBeInt, srcType) case ssa.ConvertPtrToInt: mustBePointer = append(mustBePointer, srcType) mustBeInt = append(mustBeInt, destType) case ssa.ConvertIntToPtr: mustBeInt = append(mustBeInt, srcType) mustBePointer = append(mustBePointer, destType) default: panic("unim") } for _, t := range mustBeInt { if err := errIfNotIntType(instr, t); err != nil { return err } } for _, t := range mustBeFloat { if err := errIfNotFloatType(instr, t); err != nil { return err } } for _, t := range mustBePointer { if err := errIfNotPointerType(instr, t); err != nil { return err } } instrError := func(message string) error { return &InstrError{ Instr: instr, Message: message, } } switch instr.ConvertType() { case ssa.ConvertSExt, ssa.ConvertZExt: if srcType.(*types.Int).Width() >= destType.(*types.Int).Width() { return instrError("sext/zext requires src width < dest width") } case ssa.ConvertTrunc: if srcType.(*types.Int).Width() <= destType.(*types.Int).Width() { return instrError("trunc requires src width > dest width") } case ssa.ConvertBitcast: // do nothing case ssa.ConvertFExt: if srcType.(*types.Float).Type().CanExtendTo(destType.(*types.Float).Type()) { return instrError("fext cannot convert from " + srcType.String() + " to " + destType.String()) } case ssa.ConvertFTrunc: if srcType.(*types.Float).Type().CanTruncateTo(destType.(*types.Float).Type()) { return instrError("ftrunc cannot convert from " + srcType.String() + " to " + destType.String()) } case ssa.ConvertFToUI, ssa.ConvertFToSI, ssa.ConvertUIToF, ssa.ConvertSIToF, ssa.ConvertPtrToInt, ssa.ConvertIntToPtr: // nothing to do default: panic("unim") } return nil }