This commit is contained in:
parent
b77d876ebb
commit
ca9595d1fb
28 changed files with 179 additions and 649 deletions
|
@ -15,7 +15,7 @@ func showSSA(root *core.Function) {
|
||||||
for _, block := range f.Blocks {
|
for _, block := range f.Blocks {
|
||||||
for i, instr := range block.Instructions {
|
for i, instr := range block.Instructions {
|
||||||
ansi.Dim.Printf("%%%-1d = ", i)
|
ansi.Dim.Printf("%%%-1d = ", i)
|
||||||
fmt.Printf("%-30s ", instr.Debug(false))
|
fmt.Printf("%-30s ", instr.String())
|
||||||
ansi.Dim.Printf(" %-30s", instr.Type().Name())
|
ansi.Dim.Printf(" %-30s", instr.Type().Name())
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
}
|
}
|
||||||
|
|
|
@ -149,10 +149,10 @@ func (f *Function) Evaluate(expr *expression.Expression) (ssa.Value, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if fn.IsExtern() {
|
if fn.IsExtern() {
|
||||||
v := f.Append(&ssa.CallExtern{
|
v := f.Append(&ssa.CallExtern{Call: ssa.Call{
|
||||||
Arguments: args,
|
Arguments: args,
|
||||||
Source: ssa.Source(expr.Source),
|
Source: ssa.Source(expr.Source),
|
||||||
})
|
}})
|
||||||
|
|
||||||
return v, nil
|
return v, nil
|
||||||
}
|
}
|
||||||
|
@ -179,7 +179,7 @@ func (f *Function) Evaluate(expr *expression.Expression) (ssa.Value, error) {
|
||||||
return nil, errors.New(&UnknownStructField{StructName: structure.Name(), FieldName: rightText}, f.File, right.Token.Position)
|
return nil, errors.New(&UnknownStructField{StructName: structure.Name(), FieldName: rightText}, f.File, right.Token.Position)
|
||||||
}
|
}
|
||||||
|
|
||||||
v := f.Append(&ssa.StructField{
|
v := f.Append(&ssa.Field{
|
||||||
Struct: identifier,
|
Struct: identifier,
|
||||||
Field: field,
|
Field: field,
|
||||||
Source: ssa.Source(expr.Source),
|
Source: ssa.Source(expr.Source),
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
package ssa
|
|
||||||
|
|
||||||
type Arguments []Value
|
|
||||||
|
|
||||||
func (v Arguments) Dependencies() []Value {
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a Arguments) Equals(b Arguments) bool {
|
|
||||||
if len(a) != len(b) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := range a {
|
|
||||||
if !a[i].Equals(b[i]) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
|
@ -12,14 +12,13 @@ type BinaryOp struct {
|
||||||
Left Value
|
Left Value
|
||||||
Right Value
|
Right Value
|
||||||
Op token.Kind
|
Op token.Kind
|
||||||
Id
|
|
||||||
Liveness
|
Liveness
|
||||||
Source
|
Source
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *BinaryOp) Dependencies() []Value {
|
func (v *BinaryOp) Inputs() []Value { return []Value{v.Left, v.Right} }
|
||||||
return []Value{v.Left, v.Right}
|
func (v *BinaryOp) IsConst() bool { return v.Left.IsConst() && v.Right.IsConst() }
|
||||||
}
|
func (v *BinaryOp) Type() types.Type { return v.Left.Type() }
|
||||||
|
|
||||||
func (a *BinaryOp) Equals(v Value) bool {
|
func (a *BinaryOp) Equals(v Value) bool {
|
||||||
b, sameType := v.(*BinaryOp)
|
b, sameType := v.(*BinaryOp)
|
||||||
|
@ -39,22 +38,6 @@ func (a *BinaryOp) Equals(v Value) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *BinaryOp) IsConst() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *BinaryOp) Debug(expand bool) string {
|
|
||||||
if expand {
|
|
||||||
return fmt.Sprintf("%s %s %s", v.Left, expression.Operators[v.Op].Symbol, v.Right)
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Sprintf("%%%d %s %%%d", v.Left.ID(), expression.Operators[v.Op].Symbol, v.Right.ID())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *BinaryOp) String() string {
|
func (v *BinaryOp) String() string {
|
||||||
return v.Debug(true)
|
return fmt.Sprintf("%s %s %s", v.Left, expression.Operators[v.Op].Symbol, v.Right)
|
||||||
}
|
|
||||||
|
|
||||||
func (v *BinaryOp) Type() types.Type {
|
|
||||||
return v.Left.Type()
|
|
||||||
}
|
}
|
|
@ -7,7 +7,7 @@ type Block struct {
|
||||||
|
|
||||||
// Append adds a new instruction to the block.
|
// Append adds a new instruction to the block.
|
||||||
func (block *Block) Append(instr Value) Value {
|
func (block *Block) Append(instr Value) Value {
|
||||||
for _, dep := range instr.Dependencies() {
|
for _, dep := range instr.Inputs() {
|
||||||
dep.(HasLiveness).AddUser(instr)
|
dep.(HasLiveness).AddUser(instr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,15 +8,15 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Bytes struct {
|
type Bytes struct {
|
||||||
Id
|
|
||||||
Bytes []byte
|
Bytes []byte
|
||||||
Liveness
|
Liveness
|
||||||
Source
|
Source
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Bytes) Dependencies() []Value {
|
func (v *Bytes) Inputs() []Value { return nil }
|
||||||
return nil
|
func (v *Bytes) IsConst() bool { return true }
|
||||||
}
|
func (v *Bytes) String() string { return strconv.Quote(string(v.Bytes)) }
|
||||||
|
func (v *Bytes) Type() types.Type { return types.CString }
|
||||||
|
|
||||||
func (a *Bytes) Equals(v Value) bool {
|
func (a *Bytes) Equals(v Value) bool {
|
||||||
b, sameType := v.(*Bytes)
|
b, sameType := v.(*Bytes)
|
||||||
|
@ -26,20 +26,4 @@ func (a *Bytes) Equals(v Value) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
return bytes.Equal(a.Bytes, b.Bytes)
|
return bytes.Equal(a.Bytes, b.Bytes)
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Bytes) IsConst() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Bytes) Debug(expand bool) string {
|
|
||||||
return v.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Bytes) String() string {
|
|
||||||
return strconv.Quote(string(v.Bytes))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Bytes) Type() types.Type {
|
|
||||||
return types.CString
|
|
||||||
}
|
}
|
|
@ -1,19 +1,19 @@
|
||||||
package ssa
|
package ssa
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strconv"
|
"fmt"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"git.urbach.dev/cli/q/src/types"
|
"git.urbach.dev/cli/q/src/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Call struct {
|
type Call struct {
|
||||||
Id
|
|
||||||
Arguments
|
Arguments
|
||||||
Liveness
|
Liveness
|
||||||
Source
|
Source
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v *Call) IsConst() bool { return false }
|
||||||
|
|
||||||
func (a *Call) Equals(v Value) bool {
|
func (a *Call) Equals(v Value) bool {
|
||||||
b, sameType := v.(*Call)
|
b, sameType := v.(*Call)
|
||||||
|
|
||||||
|
@ -24,42 +24,8 @@ func (a *Call) Equals(v Value) bool {
|
||||||
return a.Arguments.Equals(b.Arguments)
|
return a.Arguments.Equals(b.Arguments)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Call) IsConst() bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Call) Debug(expand bool) string {
|
|
||||||
tmp := strings.Builder{}
|
|
||||||
|
|
||||||
if expand {
|
|
||||||
tmp.WriteString(v.Arguments[0].String())
|
|
||||||
} else {
|
|
||||||
tmp.WriteString("%")
|
|
||||||
tmp.WriteString(strconv.Itoa(v.Arguments[0].ID()))
|
|
||||||
}
|
|
||||||
|
|
||||||
tmp.WriteString("(")
|
|
||||||
args := v.Arguments[1:]
|
|
||||||
|
|
||||||
for i, arg := range args {
|
|
||||||
if expand {
|
|
||||||
tmp.WriteString(arg.String())
|
|
||||||
} else {
|
|
||||||
tmp.WriteString("%")
|
|
||||||
tmp.WriteString(strconv.Itoa(arg.ID()))
|
|
||||||
}
|
|
||||||
|
|
||||||
if i != len(args)-1 {
|
|
||||||
tmp.WriteString(", ")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tmp.WriteString(")")
|
|
||||||
return tmp.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Call) String() string {
|
func (v *Call) String() string {
|
||||||
return v.Debug(true)
|
return fmt.Sprintf("%s(%s)", v.Arguments[0].String(), v.Arguments[1:].String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Call) Type() types.Type {
|
func (v *Call) Type() types.Type {
|
||||||
|
|
|
@ -1,73 +1,3 @@
|
||||||
package ssa
|
package ssa
|
||||||
|
|
||||||
import (
|
type CallExtern struct{ Call }
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"git.urbach.dev/cli/q/src/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
type CallExtern struct {
|
|
||||||
Id
|
|
||||||
Arguments
|
|
||||||
Liveness
|
|
||||||
Source
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *CallExtern) Equals(v Value) bool {
|
|
||||||
b, sameType := v.(*CallExtern)
|
|
||||||
|
|
||||||
if !sameType {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return a.Arguments.Equals(b.Arguments)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *CallExtern) IsConst() bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *CallExtern) Debug(expand bool) string {
|
|
||||||
tmp := strings.Builder{}
|
|
||||||
|
|
||||||
if expand {
|
|
||||||
tmp.WriteString(v.Arguments[0].String())
|
|
||||||
} else {
|
|
||||||
tmp.WriteString("%")
|
|
||||||
tmp.WriteString(strconv.Itoa(v.Arguments[0].ID()))
|
|
||||||
}
|
|
||||||
|
|
||||||
tmp.WriteString("(")
|
|
||||||
args := v.Arguments[1:]
|
|
||||||
|
|
||||||
for i, arg := range args {
|
|
||||||
if expand {
|
|
||||||
tmp.WriteString(arg.String())
|
|
||||||
} else {
|
|
||||||
tmp.WriteString("%")
|
|
||||||
tmp.WriteString(strconv.Itoa(arg.ID()))
|
|
||||||
}
|
|
||||||
|
|
||||||
if i != len(args)-1 {
|
|
||||||
tmp.WriteString(", ")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tmp.WriteString(")")
|
|
||||||
return tmp.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *CallExtern) String() string {
|
|
||||||
return v.Debug(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *CallExtern) Type() types.Type {
|
|
||||||
typ := v.Arguments[0].(*Function).Typ
|
|
||||||
|
|
||||||
if len(typ.Output) == 0 {
|
|
||||||
return types.Void
|
|
||||||
}
|
|
||||||
|
|
||||||
return typ.Output[0]
|
|
||||||
}
|
|
29
src/ssa/Field.go
Normal file
29
src/ssa/Field.go
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
package ssa
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"git.urbach.dev/cli/q/src/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Field struct {
|
||||||
|
Struct Value
|
||||||
|
Field *types.Field
|
||||||
|
Liveness
|
||||||
|
Source
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Field) IsConst() bool { return true }
|
||||||
|
func (v *Field) Type() types.Type { return v.Field.Type }
|
||||||
|
func (v *Field) String() string { return fmt.Sprintf("%s.%s", v.Struct, v.Field) }
|
||||||
|
func (v *Field) Inputs() []Value { return []Value{v.Struct} }
|
||||||
|
|
||||||
|
func (a *Field) Equals(v Value) bool {
|
||||||
|
b, sameType := v.(*Field)
|
||||||
|
|
||||||
|
if !sameType {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.Field == b.Field
|
||||||
|
}
|
|
@ -6,14 +6,14 @@ type Function struct {
|
||||||
UniqueName string
|
UniqueName string
|
||||||
Typ *types.Function
|
Typ *types.Function
|
||||||
IsExtern bool
|
IsExtern bool
|
||||||
Id
|
|
||||||
Liveness
|
Liveness
|
||||||
Source
|
Source
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Function) Dependencies() []Value {
|
func (v *Function) Inputs() []Value { return nil }
|
||||||
return nil
|
func (v *Function) IsConst() bool { return true }
|
||||||
}
|
func (v *Function) String() string { return v.UniqueName }
|
||||||
|
func (v *Function) Type() types.Type { return v.Typ }
|
||||||
|
|
||||||
func (a *Function) Equals(v Value) bool {
|
func (a *Function) Equals(v Value) bool {
|
||||||
b, sameType := v.(*Function)
|
b, sameType := v.(*Function)
|
||||||
|
@ -23,20 +23,4 @@ func (a *Function) Equals(v Value) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
return a.UniqueName == b.UniqueName
|
return a.UniqueName == b.UniqueName
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Function) IsConst() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Function) Debug(expand bool) string {
|
|
||||||
return v.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Function) String() string {
|
|
||||||
return v.UniqueName
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Function) Type() types.Type {
|
|
||||||
return v.Typ
|
|
||||||
}
|
}
|
|
@ -1,6 +0,0 @@
|
||||||
package ssa
|
|
||||||
|
|
||||||
type HasLiveness interface {
|
|
||||||
AddUser(Value)
|
|
||||||
Users() []Value
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
package ssa
|
|
||||||
|
|
||||||
import "git.urbach.dev/cli/q/src/token"
|
|
||||||
|
|
||||||
type HasSource interface {
|
|
||||||
Start() token.Position
|
|
||||||
End() token.Position
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
package ssa
|
|
||||||
|
|
||||||
type Id int
|
|
||||||
|
|
||||||
func (id Id) ID() int {
|
|
||||||
return int(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (id *Id) SetID(newId int) {
|
|
||||||
*id = Id(newId)
|
|
||||||
}
|
|
|
@ -3,7 +3,6 @@ package ssa
|
||||||
// IR is a list of basic blocks.
|
// IR is a list of basic blocks.
|
||||||
type IR struct {
|
type IR struct {
|
||||||
Blocks []*Block
|
Blocks []*Block
|
||||||
nextId int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddBlock adds a new block to the function.
|
// AddBlock adds a new block to the function.
|
||||||
|
@ -28,8 +27,6 @@ func (f *IR) Append(instr Value) Value {
|
||||||
return existing
|
return existing
|
||||||
}
|
}
|
||||||
|
|
||||||
instr.SetID(f.nextId)
|
|
||||||
f.nextId++
|
|
||||||
return f.Blocks[len(f.Blocks)-1].Append(instr)
|
return f.Blocks[len(f.Blocks)-1].Append(instr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,14 +8,14 @@ import (
|
||||||
|
|
||||||
type Int struct {
|
type Int struct {
|
||||||
Int int
|
Int int
|
||||||
Id
|
|
||||||
Liveness
|
Liveness
|
||||||
Source
|
Source
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Int) Dependencies() []Value {
|
func (v *Int) Inputs() []Value { return nil }
|
||||||
return nil
|
func (v *Int) IsConst() bool { return true }
|
||||||
}
|
func (v *Int) String() string { return strconv.Itoa(v.Int) }
|
||||||
|
func (v *Int) Type() types.Type { return types.AnyInt }
|
||||||
|
|
||||||
func (a *Int) Equals(v Value) bool {
|
func (a *Int) Equals(v Value) bool {
|
||||||
b, sameType := v.(*Int)
|
b, sameType := v.(*Int)
|
||||||
|
@ -25,20 +25,4 @@ func (a *Int) Equals(v Value) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
return a.Int == b.Int
|
return a.Int == b.Int
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Int) IsConst() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Int) Debug(expand bool) string {
|
|
||||||
return v.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Int) String() string {
|
|
||||||
return strconv.Itoa(v.Int)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Int) Type() types.Type {
|
|
||||||
return types.AnyInt
|
|
||||||
}
|
}
|
|
@ -1,13 +0,0 @@
|
||||||
package ssa
|
|
||||||
|
|
||||||
type Liveness struct {
|
|
||||||
users []Value
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Liveness) AddUser(user Value) {
|
|
||||||
v.users = append(v.users, user)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Liveness) Users() []Value {
|
|
||||||
return v.users
|
|
||||||
}
|
|
|
@ -10,14 +10,14 @@ type Parameter struct {
|
||||||
Index uint8
|
Index uint8
|
||||||
Name string
|
Name string
|
||||||
Typ types.Type
|
Typ types.Type
|
||||||
Id
|
|
||||||
Liveness
|
Liveness
|
||||||
Source
|
Source
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Parameter) Dependencies() []Value {
|
func (v *Parameter) Inputs() []Value { return nil }
|
||||||
return nil
|
func (v *Parameter) IsConst() bool { return true }
|
||||||
}
|
func (v *Parameter) String() string { return fmt.Sprintf("args[%d]", v.Index) }
|
||||||
|
func (v *Parameter) Type() types.Type { return v.Typ }
|
||||||
|
|
||||||
func (a *Parameter) Equals(v Value) bool {
|
func (a *Parameter) Equals(v Value) bool {
|
||||||
b, sameType := v.(*Parameter)
|
b, sameType := v.(*Parameter)
|
||||||
|
@ -27,20 +27,4 @@ func (a *Parameter) Equals(v Value) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
return a.Index == b.Index
|
return a.Index == b.Index
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Parameter) IsConst() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Parameter) Debug(expand bool) string {
|
|
||||||
return v.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Parameter) String() string {
|
|
||||||
return fmt.Sprintf("args[%d]", v.Index)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Parameter) Type() types.Type {
|
|
||||||
return v.Typ
|
|
||||||
}
|
}
|
|
@ -1,18 +1,21 @@
|
||||||
package ssa
|
package ssa
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strconv"
|
"fmt"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"git.urbach.dev/cli/q/src/types"
|
"git.urbach.dev/cli/q/src/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Return struct {
|
type Return struct {
|
||||||
Id
|
|
||||||
Arguments
|
Arguments
|
||||||
Source
|
Source
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v *Return) AddUser(Value) { panic("return can not be used as a dependency") }
|
||||||
|
func (v *Return) IsConst() bool { return false }
|
||||||
|
func (v *Return) Type() types.Type { return types.Void }
|
||||||
|
func (v *Return) Users() []Value { return nil }
|
||||||
|
|
||||||
func (a *Return) Equals(v Value) bool {
|
func (a *Return) Equals(v Value) bool {
|
||||||
b, sameType := v.(*Return)
|
b, sameType := v.(*Return)
|
||||||
|
|
||||||
|
@ -33,38 +36,10 @@ func (a *Return) Equals(v Value) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Return) IsConst() bool {
|
func (v *Return) String() string {
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Return) Debug(expand bool) string {
|
|
||||||
if len(v.Arguments) == 0 {
|
if len(v.Arguments) == 0 {
|
||||||
return "return"
|
return "return"
|
||||||
}
|
}
|
||||||
|
|
||||||
tmp := strings.Builder{}
|
return fmt.Sprintf("return %s", v.Arguments.String())
|
||||||
tmp.WriteString("return ")
|
|
||||||
|
|
||||||
for i, arg := range v.Arguments {
|
|
||||||
if expand {
|
|
||||||
tmp.WriteString(arg.String())
|
|
||||||
} else {
|
|
||||||
tmp.WriteString("%")
|
|
||||||
tmp.WriteString(strconv.Itoa(arg.ID()))
|
|
||||||
}
|
|
||||||
|
|
||||||
if i != len(v.Arguments)-1 {
|
|
||||||
tmp.WriteString(", ")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return tmp.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Return) String() string {
|
|
||||||
return v.Debug(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Return) Type() types.Type {
|
|
||||||
return types.Void
|
|
||||||
}
|
}
|
|
@ -1,13 +0,0 @@
|
||||||
package ssa
|
|
||||||
|
|
||||||
import "git.urbach.dev/cli/q/src/token"
|
|
||||||
|
|
||||||
type Source token.List
|
|
||||||
|
|
||||||
func (v Source) Start() token.Position {
|
|
||||||
return v[0].Position
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v Source) End() token.Position {
|
|
||||||
return v[len(v)-1].End()
|
|
||||||
}
|
|
|
@ -1,20 +1,22 @@
|
||||||
package ssa
|
package ssa
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strconv"
|
"fmt"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"git.urbach.dev/cli/q/src/types"
|
"git.urbach.dev/cli/q/src/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Struct struct {
|
type Struct struct {
|
||||||
Typ *types.Struct
|
Typ *types.Struct
|
||||||
Id
|
|
||||||
Arguments
|
Arguments
|
||||||
Liveness
|
Liveness
|
||||||
Source
|
Source
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v *Struct) IsConst() bool { return true }
|
||||||
|
func (v *Struct) String() string { return fmt.Sprintf("%s{%s}", v.Typ.Name(), v.Arguments.String()) }
|
||||||
|
func (v *Struct) Type() types.Type { return v.Typ }
|
||||||
|
|
||||||
func (a *Struct) Equals(v Value) bool {
|
func (a *Struct) Equals(v Value) bool {
|
||||||
b, sameType := v.(*Struct)
|
b, sameType := v.(*Struct)
|
||||||
|
|
||||||
|
@ -23,38 +25,4 @@ func (a *Struct) Equals(v Value) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
return a.Arguments.Equals(b.Arguments)
|
return a.Arguments.Equals(b.Arguments)
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Struct) IsConst() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Struct) Debug(expand bool) string {
|
|
||||||
tmp := strings.Builder{}
|
|
||||||
tmp.WriteString(v.Typ.Name())
|
|
||||||
tmp.WriteString("{")
|
|
||||||
|
|
||||||
for i, arg := range v.Arguments {
|
|
||||||
if expand {
|
|
||||||
tmp.WriteString(arg.String())
|
|
||||||
} else {
|
|
||||||
tmp.WriteString("%")
|
|
||||||
tmp.WriteString(strconv.Itoa(arg.ID()))
|
|
||||||
}
|
|
||||||
|
|
||||||
if i != len(v.Arguments)-1 {
|
|
||||||
tmp.WriteString(", ")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tmp.WriteString("}")
|
|
||||||
return tmp.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Struct) String() string {
|
|
||||||
return v.Debug(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Struct) Type() types.Type {
|
|
||||||
return v.Typ
|
|
||||||
}
|
}
|
|
@ -1,49 +0,0 @@
|
||||||
package ssa
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"git.urbach.dev/cli/q/src/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
type StructField struct {
|
|
||||||
Struct Value
|
|
||||||
Field *types.Field
|
|
||||||
Id
|
|
||||||
Liveness
|
|
||||||
Source
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *StructField) Dependencies() []Value {
|
|
||||||
return []Value{v.Struct}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *StructField) Equals(v Value) bool {
|
|
||||||
b, sameType := v.(*StructField)
|
|
||||||
|
|
||||||
if !sameType {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return a.Field == b.Field
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *StructField) IsConst() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *StructField) Debug(expand bool) string {
|
|
||||||
if expand {
|
|
||||||
return fmt.Sprintf("%s.%s", v.Struct, v.Field)
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Sprintf("%%%d.%s", v.Struct.ID(), v.Field)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *StructField) String() string {
|
|
||||||
return v.Debug(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *StructField) Type() types.Type {
|
|
||||||
return v.Field.Type
|
|
||||||
}
|
|
18
src/ssa/Struct_test.go
Normal file
18
src/ssa/Struct_test.go
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
package ssa_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"git.urbach.dev/cli/q/src/ssa"
|
||||||
|
"git.urbach.dev/cli/q/src/types"
|
||||||
|
"git.urbach.dev/go/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestStruct(t *testing.T) {
|
||||||
|
fn := ssa.IR{}
|
||||||
|
hello := []byte("Hello")
|
||||||
|
pointer := fn.Append(&ssa.Bytes{Bytes: hello})
|
||||||
|
length := fn.Append(&ssa.Int{Int: len(hello)})
|
||||||
|
str := fn.Append(&ssa.Struct{Typ: types.String, Arguments: ssa.Arguments{pointer, length}})
|
||||||
|
assert.Equal(t, str.String(), "string{\"Hello\", 5}")
|
||||||
|
}
|
|
@ -1,19 +1,21 @@
|
||||||
package ssa
|
package ssa
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strconv"
|
"fmt"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"git.urbach.dev/cli/q/src/types"
|
"git.urbach.dev/cli/q/src/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Syscall struct {
|
type Syscall struct {
|
||||||
Id
|
|
||||||
Arguments
|
Arguments
|
||||||
Liveness
|
Liveness
|
||||||
Source
|
Source
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v *Syscall) IsConst() bool { return false }
|
||||||
|
func (v *Syscall) String() string { return fmt.Sprintf("syscall(%s)", v.Arguments.String()) }
|
||||||
|
func (v *Syscall) Type() types.Type { return types.Any }
|
||||||
|
|
||||||
func (a *Syscall) Equals(v Value) bool {
|
func (a *Syscall) Equals(v Value) bool {
|
||||||
b, sameType := v.(*Syscall)
|
b, sameType := v.(*Syscall)
|
||||||
|
|
||||||
|
@ -22,37 +24,4 @@ func (a *Syscall) Equals(v Value) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
return a.Arguments.Equals(b.Arguments)
|
return a.Arguments.Equals(b.Arguments)
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Syscall) IsConst() bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Syscall) Debug(expand bool) string {
|
|
||||||
tmp := strings.Builder{}
|
|
||||||
tmp.WriteString("syscall(")
|
|
||||||
|
|
||||||
for i, arg := range v.Arguments {
|
|
||||||
if expand {
|
|
||||||
tmp.WriteString(arg.String())
|
|
||||||
} else {
|
|
||||||
tmp.WriteString("%")
|
|
||||||
tmp.WriteString(strconv.Itoa(arg.ID()))
|
|
||||||
}
|
|
||||||
|
|
||||||
if i != len(v.Arguments)-1 {
|
|
||||||
tmp.WriteString(", ")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tmp.WriteString(")")
|
|
||||||
return tmp.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Syscall) String() string {
|
|
||||||
return v.Debug(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Syscall) Type() types.Type {
|
|
||||||
return types.Any
|
|
||||||
}
|
}
|
|
@ -1,16 +1,23 @@
|
||||||
package ssa
|
package ssa
|
||||||
|
|
||||||
import (
|
import "git.urbach.dev/cli/q/src/types"
|
||||||
"git.urbach.dev/cli/q/src/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Value interface {
|
type Value interface {
|
||||||
Debug(bool) string
|
// Type returns the data type.
|
||||||
Dependencies() []Value
|
|
||||||
Equals(Value) bool
|
|
||||||
ID() int
|
|
||||||
IsConst() bool
|
|
||||||
SetID(int)
|
|
||||||
String() string
|
|
||||||
Type() types.Type
|
Type() types.Type
|
||||||
|
|
||||||
|
// Users returns all values that reference this value as an input.
|
||||||
|
Users() []Value
|
||||||
|
|
||||||
|
// Inputs returns all values that are needed for this value to be calculated.
|
||||||
|
Inputs() []Value
|
||||||
|
|
||||||
|
// Equals returns true if it's equal to the given value.
|
||||||
|
Equals(Value) bool
|
||||||
|
|
||||||
|
// IsConst returns true if the calculation of the value has no side effects.
|
||||||
|
IsConst() bool
|
||||||
|
|
||||||
|
// Strings returns a human-readable form of the value.
|
||||||
|
String() string
|
||||||
}
|
}
|
|
@ -1,190 +0,0 @@
|
||||||
package ssa_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"runtime/debug"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"git.urbach.dev/cli/q/src/ssa"
|
|
||||||
"git.urbach.dev/go/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
// This benchmark compares the performance of fat structs and interfaces.
|
|
||||||
// It allocates `actual` objects where `actual` must be divisible by 2.
|
|
||||||
const (
|
|
||||||
actual = 64
|
|
||||||
estimate = 8
|
|
||||||
)
|
|
||||||
|
|
||||||
type FatStruct struct {
|
|
||||||
Type byte
|
|
||||||
A int
|
|
||||||
B int
|
|
||||||
C int
|
|
||||||
D int
|
|
||||||
E int
|
|
||||||
F int
|
|
||||||
G int
|
|
||||||
}
|
|
||||||
|
|
||||||
type Instruction interface{}
|
|
||||||
|
|
||||||
type BinaryInstruction struct {
|
|
||||||
A int
|
|
||||||
B int
|
|
||||||
}
|
|
||||||
|
|
||||||
type OtherInstruction struct {
|
|
||||||
C int
|
|
||||||
D int
|
|
||||||
E int
|
|
||||||
F int
|
|
||||||
G int
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
|
||||||
debug.SetGCPercent(-1)
|
|
||||||
os.Exit(m.Run())
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkFatStructRaw(b *testing.B) {
|
|
||||||
for b.Loop() {
|
|
||||||
entries := make([]FatStruct, 0, estimate)
|
|
||||||
|
|
||||||
for i := range actual {
|
|
||||||
entries = append(entries, FatStruct{
|
|
||||||
Type: byte(i % 2),
|
|
||||||
A: i,
|
|
||||||
B: i,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
count := 0
|
|
||||||
|
|
||||||
for _, entry := range entries {
|
|
||||||
switch entry.Type {
|
|
||||||
case 0:
|
|
||||||
count++
|
|
||||||
case 1:
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
assert.Equal(b, count, actual/2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkFatStructPtr(b *testing.B) {
|
|
||||||
for b.Loop() {
|
|
||||||
entries := make([]*FatStruct, 0, estimate)
|
|
||||||
|
|
||||||
for i := range actual {
|
|
||||||
entries = append(entries, &FatStruct{
|
|
||||||
Type: byte(i % 2),
|
|
||||||
A: i,
|
|
||||||
B: i,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
count := 0
|
|
||||||
|
|
||||||
for _, entry := range entries {
|
|
||||||
switch entry.Type {
|
|
||||||
case 0:
|
|
||||||
count++
|
|
||||||
case 1:
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
assert.Equal(b, count, actual/2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkInterfaceRaw(b *testing.B) {
|
|
||||||
for b.Loop() {
|
|
||||||
entries := make([]Instruction, 0, estimate)
|
|
||||||
|
|
||||||
for i := range actual {
|
|
||||||
if i%2 == 0 {
|
|
||||||
entries = append(entries, BinaryInstruction{
|
|
||||||
A: i,
|
|
||||||
B: i,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
entries = append(entries, OtherInstruction{
|
|
||||||
C: i,
|
|
||||||
D: i,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
count := 0
|
|
||||||
|
|
||||||
for _, entry := range entries {
|
|
||||||
switch entry.(type) {
|
|
||||||
case BinaryInstruction:
|
|
||||||
count++
|
|
||||||
case OtherInstruction:
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
assert.Equal(b, count, actual/2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkInterfacePtr(b *testing.B) {
|
|
||||||
for b.Loop() {
|
|
||||||
entries := make([]Instruction, 0, estimate)
|
|
||||||
|
|
||||||
for i := range actual {
|
|
||||||
if i%2 == 0 {
|
|
||||||
entries = append(entries, &BinaryInstruction{
|
|
||||||
A: i,
|
|
||||||
B: i,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
entries = append(entries, &OtherInstruction{
|
|
||||||
C: i,
|
|
||||||
D: i,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
count := 0
|
|
||||||
|
|
||||||
for _, entry := range entries {
|
|
||||||
switch entry.(type) {
|
|
||||||
case *BinaryInstruction:
|
|
||||||
count++
|
|
||||||
case *OtherInstruction:
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
assert.Equal(b, count, actual/2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkSSA(b *testing.B) {
|
|
||||||
for b.Loop() {
|
|
||||||
f := ssa.IR{}
|
|
||||||
|
|
||||||
for i := range actual {
|
|
||||||
if i%2 == 0 {
|
|
||||||
f.Append(&ssa.Return{})
|
|
||||||
} else {
|
|
||||||
f.Append(&ssa.Call{})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
count := 0
|
|
||||||
|
|
||||||
for instr := range f.Values {
|
|
||||||
switch instr.(type) {
|
|
||||||
case *ssa.Return:
|
|
||||||
count++
|
|
||||||
case *ssa.Call:
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
assert.Equal(b, count, actual/2)
|
|
||||||
}
|
|
||||||
}
|
|
65
src/ssa/common.go
Normal file
65
src/ssa/common.go
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
package ssa
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"git.urbach.dev/cli/q/src/token"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Arguments defines a list of values that this value depends on.
|
||||||
|
type Arguments []Value
|
||||||
|
|
||||||
|
func (v Arguments) Inputs() []Value { return v }
|
||||||
|
|
||||||
|
// String returns a comma-separated list of all arguments.
|
||||||
|
func (v Arguments) String() string {
|
||||||
|
tmp := strings.Builder{}
|
||||||
|
|
||||||
|
for i, arg := range v {
|
||||||
|
tmp.WriteString(arg.String())
|
||||||
|
|
||||||
|
if i != len(v)-1 {
|
||||||
|
tmp.WriteString(", ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tmp.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a Arguments) Equals(b Arguments) bool {
|
||||||
|
if len(a) != len(b) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range a {
|
||||||
|
if !a[i].Equals(b[i]) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Liveness tracks where the value is used.
|
||||||
|
type Liveness struct {
|
||||||
|
users []Value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Liveness) AddUser(user Value) { v.users = append(v.users, user) }
|
||||||
|
func (v *Liveness) Users() []Value { return v.users }
|
||||||
|
|
||||||
|
type HasLiveness interface {
|
||||||
|
AddUser(Value)
|
||||||
|
Users() []Value
|
||||||
|
}
|
||||||
|
|
||||||
|
// Source tracks the source tokens.
|
||||||
|
type Source token.List
|
||||||
|
|
||||||
|
func (v Source) Start() token.Position { return v[0].Position }
|
||||||
|
func (v Source) End() token.Position { return v[len(v)-1].End() }
|
||||||
|
|
||||||
|
type HasSource interface {
|
||||||
|
Start() token.Position
|
||||||
|
End() token.Position
|
||||||
|
}
|
|
@ -16,9 +16,7 @@ func (f *Compiler) GenerateAssembly(ir ssa.IR, isLeaf bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for instr := range ir.Values {
|
for instr := range ir.Values {
|
||||||
live, isLive := instr.(ssa.HasLiveness)
|
if len(instr.Users()) > 0 {
|
||||||
|
|
||||||
if isLive && len(live.Users()) > 0 {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -91,7 +91,7 @@ func (f *Compiler) ValueToRegister(instr ssa.Value, destination cpu.Register) {
|
||||||
Source: source,
|
Source: source,
|
||||||
})
|
})
|
||||||
|
|
||||||
case *ssa.StructField:
|
case *ssa.Field:
|
||||||
parameter := instr.Struct.(*ssa.Parameter)
|
parameter := instr.Struct.(*ssa.Parameter)
|
||||||
field := instr.Field
|
field := instr.Field
|
||||||
source := f.CPU.Call[parameter.Index+field.Index]
|
source := f.CPU.Call[parameter.Index+field.Index]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue