compiler: refactor parseConvert

Этот коммит содержится в:
Ayke van Laethem 2019-11-23 12:31:53 +01:00 коммит произвёл Ron Evans
родитель a1ba71ce99
коммит bee5a67097
2 изменённых файлов: 50 добавлений и 49 удалений

Просмотреть файл

@ -1507,7 +1507,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
panic("const is not an expression") panic("const is not an expression")
case *ssa.Convert: case *ssa.Convert:
x := frame.getValue(expr.X) x := frame.getValue(expr.X)
return c.parseConvert(expr.X.Type(), expr.Type(), x, expr.Pos()) return frame.createConvert(expr.X.Type(), expr.Type(), x, expr.Pos())
case *ssa.Extract: case *ssa.Extract:
if _, ok := expr.Tuple.(*ssa.Select); ok { if _, ok := expr.Tuple.(*ssa.Select); ok {
return frame.getChanSelectResult(expr), nil return frame.getChanSelectResult(expr), nil
@ -1657,7 +1657,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
frame.createSliceBoundsCheck(maxSize, sliceLen, sliceCap, sliceCap, lenType, capType, capType) frame.createSliceBoundsCheck(maxSize, sliceLen, sliceCap, sliceCap, lenType, capType, capType)
// Allocate the backing array. // Allocate the backing array.
sliceCapCast, err := c.parseConvert(expr.Cap.Type(), types.Typ[types.Uintptr], sliceCap, expr.Pos()) sliceCapCast, err := frame.createConvert(expr.Cap.Type(), types.Typ[types.Uintptr], sliceCap, expr.Pos())
if err != nil { if err != nil {
return llvm.Value{}, err return llvm.Value{}, err
} }
@ -1667,11 +1667,11 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
// Extend or truncate if necessary. This is safe as we've already done // Extend or truncate if necessary. This is safe as we've already done
// the bounds check. // the bounds check.
sliceLen, err = c.parseConvert(expr.Len.Type(), types.Typ[types.Uintptr], sliceLen, expr.Pos()) sliceLen, err = frame.createConvert(expr.Len.Type(), types.Typ[types.Uintptr], sliceLen, expr.Pos())
if err != nil { if err != nil {
return llvm.Value{}, err return llvm.Value{}, err
} }
sliceCap, err = c.parseConvert(expr.Cap.Type(), types.Typ[types.Uintptr], sliceCap, expr.Pos()) sliceCap, err = frame.createConvert(expr.Cap.Type(), types.Typ[types.Uintptr], sliceCap, expr.Pos())
if err != nil { if err != nil {
return llvm.Value{}, err return llvm.Value{}, err
} }
@ -2358,15 +2358,16 @@ func (b *builder) createConst(prefix string, expr *ssa.Const) llvm.Value {
} }
} }
func (c *Compiler) parseConvert(typeFrom, typeTo types.Type, value llvm.Value, pos token.Pos) (llvm.Value, error) { // createConvert creates a Go type conversion instruction.
func (b *builder) createConvert(typeFrom, typeTo types.Type, value llvm.Value, pos token.Pos) (llvm.Value, error) {
llvmTypeFrom := value.Type() llvmTypeFrom := value.Type()
llvmTypeTo := c.getLLVMType(typeTo) llvmTypeTo := b.getLLVMType(typeTo)
// Conversion between unsafe.Pointer and uintptr. // Conversion between unsafe.Pointer and uintptr.
isPtrFrom := isPointer(typeFrom.Underlying()) isPtrFrom := isPointer(typeFrom.Underlying())
isPtrTo := isPointer(typeTo.Underlying()) isPtrTo := isPointer(typeTo.Underlying())
if isPtrFrom && !isPtrTo { if isPtrFrom && !isPtrTo {
return c.builder.CreatePtrToInt(value, llvmTypeTo, ""), nil return b.CreatePtrToInt(value, llvmTypeTo, ""), nil
} else if !isPtrFrom && isPtrTo { } else if !isPtrFrom && isPtrTo {
if !value.IsABinaryOperator().IsNil() && value.InstructionOpcode() == llvm.Add { if !value.IsABinaryOperator().IsNil() && value.InstructionOpcode() == llvm.Add {
// This is probably a pattern like the following: // This is probably a pattern like the following:
@ -2381,7 +2382,7 @@ func (c *Compiler) parseConvert(typeFrom, typeTo types.Type, value llvm.Value, p
} }
if !ptr.IsAPtrToIntInst().IsNil() { if !ptr.IsAPtrToIntInst().IsNil() {
origptr := ptr.Operand(0) origptr := ptr.Operand(0)
if origptr.Type() == c.i8ptrType { if origptr.Type() == b.i8ptrType {
// This pointer can be calculated from the original // This pointer can be calculated from the original
// ptrtoint instruction with a GEP. The leftover inttoptr // ptrtoint instruction with a GEP. The leftover inttoptr
// instruction is trivial to optimize away. // instruction is trivial to optimize away.
@ -2389,21 +2390,21 @@ func (c *Compiler) parseConvert(typeFrom, typeTo types.Type, value llvm.Value, p
// create a GEP that is not in bounds. However, we're // create a GEP that is not in bounds. However, we're
// talking about unsafe code here so the programmer has to // talking about unsafe code here so the programmer has to
// be careful anyway. // be careful anyway.
return c.builder.CreateInBoundsGEP(origptr, []llvm.Value{index}, ""), nil return b.CreateInBoundsGEP(origptr, []llvm.Value{index}, ""), nil
} }
} }
} }
return c.builder.CreateIntToPtr(value, llvmTypeTo, ""), nil return b.CreateIntToPtr(value, llvmTypeTo, ""), nil
} }
// Conversion between pointers and unsafe.Pointer. // Conversion between pointers and unsafe.Pointer.
if isPtrFrom && isPtrTo { if isPtrFrom && isPtrTo {
return c.builder.CreateBitCast(value, llvmTypeTo, ""), nil return b.CreateBitCast(value, llvmTypeTo, ""), nil
} }
switch typeTo := typeTo.Underlying().(type) { switch typeTo := typeTo.Underlying().(type) {
case *types.Basic: case *types.Basic:
sizeFrom := c.targetData.TypeAllocSize(llvmTypeFrom) sizeFrom := b.targetData.TypeAllocSize(llvmTypeFrom)
if typeTo.Info()&types.IsString != 0 { if typeTo.Info()&types.IsString != 0 {
switch typeFrom := typeFrom.Underlying().(type) { switch typeFrom := typeFrom.Underlying().(type) {
@ -2413,47 +2414,47 @@ func (c *Compiler) parseConvert(typeFrom, typeTo types.Type, value llvm.Value, p
// Cast to an i32 value as expected by // Cast to an i32 value as expected by
// runtime.stringFromUnicode. // runtime.stringFromUnicode.
if sizeFrom > 4 { if sizeFrom > 4 {
value = c.builder.CreateTrunc(value, c.ctx.Int32Type(), "") value = b.CreateTrunc(value, b.ctx.Int32Type(), "")
} else if sizeFrom < 4 && typeTo.Info()&types.IsUnsigned != 0 { } else if sizeFrom < 4 && typeTo.Info()&types.IsUnsigned != 0 {
value = c.builder.CreateZExt(value, c.ctx.Int32Type(), "") value = b.CreateZExt(value, b.ctx.Int32Type(), "")
} else if sizeFrom < 4 { } else if sizeFrom < 4 {
value = c.builder.CreateSExt(value, c.ctx.Int32Type(), "") value = b.CreateSExt(value, b.ctx.Int32Type(), "")
} }
return c.createRuntimeCall("stringFromUnicode", []llvm.Value{value}, ""), nil return b.createRuntimeCall("stringFromUnicode", []llvm.Value{value}, ""), nil
case *types.Slice: case *types.Slice:
switch typeFrom.Elem().(*types.Basic).Kind() { switch typeFrom.Elem().(*types.Basic).Kind() {
case types.Byte: case types.Byte:
return c.createRuntimeCall("stringFromBytes", []llvm.Value{value}, ""), nil return b.createRuntimeCall("stringFromBytes", []llvm.Value{value}, ""), nil
case types.Rune: case types.Rune:
return c.createRuntimeCall("stringFromRunes", []llvm.Value{value}, ""), nil return b.createRuntimeCall("stringFromRunes", []llvm.Value{value}, ""), nil
default: default:
return llvm.Value{}, c.makeError(pos, "todo: convert to string: "+typeFrom.String()) return llvm.Value{}, b.makeError(pos, "todo: convert to string: "+typeFrom.String())
} }
default: default:
return llvm.Value{}, c.makeError(pos, "todo: convert to string: "+typeFrom.String()) return llvm.Value{}, b.makeError(pos, "todo: convert to string: "+typeFrom.String())
} }
} }
typeFrom := typeFrom.Underlying().(*types.Basic) typeFrom := typeFrom.Underlying().(*types.Basic)
sizeTo := c.targetData.TypeAllocSize(llvmTypeTo) sizeTo := b.targetData.TypeAllocSize(llvmTypeTo)
if typeFrom.Info()&types.IsInteger != 0 && typeTo.Info()&types.IsInteger != 0 { if typeFrom.Info()&types.IsInteger != 0 && typeTo.Info()&types.IsInteger != 0 {
// Conversion between two integers. // Conversion between two integers.
if sizeFrom > sizeTo { if sizeFrom > sizeTo {
return c.builder.CreateTrunc(value, llvmTypeTo, ""), nil return b.CreateTrunc(value, llvmTypeTo, ""), nil
} else if typeFrom.Info()&types.IsUnsigned != 0 { // if unsigned } else if typeFrom.Info()&types.IsUnsigned != 0 { // if unsigned
return c.builder.CreateZExt(value, llvmTypeTo, ""), nil return b.CreateZExt(value, llvmTypeTo, ""), nil
} else { // if signed } else { // if signed
return c.builder.CreateSExt(value, llvmTypeTo, ""), nil return b.CreateSExt(value, llvmTypeTo, ""), nil
} }
} }
if typeFrom.Info()&types.IsFloat != 0 && typeTo.Info()&types.IsFloat != 0 { if typeFrom.Info()&types.IsFloat != 0 && typeTo.Info()&types.IsFloat != 0 {
// Conversion between two floats. // Conversion between two floats.
if sizeFrom > sizeTo { if sizeFrom > sizeTo {
return c.builder.CreateFPTrunc(value, llvmTypeTo, ""), nil return b.CreateFPTrunc(value, llvmTypeTo, ""), nil
} else if sizeFrom < sizeTo { } else if sizeFrom < sizeTo {
return c.builder.CreateFPExt(value, llvmTypeTo, ""), nil return b.CreateFPExt(value, llvmTypeTo, ""), nil
} else { } else {
return value, nil return value, nil
} }
@ -2462,46 +2463,46 @@ func (c *Compiler) parseConvert(typeFrom, typeTo types.Type, value llvm.Value, p
if typeFrom.Info()&types.IsFloat != 0 && typeTo.Info()&types.IsInteger != 0 { if typeFrom.Info()&types.IsFloat != 0 && typeTo.Info()&types.IsInteger != 0 {
// Conversion from float to int. // Conversion from float to int.
if typeTo.Info()&types.IsUnsigned != 0 { // if unsigned if typeTo.Info()&types.IsUnsigned != 0 { // if unsigned
return c.builder.CreateFPToUI(value, llvmTypeTo, ""), nil return b.CreateFPToUI(value, llvmTypeTo, ""), nil
} else { // if signed } else { // if signed
return c.builder.CreateFPToSI(value, llvmTypeTo, ""), nil return b.CreateFPToSI(value, llvmTypeTo, ""), nil
} }
} }
if typeFrom.Info()&types.IsInteger != 0 && typeTo.Info()&types.IsFloat != 0 { if typeFrom.Info()&types.IsInteger != 0 && typeTo.Info()&types.IsFloat != 0 {
// Conversion from int to float. // Conversion from int to float.
if typeFrom.Info()&types.IsUnsigned != 0 { // if unsigned if typeFrom.Info()&types.IsUnsigned != 0 { // if unsigned
return c.builder.CreateUIToFP(value, llvmTypeTo, ""), nil return b.CreateUIToFP(value, llvmTypeTo, ""), nil
} else { // if signed } else { // if signed
return c.builder.CreateSIToFP(value, llvmTypeTo, ""), nil return b.CreateSIToFP(value, llvmTypeTo, ""), nil
} }
} }
if typeFrom.Kind() == types.Complex128 && typeTo.Kind() == types.Complex64 { if typeFrom.Kind() == types.Complex128 && typeTo.Kind() == types.Complex64 {
// Conversion from complex128 to complex64. // Conversion from complex128 to complex64.
r := c.builder.CreateExtractValue(value, 0, "real.f64") r := b.CreateExtractValue(value, 0, "real.f64")
i := c.builder.CreateExtractValue(value, 1, "imag.f64") i := b.CreateExtractValue(value, 1, "imag.f64")
r = c.builder.CreateFPTrunc(r, c.ctx.FloatType(), "real.f32") r = b.CreateFPTrunc(r, b.ctx.FloatType(), "real.f32")
i = c.builder.CreateFPTrunc(i, c.ctx.FloatType(), "imag.f32") i = b.CreateFPTrunc(i, b.ctx.FloatType(), "imag.f32")
cplx := llvm.Undef(c.ctx.StructType([]llvm.Type{c.ctx.FloatType(), c.ctx.FloatType()}, false)) cplx := llvm.Undef(b.ctx.StructType([]llvm.Type{b.ctx.FloatType(), b.ctx.FloatType()}, false))
cplx = c.builder.CreateInsertValue(cplx, r, 0, "") cplx = b.CreateInsertValue(cplx, r, 0, "")
cplx = c.builder.CreateInsertValue(cplx, i, 1, "") cplx = b.CreateInsertValue(cplx, i, 1, "")
return cplx, nil return cplx, nil
} }
if typeFrom.Kind() == types.Complex64 && typeTo.Kind() == types.Complex128 { if typeFrom.Kind() == types.Complex64 && typeTo.Kind() == types.Complex128 {
// Conversion from complex64 to complex128. // Conversion from complex64 to complex128.
r := c.builder.CreateExtractValue(value, 0, "real.f32") r := b.CreateExtractValue(value, 0, "real.f32")
i := c.builder.CreateExtractValue(value, 1, "imag.f32") i := b.CreateExtractValue(value, 1, "imag.f32")
r = c.builder.CreateFPExt(r, c.ctx.DoubleType(), "real.f64") r = b.CreateFPExt(r, b.ctx.DoubleType(), "real.f64")
i = c.builder.CreateFPExt(i, c.ctx.DoubleType(), "imag.f64") i = b.CreateFPExt(i, b.ctx.DoubleType(), "imag.f64")
cplx := llvm.Undef(c.ctx.StructType([]llvm.Type{c.ctx.DoubleType(), c.ctx.DoubleType()}, false)) cplx := llvm.Undef(b.ctx.StructType([]llvm.Type{b.ctx.DoubleType(), b.ctx.DoubleType()}, false))
cplx = c.builder.CreateInsertValue(cplx, r, 0, "") cplx = b.CreateInsertValue(cplx, r, 0, "")
cplx = c.builder.CreateInsertValue(cplx, i, 1, "") cplx = b.CreateInsertValue(cplx, i, 1, "")
return cplx, nil return cplx, nil
} }
return llvm.Value{}, c.makeError(pos, "todo: convert: basic non-integer type: "+typeFrom.String()+" -> "+typeTo.String()) return llvm.Value{}, b.makeError(pos, "todo: convert: basic non-integer type: "+typeFrom.String()+" -> "+typeTo.String())
case *types.Slice: case *types.Slice:
if basic, ok := typeFrom.(*types.Basic); !ok || basic.Info()&types.IsString == 0 { if basic, ok := typeFrom.(*types.Basic); !ok || basic.Info()&types.IsString == 0 {
@ -2511,15 +2512,15 @@ func (c *Compiler) parseConvert(typeFrom, typeTo types.Type, value llvm.Value, p
elemType := typeTo.Elem().Underlying().(*types.Basic) // must be byte or rune elemType := typeTo.Elem().Underlying().(*types.Basic) // must be byte or rune
switch elemType.Kind() { switch elemType.Kind() {
case types.Byte: case types.Byte:
return c.createRuntimeCall("stringToBytes", []llvm.Value{value}, ""), nil return b.createRuntimeCall("stringToBytes", []llvm.Value{value}, ""), nil
case types.Rune: case types.Rune:
return c.createRuntimeCall("stringToRunes", []llvm.Value{value}, ""), nil return b.createRuntimeCall("stringToRunes", []llvm.Value{value}, ""), nil
default: default:
panic("unexpected type in string to slice conversion") panic("unexpected type in string to slice conversion")
} }
default: default:
return llvm.Value{}, c.makeError(pos, "todo: convert "+typeTo.String()+" <- "+typeFrom.String()) return llvm.Value{}, b.makeError(pos, "todo: convert "+typeTo.String()+" <- "+typeFrom.String())
} }
} }

Просмотреть файл

@ -36,7 +36,7 @@ func (c *Compiler) emitMakeMap(frame *Frame, expr *ssa.MakeMap) (llvm.Value, err
if expr.Reserve != nil { if expr.Reserve != nil {
sizeHint = frame.getValue(expr.Reserve) sizeHint = frame.getValue(expr.Reserve)
var err error var err error
sizeHint, err = c.parseConvert(expr.Reserve.Type(), types.Typ[types.Uintptr], sizeHint, expr.Pos()) sizeHint, err = frame.createConvert(expr.Reserve.Type(), types.Typ[types.Uintptr], sizeHint, expr.Pos())
if err != nil { if err != nil {
return llvm.Value{}, err return llvm.Value{}, err
} }