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
// Block is a list of instructions that can be targeted in branches.
type Block struct {
Entry []*Block
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)
return &b.Instructions[len(b.Instructions)-1]
}

View file

@ -1,5 +1,13 @@
package ssa
// Function is a list of basic blocks.
type Function struct {
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
// 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.
type Instruction struct {
Type Type
Parameters []Index
Int int64
Float float64
String string
Type Type
Args []*Instruction
Int int64
Float float64
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
// Type represents the instruction type.
type Type byte
const (
@ -24,6 +25,10 @@ const (
Shl
Shr
// Branch
If
Jump
// Special
Call
Phi

View file

@ -8,6 +8,8 @@ import (
"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
type FatStruct struct {

View file

@ -4,11 +4,19 @@ import (
"testing"
"git.urbach.dev/cli/q/src/ssa"
"git.urbach.dev/go/assert"
)
func TestBlock(t *testing.T) {
block := &ssa.Block{}
block.Append(ssa.Instruction{Type: ssa.Int, Int: 1})
block.Append(ssa.Instruction{Type: ssa.Int, Int: 2})
block.Append(ssa.Instruction{Type: ssa.Add, Parameters: []ssa.Index{0, 1}})
f := ssa.Function{}
block := f.AddBlock()
a := block.Append(ssa.Instruction{Type: ssa.Int, Int: 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(), "")
}