diff --git a/src/compiler/showSSA.go b/src/compiler/showSSA.go index b73246e..bf78313 100644 --- a/src/compiler/showSSA.go +++ b/src/compiler/showSSA.go @@ -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() } diff --git a/src/core/Evaluate.go b/src/core/Evaluate.go index 378f28e..1af8a0f 100644 --- a/src/core/Evaluate.go +++ b/src/core/Evaluate.go @@ -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), diff --git a/src/ssa/Arguments.go b/src/ssa/Arguments.go deleted file mode 100644 index 0cff931..0000000 --- a/src/ssa/Arguments.go +++ /dev/null @@ -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 -} \ No newline at end of file diff --git a/src/ssa/BinaryOp.go b/src/ssa/BinaryOp.go index 039b2e7..3905a90 100644 --- a/src/ssa/BinaryOp.go +++ b/src/ssa/BinaryOp.go @@ -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 { - 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() + return fmt.Sprintf("%s %s %s", v.Left, expression.Operators[v.Op].Symbol, v.Right) } \ No newline at end of file diff --git a/src/ssa/Block.go b/src/ssa/Block.go index 975e809..75d9282 100644 --- a/src/ssa/Block.go +++ b/src/ssa/Block.go @@ -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) } diff --git a/src/ssa/Bytes.go b/src/ssa/Bytes.go index 0215c94..78ad0a7 100644 --- a/src/ssa/Bytes.go +++ b/src/ssa/Bytes.go @@ -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) @@ -26,20 +26,4 @@ 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 } \ No newline at end of file diff --git a/src/ssa/Call.go b/src/ssa/Call.go index a1629f0..cebfa9f 100644 --- a/src/ssa/Call.go +++ b/src/ssa/Call.go @@ -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 { diff --git a/src/ssa/CallExtern.go b/src/ssa/CallExtern.go index a6b4b68..1e797ab 100644 --- a/src/ssa/CallExtern.go +++ b/src/ssa/CallExtern.go @@ -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] -} \ No newline at end of file +type CallExtern struct{ Call } \ No newline at end of file diff --git a/src/ssa/Field.go b/src/ssa/Field.go new file mode 100644 index 0000000..6cc0cde --- /dev/null +++ b/src/ssa/Field.go @@ -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 +} \ No newline at end of file diff --git a/src/ssa/Function.go b/src/ssa/Function.go index 513f08b..29cc8b1 100644 --- a/src/ssa/Function.go +++ b/src/ssa/Function.go @@ -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) @@ -23,20 +23,4 @@ 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 } \ No newline at end of file diff --git a/src/ssa/HasLiveness.go b/src/ssa/HasLiveness.go deleted file mode 100644 index 52528bf..0000000 --- a/src/ssa/HasLiveness.go +++ /dev/null @@ -1,6 +0,0 @@ -package ssa - -type HasLiveness interface { - AddUser(Value) - Users() []Value -} \ No newline at end of file diff --git a/src/ssa/HasSource.go b/src/ssa/HasSource.go deleted file mode 100644 index 5b614d4..0000000 --- a/src/ssa/HasSource.go +++ /dev/null @@ -1,8 +0,0 @@ -package ssa - -import "git.urbach.dev/cli/q/src/token" - -type HasSource interface { - Start() token.Position - End() token.Position -} \ No newline at end of file diff --git a/src/ssa/ID.go b/src/ssa/ID.go deleted file mode 100644 index 7751f3f..0000000 --- a/src/ssa/ID.go +++ /dev/null @@ -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) -} \ No newline at end of file diff --git a/src/ssa/IR.go b/src/ssa/IR.go index fea735d..84cc362 100644 --- a/src/ssa/IR.go +++ b/src/ssa/IR.go @@ -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) } diff --git a/src/ssa/Int.go b/src/ssa/Int.go index 0488f51..658cbed 100644 --- a/src/ssa/Int.go +++ b/src/ssa/Int.go @@ -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) @@ -25,20 +25,4 @@ 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 } \ No newline at end of file diff --git a/src/ssa/Liveness.go b/src/ssa/Liveness.go deleted file mode 100644 index 9ce8774..0000000 --- a/src/ssa/Liveness.go +++ /dev/null @@ -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 -} \ No newline at end of file diff --git a/src/ssa/Parameter.go b/src/ssa/Parameter.go index 63f408d..6e79676 100644 --- a/src/ssa/Parameter.go +++ b/src/ssa/Parameter.go @@ -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) @@ -27,20 +27,4 @@ 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 } \ No newline at end of file diff --git a/src/ssa/Return.go b/src/ssa/Return.go index 51f3484..da66e16 100644 --- a/src/ssa/Return.go +++ b/src/ssa/Return.go @@ -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()) } \ No newline at end of file diff --git a/src/ssa/Source.go b/src/ssa/Source.go deleted file mode 100644 index 28330f2..0000000 --- a/src/ssa/Source.go +++ /dev/null @@ -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() -} \ No newline at end of file diff --git a/src/ssa/Struct.go b/src/ssa/Struct.go index d749d43..36bfbba 100644 --- a/src/ssa/Struct.go +++ b/src/ssa/Struct.go @@ -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) @@ -23,38 +25,4 @@ 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 } \ No newline at end of file diff --git a/src/ssa/StructField.go b/src/ssa/StructField.go deleted file mode 100644 index 279d830..0000000 --- a/src/ssa/StructField.go +++ /dev/null @@ -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 -} \ No newline at end of file diff --git a/src/ssa/Struct_test.go b/src/ssa/Struct_test.go new file mode 100644 index 0000000..c6019b1 --- /dev/null +++ b/src/ssa/Struct_test.go @@ -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}") +} \ No newline at end of file diff --git a/src/ssa/Syscall.go b/src/ssa/Syscall.go index cdd87b0..482016c 100644 --- a/src/ssa/Syscall.go +++ b/src/ssa/Syscall.go @@ -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) @@ -22,37 +24,4 @@ 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 } \ No newline at end of file diff --git a/src/ssa/Value.go b/src/ssa/Value.go index 74c2e86..c36560f 100644 --- a/src/ssa/Value.go +++ b/src/ssa/Value.go @@ -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 } \ No newline at end of file diff --git a/src/ssa/bench_test.go b/src/ssa/bench_test.go deleted file mode 100644 index 6c64485..0000000 --- a/src/ssa/bench_test.go +++ /dev/null @@ -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) - } -} \ No newline at end of file diff --git a/src/ssa/common.go b/src/ssa/common.go new file mode 100644 index 0000000..ae0403f --- /dev/null +++ b/src/ssa/common.go @@ -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 +} \ No newline at end of file diff --git a/src/ssa2asm/GenerateAssembly.go b/src/ssa2asm/GenerateAssembly.go index a0e3d9f..0337fa5 100644 --- a/src/ssa2asm/GenerateAssembly.go +++ b/src/ssa2asm/GenerateAssembly.go @@ -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 } diff --git a/src/ssa2asm/ValueToRegister.go b/src/ssa2asm/ValueToRegister.go index 81e2d05..850074d 100644 --- a/src/ssa2asm/ValueToRegister.go +++ b/src/ssa2asm/ValueToRegister.go @@ -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]