Simplified ssa package
All checks were successful
/ test (push) Successful in 15s

This commit is contained in:
Eduard Urbach 2025-07-03 22:54:30 +02:00
parent b77d876ebb
commit ca9595d1fb
Signed by: akyoto
GPG key ID: 49226B848C78F6C8
28 changed files with 179 additions and 649 deletions

View file

@ -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()
} }

View file

@ -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),

View file

@ -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
}

View file

@ -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()
} }

View file

@ -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)
} }

View file

@ -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
} }

View file

@ -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 {

View file

@ -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
View 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
}

View file

@ -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
} }

View file

@ -1,6 +0,0 @@
package ssa
type HasLiveness interface {
AddUser(Value)
Users() []Value
}

View file

@ -1,8 +0,0 @@
package ssa
import "git.urbach.dev/cli/q/src/token"
type HasSource interface {
Start() token.Position
End() token.Position
}

View file

@ -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)
}

View file

@ -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)
} }

View file

@ -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
} }

View file

@ -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
}

View file

@ -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
} }

View file

@ -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
} }

View file

@ -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()
}

View file

@ -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
} }

View file

@ -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
View 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}")
}

View file

@ -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
} }

View file

@ -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
} }

View file

@ -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
View 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
}

View file

@ -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
} }

View file

@ -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]