Implemented a basic API for SSA
All checks were successful
/ test (push) Successful in 16s

This commit is contained in:
Eduard Urbach 2025-06-20 23:42:58 +02:00
parent 89f375f4fc
commit 14bccadd0f
Signed by: akyoto
GPG key ID: 49226B848C78F6C8
7 changed files with 54 additions and 16 deletions

View file

@ -1,11 +1,12 @@
package ssa package ssa
// Block is a list of instructions that can be targeted in branches.
type Block struct { type Block struct {
Entry []*Block
Instructions []Instruction Instructions []Instruction
Exit []*Block
} }
func (b *Block) Append(instr Instruction) { // Append adds a new instruction to the block.
func (b *Block) Append(instr Instruction) *Instruction {
b.Instructions = append(b.Instructions, instr) b.Instructions = append(b.Instructions, instr)
return &b.Instructions[len(b.Instructions)-1]
} }

View file

@ -1,5 +1,13 @@
package ssa package ssa
// Function is a list of basic blocks.
type Function struct { type Function struct {
Blocks []*Block Blocks []*Block
}
// AddBlock adds a new block to the function.
func (f *Function) AddBlock() *Block {
block := &Block{}
f.Blocks = append(f.Blocks, block)
return block
} }

View file

@ -1,3 +0,0 @@
package ssa
type Index = uint16

View file

@ -1,11 +1,28 @@
package ssa package ssa
// Instruction is a "fat struct" for performance reasons. import (
"fmt"
)
// Instruction is a single instruction in a basic block.
// It is implemented as a "fat struct" for performance reasons.
// It contains all the fields necessary to represent all instruction types. // It contains all the fields necessary to represent all instruction types.
type Instruction struct { type Instruction struct {
Type Type Type Type
Parameters []Index Args []*Instruction
Int int64 Int int64
Float float64 Float float64
String string Text string
}
// String returns a human-readable representation of the instruction.
func (i *Instruction) String() string {
switch i.Type {
case Int:
return fmt.Sprintf("%d", i.Int)
case Add:
return fmt.Sprintf("%s + %s", i.Args[0], i.Args[1])
default:
return ""
}
} }

View file

@ -1,5 +1,6 @@
package ssa package ssa
// Type represents the instruction type.
type Type byte type Type byte
const ( const (
@ -24,6 +25,10 @@ const (
Shl Shl
Shr Shr
// Branch
If
Jump
// Special // Special
Call Call
Phi Phi

View file

@ -8,6 +8,8 @@ import (
"git.urbach.dev/go/assert" "git.urbach.dev/go/assert"
) )
// This benchmark compares the performance of fat structs and interfaces.
// It allocates `n` objects where `n` must be divisible by 2.
const n = 100 const n = 100
type FatStruct struct { type FatStruct struct {

View file

@ -4,11 +4,19 @@ import (
"testing" "testing"
"git.urbach.dev/cli/q/src/ssa" "git.urbach.dev/cli/q/src/ssa"
"git.urbach.dev/go/assert"
) )
func TestBlock(t *testing.T) { func TestBlock(t *testing.T) {
block := &ssa.Block{} f := ssa.Function{}
block.Append(ssa.Instruction{Type: ssa.Int, Int: 1}) block := f.AddBlock()
block.Append(ssa.Instruction{Type: ssa.Int, Int: 2}) a := block.Append(ssa.Instruction{Type: ssa.Int, Int: 1})
block.Append(ssa.Instruction{Type: ssa.Add, Parameters: []ssa.Index{0, 1}}) b := block.Append(ssa.Instruction{Type: ssa.Int, Int: 2})
c := block.Append(ssa.Instruction{Type: ssa.Add, Args: []*ssa.Instruction{a, b}})
assert.Equal(t, c.String(), "1 + 2")
}
func TestInvalidInstruction(t *testing.T) {
instr := ssa.Instruction{}
assert.Equal(t, instr.String(), "")
} }