compiler: add complex manipulation

* builtins: real, imag, complex
* printing of complex numbers

No support for complex arithmetic yet.
Этот коммит содержится в:
Ayke van Laethem 2018-10-22 13:44:59 +02:00
родитель 9393cdd5ed
коммит 9b9b66a09d
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: E97FF5335DFDFDED
7 изменённых файлов: 145 добавлений и 7 удалений

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

@ -56,10 +56,11 @@ Currently supported features:
* defer
* closures
* bound methods
* complex numbers (except for arithmetic)
Not yet supported:
* complex numbers
* complex arithmetic
* garbage collection
* recover
* channels

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

@ -679,13 +679,13 @@ func (c *Compiler) getZeroValue(typ llvm.Type) (llvm.Value, error) {
switch typ.TypeKind() {
case llvm.ArrayTypeKind:
subTyp := typ.ElementType()
subVal, err := c.getZeroValue(subTyp)
if err != nil {
return llvm.Value{}, err
}
vals := make([]llvm.Value, typ.ArrayLength())
for i := range vals {
val, err := c.getZeroValue(subTyp)
if err != nil {
return llvm.Value{}, err
}
vals[i] = val
vals[i] = subVal
}
return llvm.ConstArray(subTyp, vals), nil
case llvm.FloatTypeKind, llvm.DoubleTypeKind:
@ -709,8 +709,18 @@ func (c *Compiler) getZeroValue(typ llvm.Type) (llvm.Value, error) {
} else {
return c.ctx.ConstStruct(vals, false), nil
}
case llvm.VectorTypeKind:
zero, err := c.getZeroValue(typ.ElementType())
if err != nil {
return llvm.Value{}, err
}
vals := make([]llvm.Value, typ.VectorSize())
for i := range vals {
vals[i] = zero
}
return llvm.ConstVector(vals, false), nil
default:
return llvm.Value{}, errors.New("todo: LLVM zero initializer")
return llvm.Value{}, errors.New("todo: LLVM zero initializer: " + typ.String())
}
}
@ -1679,6 +1689,30 @@ func (c *Compiler) parseBuiltin(frame *Frame, args []ssa.Value, callName string)
default:
return llvm.Value{}, errors.New("todo: cap: unknown type")
}
case "complex":
r, err := c.parseExpr(frame, args[0])
if err != nil {
return llvm.Value{}, err
}
i, err := c.parseExpr(frame, args[1])
if err != nil {
return llvm.Value{}, err
}
t := args[0].Type().Underlying().(*types.Basic)
switch t.Kind() {
case types.Float32:
cplx := llvm.Undef(llvm.VectorType(c.ctx.FloatType(), 2))
cplx = c.builder.CreateInsertValue(cplx, r, 0, "")
cplx = c.builder.CreateInsertValue(cplx, i, 1, "")
return cplx, nil
case types.Float64:
cplx := llvm.Undef(llvm.VectorType(c.ctx.DoubleType(), 2))
cplx = c.builder.CreateInsertValue(cplx, r, 0, "")
cplx = c.builder.CreateInsertValue(cplx, i, 1, "")
return cplx, nil
default:
return llvm.Value{}, errors.New("unsupported type in complex builtin: " + t.String())
}
case "copy":
dst, err := c.parseExpr(frame, args[0])
if err != nil {
@ -1707,6 +1741,13 @@ func (c *Compiler) parseBuiltin(frame *Frame, args []ssa.Value, callName string)
return llvm.Value{}, err
}
return llvm.Value{}, c.emitMapDelete(args[1].Type(), m, key)
case "imag":
cplx, err := c.parseExpr(frame, args[0])
if err != nil {
return llvm.Value{}, err
}
index := llvm.ConstInt(c.ctx.Int32Type(), 1, false)
return c.builder.CreateExtractElement(cplx, index, "imag"), nil
case "len":
value, err := c.parseExpr(frame, args[0])
if err != nil {
@ -1768,6 +1809,10 @@ func (c *Compiler) parseBuiltin(frame *Frame, args []ssa.Value, callName string)
c.createRuntimeCall("printfloat32", []llvm.Value{value}, "")
} else if typ.Kind() == types.Float64 {
c.createRuntimeCall("printfloat64", []llvm.Value{value}, "")
} else if typ.Kind() == types.Complex64 {
c.createRuntimeCall("printcomplex64", []llvm.Value{value}, "")
} else if typ.Kind() == types.Complex128 {
c.createRuntimeCall("printcomplex128", []llvm.Value{value}, "")
} else {
return llvm.Value{}, errors.New("unknown basic arg type: " + typ.String())
}
@ -1787,6 +1832,13 @@ func (c *Compiler) parseBuiltin(frame *Frame, args []ssa.Value, callName string)
c.createRuntimeCall("printnl", nil, "")
}
return llvm.Value{}, nil // print() or println() returns void
case "real":
cplx, err := c.parseExpr(frame, args[0])
if err != nil {
return llvm.Value{}, err
}
index := llvm.ConstInt(c.ctx.Int32Type(), 0, false)
return c.builder.CreateExtractElement(cplx, index, "real"), nil
case "recover":
return c.createRuntimeCall("_recover", nil, ""), nil
case "ssa:wrapnilchk":
@ -2940,6 +2992,19 @@ func (c *Compiler) parseConst(prefix string, expr *ssa.Const) (llvm.Value, error
} else if typ.Info()&types.IsFloat != 0 {
n, _ := constant.Float64Val(expr.Value)
return llvm.ConstFloat(llvmType, n), nil
} else if typ.Kind() == types.Complex128 {
r, err := c.parseConst(prefix, ssa.NewConst(constant.Real(expr.Value), types.Typ[types.Float64]))
if err != nil {
return llvm.Value{}, err
}
i, err := c.parseConst(prefix, ssa.NewConst(constant.Imag(expr.Value), types.Typ[types.Float64]))
if err != nil {
return llvm.Value{}, err
}
cplx := llvm.Undef(llvm.VectorType(c.ctx.DoubleType(), 2))
cplx = c.builder.CreateInsertValue(cplx, r, 0, "")
cplx = c.builder.CreateInsertValue(cplx, i, 1, "")
return cplx, nil
} else {
return llvm.Value{}, errors.New("todo: unknown constant: " + expr.String())
}
@ -3088,6 +3153,30 @@ func (c *Compiler) parseConvert(typeFrom, typeTo types.Type, value llvm.Value) (
}
}
if typeFrom.Kind() == types.Complex128 && typeTo.Kind() == types.Complex64 {
// Conversion from complex128 to complex64.
r := c.builder.CreateExtractElement(value, llvm.ConstInt(c.ctx.Int32Type(), 0, false), "real.f64")
i := c.builder.CreateExtractElement(value, llvm.ConstInt(c.ctx.Int32Type(), 1, false), "imag.f64")
r = c.builder.CreateFPTrunc(r, c.ctx.FloatType(), "real.f32")
i = c.builder.CreateFPTrunc(i, c.ctx.FloatType(), "imag.f32")
cplx := llvm.Undef(llvm.VectorType(c.ctx.FloatType(), 2))
cplx = c.builder.CreateInsertValue(cplx, r, 0, "")
cplx = c.builder.CreateInsertValue(cplx, i, 1, "")
return cplx, nil
}
if typeFrom.Kind() == types.Complex64 && typeTo.Kind() == types.Complex128 {
// Conversion from complex64 to complex128.
r := c.builder.CreateExtractElement(value, llvm.ConstInt(c.ctx.Int32Type(), 0, false), "real.f32")
i := c.builder.CreateExtractElement(value, llvm.ConstInt(c.ctx.Int32Type(), 1, false), "imag.f32")
r = c.builder.CreateFPExt(r, c.ctx.DoubleType(), "real.f64")
i = c.builder.CreateFPExt(i, c.ctx.DoubleType(), "imag.f64")
cplx := llvm.Undef(llvm.VectorType(c.ctx.DoubleType(), 2))
cplx = c.builder.CreateInsertValue(cplx, r, 0, "")
cplx = c.builder.CreateInsertValue(cplx, i, 1, "")
return cplx, nil
}
return llvm.Value{}, errors.New("todo: convert: basic non-integer type: " + typeFrom.String() + " -> " + typeTo.String())
case *types.Slice:

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

@ -174,6 +174,20 @@ func printfloat64(v float64) {
}
}
func printcomplex64(c complex64) {
putchar('(')
printfloat32(real(c))
printfloat32(imag(c))
printstring("i)")
}
func printcomplex128(c complex128) {
putchar('(')
printfloat64(real(c))
printfloat64(imag(c))
printstring("i)")
}
func printspace() {
putchar(' ')
}

20
testdata/float.go предоставленный
Просмотреть файл

@ -23,4 +23,24 @@ func main() {
// casting
println(float32(f64))
println(float64(f32))
// complex64
c64 := complex(f32, 1.2)
println(c64)
println(real(c64))
println(imag(c64))
// complex128
c128 := complex(f64, -2.0)
println(c128)
println(real(c128))
println(imag(c128))
// untyped complex
println(2 + 1i)
println(complex(2, -2))
// cast complex
println(complex64(c128))
println(complex128(c64))
}

10
testdata/float.txt предоставленный
Просмотреть файл

@ -11,3 +11,13 @@
+3.333333e-001
+6.666667e-001
+6.666667e-001
(+6.666667e-001+1.200000e+000i)
+6.666667e-001
+1.200000e+000
(+6.666667e-001-2.000000e+000i)
+6.666667e-001
-2.000000e+000
(+2.000000e+000+1.000000e+000i)
(+2.000000e+000-2.000000e+000i)
(+6.666667e-001-2.000000e+000i)
(+6.666667e-001+1.200000e+000i)

3
testdata/print.go предоставленный
Просмотреть файл

@ -29,6 +29,9 @@ func main() {
// print float64
println(3.14)
// print complex128
println(5+1.2345i)
// print interface
println(interface{}(nil))

1
testdata/print.txt предоставленный
Просмотреть файл

@ -16,6 +16,7 @@ a b c
123456789012
-123456789012
+3.140000e+000
(+5.000000e+000+1.234500e+000i)
(0:nil)
map[2]
true false