diff --git a/README.markdown b/README.markdown index a8e75c35..fa710c75 100644 --- a/README.markdown +++ b/README.markdown @@ -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 diff --git a/compiler/compiler.go b/compiler/compiler.go index d99622c3..347ff1bf 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -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: diff --git a/src/runtime/print.go b/src/runtime/print.go index 2a42f99c..dfc438dd 100644 --- a/src/runtime/print.go +++ b/src/runtime/print.go @@ -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(' ') } diff --git a/testdata/float.go b/testdata/float.go index ee759cf1..dd11b516 100644 --- a/testdata/float.go +++ b/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)) } diff --git a/testdata/float.txt b/testdata/float.txt index 0cb143de..a5d688bf 100644 --- a/testdata/float.txt +++ b/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) diff --git a/testdata/print.go b/testdata/print.go index a8d2ada6..16e5761f 100644 --- a/testdata/print.go +++ b/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)) diff --git a/testdata/print.txt b/testdata/print.txt index bc03de89..fcffe718 100644 --- a/testdata/print.txt +++ b/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