diff --git a/cl/compile.go b/cl/compile.go index 9f2e9ceb..3a4fd9fa 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -300,6 +300,10 @@ func (p *context) compileInstrAndValue(b llssa.Builder, iv instrAndValue) (ret l t := v.Type() x := p.compileValue(b, v.X) ret = b.ChangeType(p.prog.Type(t), x) + case *ssa.Convert: + t := v.Type() + x := p.compileValue(b, v.X) + ret = b.Convert(p.prog.Type(t), x) case *ssa.FieldAddr: x := p.compileValue(b, v.X) ret = b.FieldAddr(x, v.Field) diff --git a/ssa/expr.go b/ssa/expr.go index 811d6d06..bbc76f57 100644 --- a/ssa/expr.go +++ b/ssa/expr.go @@ -110,6 +110,9 @@ func (p Program) Val(v interface{}) Expr { } func (b Builder) Const(v constant.Value, typ Type) Expr { + if v == nil { + return b.prog.Null(typ) + } switch t := typ.t.(type) { case *types.Basic: kind := t.Kind() @@ -410,9 +413,6 @@ func (b Builder) Alloc(t Type, heap bool) (ret Expr) { // types in the type set of X.Type() have a value-preserving type // change to all types in the type set of Type(). // -// Pos() returns the ast.CallExpr.Lparen, if the instruction arose -// from an explicit conversion in the source. -// // Example printed form: // // t1 = changetype *int <- IntPtr (t0) @@ -422,9 +422,58 @@ func (b Builder) ChangeType(t Type, x Expr) (ret Expr) { } typ := t.t switch typ.(type) { + default: + ret.impl = b.impl.CreateBitCast(x.impl, t.ll, "bitCast") + ret.Type = b.prog.Type(typ) + return + } +} + +// The Convert instruction yields the conversion of value X to type +// Type(). One or both of those types is basic (but possibly named). +// +// A conversion may change the value and representation of its operand. +// Conversions are permitted: +// - between real numeric types. +// - between complex numeric types. +// - between string and []byte or []rune. +// - between pointers and unsafe.Pointer. +// - between unsafe.Pointer and uintptr. +// - from (Unicode) integer to (UTF-8) string. +// +// A conversion may imply a type name change also. +// +// Conversions may to be to or from a type parameter. All types in +// the type set of X.Type() can be converted to all types in the type +// set of Type(). +// +// This operation cannot fail dynamically. +// +// Conversions of untyped string/number/bool constants to a specific +// representation are eliminated during SSA construction. +// +// Pos() returns the ast.CallExpr.Lparen, if the instruction arose +// from an explicit conversion in the source. +// +// Example printed form: +// +// t1 = convert []byte <- string (t0) +func (b Builder) Convert(t Type, x Expr) (ret Expr) { + typ := t.t + ret.Type = b.prog.Type(typ) + switch und := typ.Underlying().(type) { + case *types.Basic: + kind := und.Kind() + switch { + case kind >= types.Int && kind <= types.Uintptr: + ret.impl = b.impl.CreateIntCast(x.impl, t.ll, "castInt") + return + case kind == types.UnsafePointer: + ret.impl = b.impl.CreatePointerCast(x.impl, t.ll, "castPtr") + return + } case *types.Pointer: ret.impl = b.impl.CreatePointerCast(x.impl, t.ll, "castPtr") - ret.Type = b.prog.Type(typ) return } panic("todo") @@ -534,6 +583,7 @@ func (b Builder) TypeAssert(x Expr, assertedTyp Type, commaOk bool) (ret Expr) { // ----------------------------------------------------------------------------- +// TODO(xsw): make inline call func (b Builder) InlineCall(fn Expr, args ...Expr) (ret Expr) { return b.Call(fn, args...) }