merge Field/Extract; prog.Tuple/Zero; TypeAssert refactor
This commit is contained in:
59
ssa/expr.go
59
ssa/expr.go
@@ -93,6 +93,40 @@ func phisExpr(t Type, phis []llvm.Value) Expr {
|
|||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
func (p Program) Zero(t Type) Expr {
|
||||||
|
var ret llvm.Value
|
||||||
|
switch u := t.raw.Type.Underlying().(type) {
|
||||||
|
case *types.Basic:
|
||||||
|
kind := u.Kind()
|
||||||
|
switch {
|
||||||
|
case kind >= types.Bool && kind <= types.Uintptr:
|
||||||
|
ret = llvm.ConstInt(p.rawType(u).ll, 0, false)
|
||||||
|
case kind == types.String:
|
||||||
|
ret = p.Zero(p.rtType("String")).impl
|
||||||
|
case kind == types.UnsafePointer:
|
||||||
|
ret = llvm.ConstPointerNull(p.tyVoidPtr())
|
||||||
|
case kind <= types.Float64:
|
||||||
|
ret = llvm.ConstFloat(p.Float64().ll, 0)
|
||||||
|
case kind == types.Float32:
|
||||||
|
ret = llvm.ConstFloat(p.Float32().ll, 0)
|
||||||
|
default:
|
||||||
|
panic("todo")
|
||||||
|
}
|
||||||
|
case *types.Pointer:
|
||||||
|
return Expr{llvm.ConstNull(t.ll), t}
|
||||||
|
case *types.Struct:
|
||||||
|
n := u.NumFields()
|
||||||
|
flds := make([]llvm.Value, n)
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
flds[i] = p.Zero(p.rawType(u.Field(i).Type())).impl
|
||||||
|
}
|
||||||
|
ret = llvm.ConstStruct(flds, false)
|
||||||
|
default:
|
||||||
|
log.Panicln("todo:", u)
|
||||||
|
}
|
||||||
|
return Expr{ret, t}
|
||||||
|
}
|
||||||
|
|
||||||
// Null returns a null constant expression.
|
// Null returns a null constant expression.
|
||||||
func (p Program) Null(t Type) Expr {
|
func (p Program) Null(t Type) Expr {
|
||||||
return Expr{llvm.ConstNull(t.ll), t}
|
return Expr{llvm.ConstNull(t.ll), t}
|
||||||
@@ -125,12 +159,6 @@ func (p Program) FloatVal(v float64, t Type) Expr {
|
|||||||
return Expr{ret, t}
|
return Expr{ret, t}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p Program) ByteVal(v byte) Expr {
|
|
||||||
t := p.Byte()
|
|
||||||
ret := llvm.ConstInt(t.ll, uint64(v), false)
|
|
||||||
return Expr{ret, t}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Val returns a constant expression.
|
// Val returns a constant expression.
|
||||||
func (p Program) Val(v interface{}) Expr {
|
func (p Program) Val(v interface{}) Expr {
|
||||||
switch v := v.(type) {
|
switch v := v.(type) {
|
||||||
@@ -941,21 +969,6 @@ func (b Builder) Call(fn Expr, args ...Expr) (ret Expr) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// The Extract instruction yields component Index of Tuple.
|
|
||||||
//
|
|
||||||
// This is used to access the results of instructions with multiple
|
|
||||||
// return values, such as Call, TypeAssert, Next, UnOp(ARROW) and
|
|
||||||
// IndexExpr(Map).
|
|
||||||
//
|
|
||||||
// Example printed form:
|
|
||||||
//
|
|
||||||
// t1 = extract t0 #1
|
|
||||||
func (b Builder) Extract(x Expr, index int) (ret Expr) {
|
|
||||||
ret.Type = b.Prog.toType(x.Type.raw.Type.(*types.Tuple).At(index).Type())
|
|
||||||
ret.impl = llvm.CreateExtractValue(b.impl, x.impl, index)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// A Builtin represents a specific use of a built-in function, e.g. len.
|
// A Builtin represents a specific use of a built-in function, e.g. len.
|
||||||
//
|
//
|
||||||
// Builtins are immutable values. Builtins do not have addresses.
|
// Builtins are immutable values. Builtins do not have addresses.
|
||||||
@@ -1009,7 +1022,7 @@ func (b Builder) BuiltinCall(fn string, args ...Expr) (ret Expr) {
|
|||||||
ret.Type = prog.Void()
|
ret.Type = prog.Void()
|
||||||
for i, arg := range args {
|
for i, arg := range args {
|
||||||
if ln && i > 0 {
|
if ln && i > 0 {
|
||||||
b.InlineCall(b.Pkg.rtFunc("PrintByte"), prog.ByteVal(' '))
|
b.InlineCall(b.Pkg.rtFunc("PrintByte"), prog.IntVal(' ', prog.Byte()))
|
||||||
}
|
}
|
||||||
var fn string
|
var fn string
|
||||||
typ := arg.Type
|
typ := arg.Type
|
||||||
@@ -1049,7 +1062,7 @@ func (b Builder) BuiltinCall(fn string, args ...Expr) (ret Expr) {
|
|||||||
b.InlineCall(b.Pkg.rtFunc(fn), arg)
|
b.InlineCall(b.Pkg.rtFunc(fn), arg)
|
||||||
}
|
}
|
||||||
if ln {
|
if ln {
|
||||||
b.InlineCall(b.Pkg.rtFunc("PrintByte"), prog.ByteVal('\n'))
|
b.InlineCall(b.Pkg.rtFunc("PrintByte"), prog.IntVal('\n', prog.Byte()))
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
case "copy":
|
case "copy":
|
||||||
|
|||||||
133
ssa/interface.go
133
ssa/interface.go
@@ -161,11 +161,13 @@ func (b Builder) makeIntfAlloc(tinter Type, rawIntf *types.Interface, typ Type,
|
|||||||
|
|
||||||
func (b Builder) makeIntfByPtr(tinter Type, rawIntf *types.Interface, typ Type, vptr Expr) (ret Expr) {
|
func (b Builder) makeIntfByPtr(tinter Type, rawIntf *types.Interface, typ Type, vptr Expr) (ret Expr) {
|
||||||
if rawIntf.Empty() {
|
if rawIntf.Empty() {
|
||||||
return Expr{b.unsafeEface(b.abiType(typ.raw.Type).impl, vptr.impl), tinter}
|
tabi := b.abiType(typ.raw.Type)
|
||||||
|
return Expr{b.unsafeEface(tabi.impl, vptr.impl), tinter}
|
||||||
}
|
}
|
||||||
panic("todo")
|
panic("todo")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(xsw): remove MakeAnyIntptr, MakeAnyString
|
||||||
func (b Builder) makeIntfByIntptr(tinter Type, rawIntf *types.Interface, typ Type, x llvm.Value) (ret Expr) {
|
func (b Builder) makeIntfByIntptr(tinter Type, rawIntf *types.Interface, typ Type, x llvm.Value) (ret Expr) {
|
||||||
if rawIntf.Empty() {
|
if rawIntf.Empty() {
|
||||||
tptr := b.Prog.Uintptr()
|
tptr := b.Prog.Uintptr()
|
||||||
@@ -176,45 +178,7 @@ func (b Builder) makeIntfByIntptr(tinter Type, rawIntf *types.Interface, typ Typ
|
|||||||
panic("todo")
|
panic("todo")
|
||||||
}
|
}
|
||||||
|
|
||||||
// The TypeAssert instruction tests whether interface value X has type
|
/*
|
||||||
// AssertedType.
|
|
||||||
//
|
|
||||||
// If !CommaOk, on success it returns v, the result of the conversion
|
|
||||||
// (defined below); on failure it panics.
|
|
||||||
//
|
|
||||||
// If CommaOk: on success it returns a pair (v, true) where v is the
|
|
||||||
// result of the conversion; on failure it returns (z, false) where z
|
|
||||||
// is AssertedType's zero value. The components of the pair must be
|
|
||||||
// accessed using the Extract instruction.
|
|
||||||
//
|
|
||||||
// If Underlying: tests whether interface value X has the underlying
|
|
||||||
// type AssertedType.
|
|
||||||
//
|
|
||||||
// If AssertedType is a concrete type, TypeAssert checks whether the
|
|
||||||
// dynamic type in interface X is equal to it, and if so, the result
|
|
||||||
// of the conversion is a copy of the value in the interface.
|
|
||||||
//
|
|
||||||
// If AssertedType is an interface, TypeAssert checks whether the
|
|
||||||
// dynamic type of the interface is assignable to it, and if so, the
|
|
||||||
// result of the conversion is a copy of the interface value X.
|
|
||||||
// If AssertedType is a superinterface of X.Type(), the operation will
|
|
||||||
// fail iff the operand is nil. (Contrast with ChangeInterface, which
|
|
||||||
// performs no nil-check.)
|
|
||||||
//
|
|
||||||
// Type() reflects the actual type of the result, possibly a
|
|
||||||
// 2-types.Tuple; AssertedType is the asserted type.
|
|
||||||
//
|
|
||||||
// Depending on the TypeAssert's purpose, Pos may return:
|
|
||||||
// - the ast.CallExpr.Lparen of an explicit T(e) conversion;
|
|
||||||
// - the ast.TypeAssertExpr.Lparen of an explicit e.(T) operation;
|
|
||||||
// - the ast.CaseClause.Case of a case of a type-switch statement;
|
|
||||||
// - the Ident(m).NamePos of an interface method value i.m
|
|
||||||
// (for which TypeAssert may be used to effect the nil check).
|
|
||||||
//
|
|
||||||
// Example printed form:
|
|
||||||
//
|
|
||||||
// t1 = typeassert t0.(int)
|
|
||||||
// t3 = typeassert,ok t2.(T)
|
|
||||||
func (b Builder) TypeAssert(x Expr, assertedTyp Type, commaOk bool) (ret Expr) {
|
func (b Builder) TypeAssert(x Expr, assertedTyp Type, commaOk bool) (ret Expr) {
|
||||||
if debugInstr {
|
if debugInstr {
|
||||||
log.Printf("TypeAssert %v, %v, %v\n", x.impl, assertedTyp.raw.Type, commaOk)
|
log.Printf("TypeAssert %v, %v, %v\n", x.impl, assertedTyp.raw.Type, commaOk)
|
||||||
@@ -277,10 +241,89 @@ func (b Builder) TypeAssert(x Expr, assertedTyp Type, commaOk bool) (ret Expr) {
|
|||||||
fnName = "CheckI2String"
|
fnName = "CheckI2String"
|
||||||
}
|
}
|
||||||
return b.InlineCall(pkg.rtFunc(fnName), x)
|
return b.InlineCall(pkg.rtFunc(fnName), x)
|
||||||
case vkStruct:
|
|
||||||
}
|
}
|
||||||
panic("todo")
|
panic("todo")
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// The TypeAssert instruction tests whether interface value X has type
|
||||||
|
// AssertedType.
|
||||||
|
//
|
||||||
|
// If !CommaOk, on success it returns v, the result of the conversion
|
||||||
|
// (defined below); on failure it panics.
|
||||||
|
//
|
||||||
|
// If CommaOk: on success it returns a pair (v, true) where v is the
|
||||||
|
// result of the conversion; on failure it returns (z, false) where z
|
||||||
|
// is AssertedType's zero value. The components of the pair must be
|
||||||
|
// accessed using the Extract instruction.
|
||||||
|
//
|
||||||
|
// If Underlying: tests whether interface value X has the underlying
|
||||||
|
// type AssertedType.
|
||||||
|
//
|
||||||
|
// If AssertedType is a concrete type, TypeAssert checks whether the
|
||||||
|
// dynamic type in interface X is equal to it, and if so, the result
|
||||||
|
// of the conversion is a copy of the value in the interface.
|
||||||
|
//
|
||||||
|
// If AssertedType is an interface, TypeAssert checks whether the
|
||||||
|
// dynamic type of the interface is assignable to it, and if so, the
|
||||||
|
// result of the conversion is a copy of the interface value X.
|
||||||
|
// If AssertedType is a superinterface of X.Type(), the operation will
|
||||||
|
// fail iff the operand is nil. (Contrast with ChangeInterface, which
|
||||||
|
// performs no nil-check.)
|
||||||
|
//
|
||||||
|
// Type() reflects the actual type of the result, possibly a
|
||||||
|
// 2-types.Tuple; AssertedType is the asserted type.
|
||||||
|
//
|
||||||
|
// Depending on the TypeAssert's purpose, Pos may return:
|
||||||
|
// - the ast.CallExpr.Lparen of an explicit T(e) conversion;
|
||||||
|
// - the ast.TypeAssertExpr.Lparen of an explicit e.(T) operation;
|
||||||
|
// - the ast.CaseClause.Case of a case of a type-switch statement;
|
||||||
|
// - the Ident(m).NamePos of an interface method value i.m
|
||||||
|
// (for which TypeAssert may be used to effect the nil check).
|
||||||
|
//
|
||||||
|
// Example printed form:
|
||||||
|
//
|
||||||
|
// t1 = typeassert t0.(int)
|
||||||
|
// t3 = typeassert,ok t2.(T)
|
||||||
|
func (b Builder) TypeAssert(x Expr, assertedTyp Type, commaOk bool) Expr {
|
||||||
|
if debugInstr {
|
||||||
|
log.Printf("TypeAssert %v, %v, %v\n", x.impl, assertedTyp.raw.Type, commaOk)
|
||||||
|
}
|
||||||
|
tx := b.faceAbiType(x)
|
||||||
|
tabi := b.abiType(assertedTyp.raw.Type)
|
||||||
|
eq := b.BinOp(token.EQL, tx, tabi)
|
||||||
|
if commaOk {
|
||||||
|
/*
|
||||||
|
prog := b.Prog
|
||||||
|
t := prog.Tuple(assertedTyp, prog.Bool())
|
||||||
|
val := b.valFromData(assertedTyp, b.InterfaceData(x))
|
||||||
|
zero := prog.Zero(assertedTyp)
|
||||||
|
valTrue := aggregateValue(b.impl, t.ll, val.impl, prog.BoolVal(true).impl)
|
||||||
|
valFalse := aggregateValue(b.impl, t.ll, zero.impl, prog.BoolVal(false).impl)
|
||||||
|
return Expr{llvm.CreateSelect(b.impl, eq.impl, valTrue, valFalse), t}
|
||||||
|
*/
|
||||||
|
panic("todo")
|
||||||
|
}
|
||||||
|
blks := b.Func.MakeBlocks(2)
|
||||||
|
b.If(eq, blks[0], blks[1])
|
||||||
|
b.SetBlock(blks[1])
|
||||||
|
b.Panic(b.Str("type assertion failed"))
|
||||||
|
b.SetBlock(blks[0])
|
||||||
|
return b.valFromData(assertedTyp, b.InterfaceData(x))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b Builder) valFromData(t Type, data Expr) Expr {
|
||||||
|
switch u := t.raw.Type.Underlying().(type) {
|
||||||
|
case *types.Basic:
|
||||||
|
kind := u.Kind()
|
||||||
|
switch {
|
||||||
|
case kind >= types.Bool && kind <= types.Uintptr:
|
||||||
|
panic("todo")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ = data
|
||||||
|
panic("todo")
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
@@ -293,4 +336,12 @@ func (b Builder) InterfaceData(x Expr) Expr {
|
|||||||
return Expr{ptr, b.Prog.VoidPtr()}
|
return Expr{ptr, b.Prog.VoidPtr()}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b Builder) faceAbiType(x Expr) Expr {
|
||||||
|
if x.kind == vkIface {
|
||||||
|
panic("todo")
|
||||||
|
}
|
||||||
|
typ := llvm.CreateExtractValue(b.impl, x.impl, 0)
|
||||||
|
return Expr{typ, b.Prog.AbiTypePtr()}
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -137,6 +137,7 @@ type aProgram struct {
|
|||||||
intTy Type
|
intTy Type
|
||||||
uintTy Type
|
uintTy Type
|
||||||
f64Ty Type
|
f64Ty Type
|
||||||
|
f32Ty Type
|
||||||
byteTy Type
|
byteTy Type
|
||||||
i32Ty Type
|
i32Ty Type
|
||||||
u32Ty Type
|
u32Ty Type
|
||||||
@@ -293,6 +294,16 @@ func (p Program) NewPackage(name, pkgPath string) Package {
|
|||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tuple returns a tuple type.
|
||||||
|
func (p Program) Tuple(typs ...Type) Type {
|
||||||
|
n := len(typs)
|
||||||
|
els := make([]*types.Var, n)
|
||||||
|
for i, t := range typs {
|
||||||
|
els[i] = types.NewParam(token.NoPos, nil, "", t.raw.Type)
|
||||||
|
}
|
||||||
|
return p.rawType(types.NewTuple(els...))
|
||||||
|
}
|
||||||
|
|
||||||
// Eface returns the empty interface type.
|
// Eface returns the empty interface type.
|
||||||
func (p Program) Eface() Type {
|
func (p Program) Eface() Type {
|
||||||
if p.efaceTy == nil {
|
if p.efaceTy == nil {
|
||||||
@@ -418,6 +429,14 @@ func (p Program) Float64() Type {
|
|||||||
return p.f64Ty
|
return p.f64Ty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Float32 returns float32 type.
|
||||||
|
func (p Program) Float32() Type {
|
||||||
|
if p.f32Ty == nil {
|
||||||
|
p.f32Ty = p.rawType(types.Typ[types.Float32])
|
||||||
|
}
|
||||||
|
return p.f32Ty
|
||||||
|
}
|
||||||
|
|
||||||
// Byte returns byte type.
|
// Byte returns byte type.
|
||||||
func (p Program) Byte() Type {
|
func (p Program) Byte() Type {
|
||||||
if p.byteTy == nil {
|
if p.byteTy == nil {
|
||||||
|
|||||||
@@ -160,6 +160,22 @@ func (b Builder) Return(results ...Expr) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The Extract instruction yields component Index of Tuple.
|
||||||
|
//
|
||||||
|
// This is used to access the results of instructions with multiple
|
||||||
|
// return values, such as Call, TypeAssert, Next, UnOp(ARROW) and
|
||||||
|
// IndexExpr(Map).
|
||||||
|
//
|
||||||
|
// Example printed form:
|
||||||
|
//
|
||||||
|
// t1 = extract t0 #1
|
||||||
|
func (b Builder) Extract(x Expr, i int) (ret Expr) {
|
||||||
|
if debugInstr {
|
||||||
|
log.Printf("Extract %v, %d\n", x.impl, i)
|
||||||
|
}
|
||||||
|
return b.getField(x, i)
|
||||||
|
}
|
||||||
|
|
||||||
// Jump emits a jump instruction.
|
// Jump emits a jump instruction.
|
||||||
func (b Builder) Jump(jmpb BasicBlock) {
|
func (b Builder) Jump(jmpb BasicBlock) {
|
||||||
if b.Func != jmpb.fn {
|
if b.Func != jmpb.fn {
|
||||||
|
|||||||
15
ssa/type.go
15
ssa/type.go
@@ -141,9 +141,14 @@ func (p Program) Index(typ Type) Type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p Program) Field(typ Type, i int) Type {
|
func (p Program) Field(typ Type, i int) Type {
|
||||||
tunder := typ.raw.Type.Underlying()
|
var fld *types.Var
|
||||||
tfld := tunder.(*types.Struct).Field(i).Type()
|
switch t := typ.raw.Type.(type) {
|
||||||
return p.rawType(tfld)
|
case *types.Tuple:
|
||||||
|
fld = t.At(i)
|
||||||
|
default:
|
||||||
|
fld = t.Underlying().(*types.Struct).Field(i)
|
||||||
|
}
|
||||||
|
return p.rawType(fld.Type())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p Program) rawType(raw types.Type) Type {
|
func (p Program) rawType(raw types.Type) Type {
|
||||||
@@ -218,9 +223,11 @@ func (p Program) tyInt64() llvm.Type {
|
|||||||
return p.int64Type
|
return p.int64Type
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
func (p Program) toTuple(typ *types.Tuple) Type {
|
func (p Program) toTuple(typ *types.Tuple) Type {
|
||||||
return &aType{p.toLLVMTuple(typ), rawType{typ}, vkTuple}
|
return &aType{p.toLLVMTuple(typ), rawType{typ}, vkTuple}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
func (p Program) toType(raw types.Type) Type {
|
func (p Program) toType(raw types.Type) Type {
|
||||||
typ := rawType{raw}
|
typ := rawType{raw}
|
||||||
@@ -385,7 +392,7 @@ func (p Program) toNamed(raw *types.Named) Type {
|
|||||||
switch t := raw.Underlying().(type) {
|
switch t := raw.Underlying().(type) {
|
||||||
case *types.Struct:
|
case *types.Struct:
|
||||||
name := NameOf(raw)
|
name := NameOf(raw)
|
||||||
return &aType{p.toLLVMNamedStruct(name, t), rawType{raw}, vkInvalid}
|
return &aType{p.toLLVMNamedStruct(name, t), rawType{raw}, vkStruct}
|
||||||
default:
|
default:
|
||||||
return p.rawType(t)
|
return p.rawType(t)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user