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 i, instr := range block.Instructions {
|
||||
ansi.Dim.Printf("%%%-1d = ", i)
|
||||
fmt.Printf("%-30s ", instr.Debug(false))
|
||||
fmt.Printf("%-30s ", instr.String())
|
||||
ansi.Dim.Printf(" %-30s", instr.Type().Name())
|
||||
fmt.Println()
|
||||
}
|
||||
|
|
|
@ -149,10 +149,10 @@ func (f *Function) Evaluate(expr *expression.Expression) (ssa.Value, error) {
|
|||
}
|
||||
|
||||
if fn.IsExtern() {
|
||||
v := f.Append(&ssa.CallExtern{
|
||||
v := f.Append(&ssa.CallExtern{Call: ssa.Call{
|
||||
Arguments: args,
|
||||
Source: ssa.Source(expr.Source),
|
||||
})
|
||||
}})
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
v := f.Append(&ssa.StructField{
|
||||
v := f.Append(&ssa.Field{
|
||||
Struct: identifier,
|
||||
Field: field,
|
||||
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
|
||||
Right Value
|
||||
Op token.Kind
|
||||
Id
|
||||
Liveness
|
||||
Source
|
||||
}
|
||||
|
||||
func (v *BinaryOp) Dependencies() []Value {
|
||||
return []Value{v.Left, v.Right}
|
||||
}
|
||||
func (v *BinaryOp) Inputs() []Value { 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 {
|
||||
b, sameType := v.(*BinaryOp)
|
||||
|
@ -39,22 +38,6 @@ func (a *BinaryOp) Equals(v Value) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func (v *BinaryOp) IsConst() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (v *BinaryOp) Debug(expand bool) string {
|
||||
if expand {
|
||||
func (v *BinaryOp) String() string {
|
||||
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 {
|
||||
return v.Debug(true)
|
||||
}
|
||||
|
||||
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.
|
||||
func (block *Block) Append(instr Value) Value {
|
||||
for _, dep := range instr.Dependencies() {
|
||||
for _, dep := range instr.Inputs() {
|
||||
dep.(HasLiveness).AddUser(instr)
|
||||
}
|
||||
|
||||
|
|
|
@ -8,15 +8,15 @@ import (
|
|||
)
|
||||
|
||||
type Bytes struct {
|
||||
Id
|
||||
Bytes []byte
|
||||
Liveness
|
||||
Source
|
||||
}
|
||||
|
||||
func (v *Bytes) Dependencies() []Value {
|
||||
return nil
|
||||
}
|
||||
func (v *Bytes) Inputs() []Value { 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 {
|
||||
b, sameType := v.(*Bytes)
|
||||
|
@ -27,19 +27,3 @@ func (a *Bytes) Equals(v Value) bool {
|
|||
|
||||
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
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"fmt"
|
||||
|
||||
"git.urbach.dev/cli/q/src/types"
|
||||
)
|
||||
|
||||
type Call struct {
|
||||
Id
|
||||
Arguments
|
||||
Liveness
|
||||
Source
|
||||
}
|
||||
|
||||
func (v *Call) IsConst() bool { return false }
|
||||
|
||||
func (a *Call) Equals(v Value) bool {
|
||||
b, sameType := v.(*Call)
|
||||
|
||||
|
@ -24,42 +24,8 @@ func (a *Call) Equals(v Value) bool {
|
|||
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 {
|
||||
return v.Debug(true)
|
||||
return fmt.Sprintf("%s(%s)", v.Arguments[0].String(), v.Arguments[1:].String())
|
||||
}
|
||||
|
||||
func (v *Call) Type() types.Type {
|
||||
|
|
|
@ -1,73 +1,3 @@
|
|||
package ssa
|
||||
|
||||
import (
|
||||
"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]
|
||||
}
|
||||
type CallExtern struct{ Call }
|
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
|
||||
Typ *types.Function
|
||||
IsExtern bool
|
||||
Id
|
||||
Liveness
|
||||
Source
|
||||
}
|
||||
|
||||
func (v *Function) Dependencies() []Value {
|
||||
return nil
|
||||
}
|
||||
func (v *Function) Inputs() []Value { 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 {
|
||||
b, sameType := v.(*Function)
|
||||
|
@ -24,19 +24,3 @@ func (a *Function) Equals(v Value) bool {
|
|||
|
||||
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.
|
||||
type IR struct {
|
||||
Blocks []*Block
|
||||
nextId int
|
||||
}
|
||||
|
||||
// AddBlock adds a new block to the function.
|
||||
|
@ -28,8 +27,6 @@ func (f *IR) Append(instr Value) Value {
|
|||
return existing
|
||||
}
|
||||
|
||||
instr.SetID(f.nextId)
|
||||
f.nextId++
|
||||
return f.Blocks[len(f.Blocks)-1].Append(instr)
|
||||
}
|
||||
|
||||
|
|
|
@ -8,14 +8,14 @@ import (
|
|||
|
||||
type Int struct {
|
||||
Int int
|
||||
Id
|
||||
Liveness
|
||||
Source
|
||||
}
|
||||
|
||||
func (v *Int) Dependencies() []Value {
|
||||
return nil
|
||||
}
|
||||
func (v *Int) Inputs() []Value { 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 {
|
||||
b, sameType := v.(*Int)
|
||||
|
@ -26,19 +26,3 @@ func (a *Int) Equals(v Value) bool {
|
|||
|
||||
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
|
||||
Name string
|
||||
Typ types.Type
|
||||
Id
|
||||
Liveness
|
||||
Source
|
||||
}
|
||||
|
||||
func (v *Parameter) Dependencies() []Value {
|
||||
return nil
|
||||
}
|
||||
func (v *Parameter) Inputs() []Value { 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 {
|
||||
b, sameType := v.(*Parameter)
|
||||
|
@ -28,19 +28,3 @@ func (a *Parameter) Equals(v Value) bool {
|
|||
|
||||
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
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"fmt"
|
||||
|
||||
"git.urbach.dev/cli/q/src/types"
|
||||
)
|
||||
|
||||
type Return struct {
|
||||
Id
|
||||
Arguments
|
||||
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 {
|
||||
b, sameType := v.(*Return)
|
||||
|
||||
|
@ -33,38 +36,10 @@ func (a *Return) Equals(v Value) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func (v *Return) IsConst() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (v *Return) Debug(expand bool) string {
|
||||
func (v *Return) String() string {
|
||||
if len(v.Arguments) == 0 {
|
||||
return "return"
|
||||
}
|
||||
|
||||
tmp := strings.Builder{}
|
||||
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
|
||||
return fmt.Sprintf("return %s", v.Arguments.String())
|
||||
}
|
|
@ -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
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"fmt"
|
||||
|
||||
"git.urbach.dev/cli/q/src/types"
|
||||
)
|
||||
|
||||
type Struct struct {
|
||||
Typ *types.Struct
|
||||
Id
|
||||
Arguments
|
||||
Liveness
|
||||
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 {
|
||||
b, sameType := v.(*Struct)
|
||||
|
||||
|
@ -24,37 +26,3 @@ func (a *Struct) Equals(v Value) bool {
|
|||
|
||||
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
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"fmt"
|
||||
|
||||
"git.urbach.dev/cli/q/src/types"
|
||||
)
|
||||
|
||||
type Syscall struct {
|
||||
Id
|
||||
Arguments
|
||||
Liveness
|
||||
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 {
|
||||
b, sameType := v.(*Syscall)
|
||||
|
||||
|
@ -23,36 +25,3 @@ func (a *Syscall) Equals(v Value) bool {
|
|||
|
||||
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
|
||||
|
||||
import (
|
||||
"git.urbach.dev/cli/q/src/types"
|
||||
)
|
||||
import "git.urbach.dev/cli/q/src/types"
|
||||
|
||||
type Value interface {
|
||||
Debug(bool) string
|
||||
Dependencies() []Value
|
||||
Equals(Value) bool
|
||||
ID() int
|
||||
IsConst() bool
|
||||
SetID(int)
|
||||
String() string
|
||||
// Type returns the data 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 {
|
||||
live, isLive := instr.(ssa.HasLiveness)
|
||||
|
||||
if isLive && len(live.Users()) > 0 {
|
||||
if len(instr.Users()) > 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
|
@ -91,7 +91,7 @@ func (f *Compiler) ValueToRegister(instr ssa.Value, destination cpu.Register) {
|
|||
Source: source,
|
||||
})
|
||||
|
||||
case *ssa.StructField:
|
||||
case *ssa.Field:
|
||||
parameter := instr.Struct.(*ssa.Parameter)
|
||||
field := instr.Field
|
||||
source := f.CPU.Call[parameter.Index+field.Index]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue