compiler: refactor parseConvert
Этот коммит содержится в:
родитель
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
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче