llgo/ssa: ChangeType, Convert

This commit is contained in:
xushiwei
2024-04-28 06:23:21 +08:00
parent c97c1e97b9
commit 475f0fa2ff
2 changed files with 58 additions and 4 deletions

View File

@@ -300,6 +300,10 @@ func (p *context) compileInstrAndValue(b llssa.Builder, iv instrAndValue) (ret l
t := v.Type() t := v.Type()
x := p.compileValue(b, v.X) x := p.compileValue(b, v.X)
ret = b.ChangeType(p.prog.Type(t), 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: case *ssa.FieldAddr:
x := p.compileValue(b, v.X) x := p.compileValue(b, v.X)
ret = b.FieldAddr(x, v.Field) ret = b.FieldAddr(x, v.Field)

View File

@@ -110,6 +110,9 @@ func (p Program) Val(v interface{}) Expr {
} }
func (b Builder) Const(v constant.Value, typ Type) Expr { func (b Builder) Const(v constant.Value, typ Type) Expr {
if v == nil {
return b.prog.Null(typ)
}
switch t := typ.t.(type) { switch t := typ.t.(type) {
case *types.Basic: case *types.Basic:
kind := t.Kind() 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 // types in the type set of X.Type() have a value-preserving type
// change to all types in the type set of 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: // Example printed form:
// //
// t1 = changetype *int <- IntPtr (t0) // t1 = changetype *int <- IntPtr (t0)
@@ -422,9 +422,58 @@ func (b Builder) ChangeType(t Type, x Expr) (ret Expr) {
} }
typ := t.t typ := t.t
switch typ.(type) { 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: case *types.Pointer:
ret.impl = b.impl.CreatePointerCast(x.impl, t.ll, "castPtr") ret.impl = b.impl.CreatePointerCast(x.impl, t.ll, "castPtr")
ret.Type = b.prog.Type(typ)
return return
} }
panic("todo") 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) { func (b Builder) InlineCall(fn Expr, args ...Expr) (ret Expr) {
return b.Call(fn, args...) return b.Call(fn, args...)
} }