Added label type

This commit is contained in:
2025-03-13 16:57:13 +01:00
parent d96c351b4b
commit c1913d99d0
32 changed files with 102 additions and 63 deletions

View File

@ -2,12 +2,12 @@ package asm
// Comment adds a comment at the current position. // Comment adds a comment at the current position.
func (a *Assembler) Comment(text string) { func (a *Assembler) Comment(text string) {
a.Label(COMMENT, text) a.Label(COMMENT, Label{Name: text, Type: CommentLabel})
} }
// DLLCall calls a function in a DLL file. // DLLCall calls a function in a DLL file.
func (a *Assembler) DLLCall(name string) { func (a *Assembler) DLLCall(name string) {
a.Label(DLLCALL, name) a.Label(DLLCALL, Label{Name: name, Type: ExternLabel})
} }
// Return returns back to the caller. // Return returns back to the caller.

View File

@ -3,6 +3,7 @@ package asm
// Label represents a jump label. // Label represents a jump label.
type Label struct { type Label struct {
Name string Name string
Type LabelType
} }
// String returns a human readable version. // String returns a human readable version.
@ -11,14 +12,12 @@ func (data *Label) String() string {
} }
// Label adds an instruction using a label. // Label adds an instruction using a label.
func (a *Assembler) Label(mnemonic Mnemonic, name string) { func (a *Assembler) Label(mnemonic Mnemonic, label Label) {
a.Instructions = append(a.Instructions, Instruction{ a.Instructions = append(a.Instructions, Instruction{
Mnemonic: mnemonic, Mnemonic: mnemonic,
Type: TypeLabel, Type: TypeLabel,
Index: Index(len(a.Param.Label)), Index: Index(len(a.Param.Label)),
}) })
a.Param.Label = append(a.Param.Label, Label{ a.Param.Label = append(a.Param.Label, label)
Name: name,
})
} }

13
src/asm/LabelType.go Normal file
View File

@ -0,0 +1,13 @@
package asm
// LabelType shows what the label was used for.
type LabelType uint8
const (
UnknownLabel LabelType = iota
CommentLabel
ControlLabel
DataLabel
FunctionLabel
ExternLabel
)

View File

@ -2,17 +2,17 @@ package asm
// MemoryLabel operates with a memory address and a number. // MemoryLabel operates with a memory address and a number.
type MemoryLabel struct { type MemoryLabel struct {
Label string Label Label
Address Memory Address Memory
} }
// String returns a human readable version. // String returns a human readable version.
func (data *MemoryLabel) String() string { func (data *MemoryLabel) String() string {
return data.Address.Format(data.Label) return data.Address.Format(data.Label.Name)
} }
// MemoryLabel adds an instruction with a memory address and a label. // MemoryLabel adds an instruction with a memory address and a label.
func (a *Assembler) MemoryLabel(mnemonic Mnemonic, address Memory, label string) { func (a *Assembler) MemoryLabel(mnemonic Mnemonic, address Memory, label Label) {
a.Instructions = append(a.Instructions, Instruction{ a.Instructions = append(a.Instructions, Instruction{
Mnemonic: mnemonic, Mnemonic: mnemonic,
Type: TypeMemoryLabel, Type: TypeMemoryLabel,

View File

@ -8,17 +8,17 @@ import (
// RegisterLabel operates with a register and a label. // RegisterLabel operates with a register and a label.
type RegisterLabel struct { type RegisterLabel struct {
Label string Label Label
Register cpu.Register Register cpu.Register
} }
// String returns a human readable version. // String returns a human readable version.
func (data *RegisterLabel) String() string { func (data *RegisterLabel) String() string {
return fmt.Sprintf("%s, %s", data.Register, data.Label) return fmt.Sprintf("%s, %s", data.Register, data.Label.Name)
} }
// RegisterLabel adds an instruction with a register and a label. // RegisterLabel adds an instruction with a register and a label.
func (a *Assembler) RegisterLabel(mnemonic Mnemonic, register cpu.Register, label string) { func (a *Assembler) RegisterLabel(mnemonic Mnemonic, register cpu.Register, label Label) {
a.Instructions = append(a.Instructions, Instruction{ a.Instructions = append(a.Instructions, Instruction{
Mnemonic: mnemonic, Mnemonic: mnemonic,
Type: TypeRegisterLabel, Type: TypeRegisterLabel,

View File

@ -3,7 +3,6 @@ package asmc
import ( import (
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"strings"
"git.urbach.dev/cli/q/src/arm" "git.urbach.dev/cli/q/src/arm"
"git.urbach.dev/cli/q/src/asm" "git.urbach.dev/cli/q/src/asm"
@ -44,8 +43,11 @@ func (c *compiler) compileARM(x asm.Instruction) {
case asm.LABEL: case asm.LABEL:
label := c.assembler.Param.Label[x.Index] label := c.assembler.Param.Label[x.Index]
c.codeLabels[label.Name] = Address(len(c.code)) c.codeLabels[label.Name] = Address(len(c.code))
c.append(arm.StorePair(arm.FP, arm.LR, arm.SP, -16))
c.append(arm.MoveRegisterRegister(arm.FP, arm.SP)) if label.Type == asm.FunctionLabel {
c.append(arm.StorePair(arm.FP, arm.LR, arm.SP, -16))
c.append(arm.MoveRegisterRegister(arm.FP, arm.SP))
}
case asm.LOAD: case asm.LOAD:
switch x.Type { switch x.Type {
@ -140,13 +142,13 @@ func (c *compiler) compileARM(x asm.Instruction) {
position := Address(len(c.code)) position := Address(len(c.code))
c.append(arm.LoadAddress(operands.Register, 0)) c.append(arm.LoadAddress(operands.Register, 0))
if strings.HasPrefix(operands.Label, "data ") { if operands.Label.Type == asm.DataLabel {
c.dataPointers = append(c.dataPointers, &pointer{ c.dataPointers = append(c.dataPointers, &pointer{
Position: position, Position: position,
OpSize: 0, OpSize: 0,
Size: 4, Size: 4,
Resolve: func() Address { Resolve: func() Address {
destination, exists := c.dataLabels[operands.Label] destination, exists := c.dataLabels[operands.Label.Name]
if !exists { if !exists {
panic("unknown label") panic("unknown label")

View File

@ -1,8 +1,6 @@
package asmc package asmc
import ( import (
"strings"
"git.urbach.dev/cli/q/src/asm" "git.urbach.dev/cli/q/src/asm"
"git.urbach.dev/cli/q/src/x86" "git.urbach.dev/cli/q/src/x86"
) )
@ -25,13 +23,13 @@ func (c *compiler) move(x asm.Instruction) {
position := end - 4 position := end - 4
opSize := position - start opSize := position - start
if strings.HasPrefix(operands.Label, "data ") { if operands.Label.Type == asm.DataLabel {
c.dataPointers = append(c.dataPointers, &pointer{ c.dataPointers = append(c.dataPointers, &pointer{
Position: position, Position: position,
OpSize: uint8(opSize), OpSize: uint8(opSize),
Size: uint8(4), Size: uint8(4),
Resolve: func() Address { Resolve: func() Address {
destination, exists := c.dataLabels[operands.Label] destination, exists := c.dataLabels[operands.Label.Name]
if !exists { if !exists {
panic("unknown label") panic("unknown label")
@ -48,7 +46,7 @@ func (c *compiler) move(x asm.Instruction) {
OpSize: uint8(opSize), OpSize: uint8(opSize),
Size: uint8(4), Size: uint8(4),
Resolve: func() Address { Resolve: func() Address {
destination, exists := c.codeLabels[operands.Label] destination, exists := c.codeLabels[operands.Label.Name]
if !exists { if !exists {
panic("unknown label") panic("unknown label")

View File

@ -34,7 +34,7 @@ func (c *compiler) store(x asm.Instruction) {
OpSize: uint8(opSize), OpSize: uint8(opSize),
Size: uint8(size), Size: uint8(size),
Resolve: func() Address { Resolve: func() Address {
destination, exists := c.codeLabels[operands.Label] destination, exists := c.codeLabels[operands.Label.Name]
if !exists { if !exists {
panic("unknown label") panic("unknown label")

View File

@ -45,7 +45,10 @@ func (r *Result) finalize() {
} }
}) })
final.Label(asm.LABEL, "_crash") final.Label(asm.LABEL, asm.Label{
Name: "_crash",
Type: asm.ControlLabel,
})
switch config.TargetOS { switch config.TargetOS {
case config.Linux: case config.Linux:

View File

@ -1,9 +1,11 @@
package core package core
import "git.urbach.dev/cli/q/src/asm"
// AddBytes adds a sequence of bytes and returns its address as a label. // AddBytes adds a sequence of bytes and returns its address as a label.
func (f *Function) AddBytes(value []byte) string { func (f *Function) AddBytes(value []byte) asm.Label {
f.count.data++ f.count.data++
label := f.CreateLabel("data", f.count.data) label := f.CreateLabel("data", f.count.data, asm.DataLabel)
f.Assembler.SetData(label, value) f.Assembler.SetData(label.Name, value)
return label return label
} }

View File

@ -1,8 +1,14 @@
package core package core
import "git.urbach.dev/cli/q/src/asm"
// Compile turns a function into machine code. // Compile turns a function into machine code.
func (f *Function) Compile() { func (f *Function) Compile() {
f.AddLabel(f.UniqueName) f.AddLabel(asm.Label{
Name: f.UniqueName,
Type: asm.FunctionLabel,
})
f.Err = f.CompileTokens(f.Body) f.Err = f.CompileTokens(f.Body)
f.Return() f.Return()

View File

@ -8,8 +8,8 @@ import (
// CompileAssert compiles an assertion. // CompileAssert compiles an assertion.
func (f *Function) CompileAssert(assert *ast.Assert) error { func (f *Function) CompileAssert(assert *ast.Assert) error {
f.count.assert++ f.count.assert++
success := f.CreateLabel("assert true", f.count.assert) success := f.CreateLabel("assert true", f.count.assert, asm.ControlLabel)
fail := f.CreateLabel("assert false", f.count.assert) fail := f.CreateLabel("assert false", f.count.assert, asm.ControlLabel)
err := f.CompileCondition(assert.Condition, success, fail) err := f.CompileCondition(assert.Condition, success, fail)
if err != nil { if err != nil {
@ -20,7 +20,7 @@ func (f *Function) CompileAssert(assert *ast.Assert) error {
f.Defer(func() { f.Defer(func() {
f.AddLabel(fail) f.AddLabel(fail)
f.Jump(asm.JUMP, "_crash") f.Jump(asm.JUMP, asm.Label{Name: "_crash", Type: asm.ControlLabel})
}) })
return err return err

View File

@ -58,7 +58,7 @@ func (f *Function) CompileCall(root *expression.Expression) ([]*Parameter, error
switch value := value.(type) { switch value := value.(type) {
case *eval.Label: case *eval.Label:
fn := f.All.Functions[value.Label] fn := f.All.Functions[value.Label.Name]
if len(parameters) != len(fn.Input) { if len(parameters) != len(fn.Input) {
return nil, errors.New(&errors.ParameterCountMismatch{Function: fn.Name, Count: len(parameters), ExpectedCount: len(fn.Input)}, f.File, root.Children[0].Token.End()) return nil, errors.New(&errors.ParameterCountMismatch{Function: fn.Name, Count: len(parameters), ExpectedCount: len(fn.Input)}, f.File, root.Children[0].Token.End())

View File

@ -12,11 +12,11 @@ import (
) )
// CompileCondition inserts code to jump to the start label or end label depending on the truth of the condition. // CompileCondition inserts code to jump to the start label or end label depending on the truth of the condition.
func (f *Function) CompileCondition(condition *expression.Expression, successLabel string, failLabel string) error { func (f *Function) CompileCondition(condition *expression.Expression, successLabel asm.Label, failLabel asm.Label) error {
switch condition.Token.Kind { switch condition.Token.Kind {
case token.LogicalOr: case token.LogicalOr:
f.count.subBranch++ f.count.subBranch++
leftFailLabel := f.CreateLabel("false", f.count.subBranch) leftFailLabel := f.CreateLabel("false", f.count.subBranch, asm.ControlLabel)
// Left // Left
left := condition.Children[0] left := condition.Children[0]
@ -43,7 +43,7 @@ func (f *Function) CompileCondition(condition *expression.Expression, successLab
case token.LogicalAnd: case token.LogicalAnd:
f.count.subBranch++ f.count.subBranch++
leftSuccessLabel := f.CreateLabel("true", f.count.subBranch) leftSuccessLabel := f.CreateLabel("true", f.count.subBranch, asm.ControlLabel)
// Left // Left
left := condition.Children[0] left := condition.Children[0]

View File

@ -24,7 +24,7 @@ func (f *Function) CompileDelete(root *expression.Expression) error {
f.RegisterNumber(asm.MOVE, f.CPU.Input[1], variable.Value.Typ.(*types.Pointer).To.Size()) f.RegisterNumber(asm.MOVE, f.CPU.Input[1], variable.Value.Typ.(*types.Pointer).To.Size())
free := f.All.Functions["mem.free"] free := f.All.Functions["mem.free"]
f.BeforeCall() f.BeforeCall()
f.Label(asm.CALL, "mem.free") f.Label(asm.CALL, asm.Label{Name: "mem.free", Type: asm.FunctionLabel})
f.AfterCall(f.CPU.Input[:2]) f.AfterCall(f.CPU.Input[:2])
f.Dependencies = append(f.Dependencies, free) f.Dependencies = append(f.Dependencies, free)
return nil return nil

View File

@ -23,8 +23,8 @@ func (f *Function) CompileFor(loop *ast.For) error {
f.count.loop++ f.count.loop++
var ( var (
label = f.CreateLabel("for", f.count.loop) label = f.CreateLabel("for", f.count.loop, asm.ControlLabel)
labelEnd = f.CreateLabel("for end", f.count.loop) labelEnd = f.CreateLabel("for end", f.count.loop, asm.ControlLabel)
counter cpu.Register counter cpu.Register
from *expression.Expression from *expression.Expression
to *expression.Expression to *expression.Expression

View File

@ -14,9 +14,9 @@ func (f *Function) CompileIf(branch *ast.If) error {
f.count.branch++ f.count.branch++
var ( var (
end string end asm.Label
success = f.CreateLabel("if true", f.count.branch) success = f.CreateLabel("if true", f.count.branch, asm.ControlLabel)
fail = f.CreateLabel("if false", f.count.branch) fail = f.CreateLabel("if false", f.count.branch, asm.ControlLabel)
err = f.CompileCondition(branch.Condition, success, fail) err = f.CompileCondition(branch.Condition, success, fail)
) )
@ -33,7 +33,7 @@ func (f *Function) CompileIf(branch *ast.If) error {
} }
if branch.Else != nil { if branch.Else != nil {
end = f.CreateLabel("if end", f.count.branch) end = f.CreateLabel("if end", f.count.branch, asm.ControlLabel)
f.Jump(asm.JUMP, end) f.Jump(asm.JUMP, end)
} }

View File

@ -12,7 +12,7 @@ func (f *Function) CompileLoop(loop *ast.Loop) error {
} }
f.count.loop++ f.count.loop++
label := f.CreateLabel("loop", f.count.loop) label := f.CreateLabel("loop", f.count.loop, asm.ControlLabel)
f.AddLabel(label) f.AddLabel(label)
scope := f.PushScope(loop.Body, f.File.Bytes) scope := f.PushScope(loop.Body, f.File.Bytes)
scope.InLoop = true scope.InLoop = true

View File

@ -47,7 +47,7 @@ func (f *Function) CompileNew(root *expression.Expression) (types.Type, error) {
f.RegisterNumber(asm.MOVE, f.CPU.Input[0], typ.Size()) f.RegisterNumber(asm.MOVE, f.CPU.Input[0], typ.Size())
alloc := f.All.Functions["mem.alloc"] alloc := f.All.Functions["mem.alloc"]
f.BeforeCall() f.BeforeCall()
f.Label(asm.CALL, "mem.alloc") f.Label(asm.CALL, asm.Label{Name: "mem.alloc", Type: asm.FunctionLabel})
f.AfterCall(f.CPU.Input[:1]) f.AfterCall(f.CPU.Input[:1])
f.Dependencies = append(f.Dependencies, alloc) f.Dependencies = append(f.Dependencies, alloc)
return &types.Pointer{To: typ}, nil return &types.Pointer{To: typ}, nil

View File

@ -8,7 +8,7 @@ import (
// CompileSwitch compiles a multi-branch instruction. // CompileSwitch compiles a multi-branch instruction.
func (f *Function) CompileSwitch(s *ast.Switch) error { func (f *Function) CompileSwitch(s *ast.Switch) error {
f.count.multiBranch++ f.count.multiBranch++
end := f.CreateLabel("switch end", f.count.multiBranch) end := f.CreateLabel("switch end", f.count.multiBranch, asm.ControlLabel)
for _, branch := range s.Cases { for _, branch := range s.Cases {
if branch.Condition == nil { if branch.Condition == nil {
@ -26,8 +26,8 @@ func (f *Function) CompileSwitch(s *ast.Switch) error {
f.count.branch++ f.count.branch++
var ( var (
success = f.CreateLabel("case true", f.count.branch) success = f.CreateLabel("case true", f.count.branch, asm.ControlLabel)
fail = f.CreateLabel("case false", f.count.branch) fail = f.CreateLabel("case false", f.count.branch, asm.ControlLabel)
err = f.CompileCondition(branch.Condition, success, fail) err = f.CompileCondition(branch.Condition, success, fail)
) )

View File

@ -3,10 +3,12 @@ package core
import ( import (
"strconv" "strconv"
"strings" "strings"
"git.urbach.dev/cli/q/src/asm"
) )
// CreateLabel creates a label that is tied to this function by using a suffix. // CreateLabel creates a label that is tied to this function by using a suffix.
func (f *Function) CreateLabel(prefix string, count counter) string { func (f *Function) CreateLabel(prefix string, count counter, typ asm.LabelType) asm.Label {
tmp := strings.Builder{} tmp := strings.Builder{}
tmp.WriteString(prefix) tmp.WriteString(prefix)
tmp.WriteString(" ") tmp.WriteString(" ")
@ -14,5 +16,9 @@ func (f *Function) CreateLabel(prefix string, count counter) string {
tmp.WriteString(" [") tmp.WriteString(" [")
tmp.WriteString(f.UniqueName) tmp.WriteString(f.UniqueName)
tmp.WriteString("]") tmp.WriteString("]")
return tmp.String()
return asm.Label{
Name: tmp.String(),
Type: typ,
}
} }

View File

@ -79,8 +79,11 @@ func (f *Function) EvaluateDot(expr *expression.Expression) (eval.Value, error)
f.Dependencies = append(f.Dependencies, function) f.Dependencies = append(f.Dependencies, function)
value := &eval.Label{ value := &eval.Label{
Typ: types.AnyPointer, Typ: types.AnyPointer,
Label: label, Label: asm.Label{
Name: label,
Type: asm.FunctionLabel,
},
} }
return value, nil return value, nil

View File

@ -4,6 +4,7 @@ import (
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"git.urbach.dev/cli/q/src/asm"
"git.urbach.dev/cli/q/src/errors" "git.urbach.dev/cli/q/src/errors"
"git.urbach.dev/cli/q/src/eval" "git.urbach.dev/cli/q/src/eval"
"git.urbach.dev/cli/q/src/token" "git.urbach.dev/cli/q/src/token"
@ -48,8 +49,11 @@ func (f *Function) EvaluateToken(t token.Token) (eval.Value, error) {
f.Dependencies = append(f.Dependencies, function) f.Dependencies = append(f.Dependencies, function)
value := &eval.Label{ value := &eval.Label{
Typ: types.AnyPointer, Typ: types.AnyPointer,
Label: function.UniqueName, Label: asm.Label{
Name: function.UniqueName,
Type: asm.FunctionLabel,
},
} }
return value, nil return value, nil

View File

@ -6,7 +6,7 @@ import (
) )
// JumpIfFalse jumps to the label if the previous comparison was false. // JumpIfFalse jumps to the label if the previous comparison was false.
func (f *Function) JumpIfFalse(operator token.Kind, label string) { func (f *Function) JumpIfFalse(operator token.Kind, label asm.Label) {
switch operator { switch operator {
case token.Equal: case token.Equal:
f.Jump(asm.JNE, label) f.Jump(asm.JNE, label)

View File

@ -6,7 +6,7 @@ import (
) )
// JumpIfTrue jumps to the label if the previous comparison was true. // JumpIfTrue jumps to the label if the previous comparison was true.
func (f *Function) JumpIfTrue(operator token.Kind, label string) { func (f *Function) JumpIfTrue(operator token.Kind, label asm.Label) {
switch operator { switch operator {
case token.Equal: case token.Equal:
f.Jump(asm.JE, label) f.Jump(asm.JE, label)

View File

@ -1,11 +1,14 @@
package eval package eval
import "git.urbach.dev/cli/q/src/types" import (
"git.urbach.dev/cli/q/src/asm"
"git.urbach.dev/cli/q/src/types"
)
// Label is a named pointer to a code or data section. // Label is a named pointer to a code or data section.
type Label struct { type Label struct {
Typ types.Type Typ types.Type
Label string Label asm.Label
} }
func (v *Label) String() string { func (v *Label) String() string {

View File

@ -2,7 +2,7 @@ package register
import "git.urbach.dev/cli/q/src/asm" import "git.urbach.dev/cli/q/src/asm"
func (f *Machine) AddLabel(label string) { func (f *Machine) AddLabel(label asm.Label) {
f.Assembler.Label(asm.LABEL, label) f.Assembler.Label(asm.LABEL, label)
f.postInstruction() f.postInstruction()
} }

View File

@ -3,7 +3,7 @@ package register
import "git.urbach.dev/cli/q/src/asm" import "git.urbach.dev/cli/q/src/asm"
func (f *Machine) DLLCall(label string) { func (f *Machine) DLLCall(label string) {
f.Assembler.Label(asm.DLLCALL, label) f.Assembler.Label(asm.DLLCALL, asm.Label{Name: label, Type: asm.UnknownLabel})
f.UseRegister(f.CPU.Output[0]) f.UseRegister(f.CPU.Output[0])
f.postInstruction() f.postInstruction()
} }

View File

@ -2,7 +2,7 @@ package register
import "git.urbach.dev/cli/q/src/asm" import "git.urbach.dev/cli/q/src/asm"
func (f *Machine) Jump(mnemonic asm.Mnemonic, label string) { func (f *Machine) Jump(mnemonic asm.Mnemonic, label asm.Label) {
f.Assembler.Label(mnemonic, label) f.Assembler.Label(mnemonic, label)
f.postInstruction() f.postInstruction()
} }

View File

@ -2,7 +2,7 @@ package register
import "git.urbach.dev/cli/q/src/asm" import "git.urbach.dev/cli/q/src/asm"
func (f *Machine) Label(mnemonic asm.Mnemonic, label string) { func (f *Machine) Label(mnemonic asm.Mnemonic, label asm.Label) {
f.Assembler.Label(mnemonic, label) f.Assembler.Label(mnemonic, label)
f.postInstruction() f.postInstruction()
} }

View File

@ -2,7 +2,7 @@ package register
import "git.urbach.dev/cli/q/src/asm" import "git.urbach.dev/cli/q/src/asm"
func (f *Machine) MemoryLabel(mnemonic asm.Mnemonic, a asm.Memory, b string) { func (f *Machine) MemoryLabel(mnemonic asm.Mnemonic, a asm.Memory, b asm.Label) {
f.Assembler.MemoryLabel(mnemonic, a, b) f.Assembler.MemoryLabel(mnemonic, a, b)
f.postInstruction() f.postInstruction()
} }

View File

@ -5,7 +5,7 @@ import (
"git.urbach.dev/cli/q/src/cpu" "git.urbach.dev/cli/q/src/cpu"
) )
func (f *Machine) RegisterLabel(mnemonic asm.Mnemonic, register cpu.Register, label string) { func (f *Machine) RegisterLabel(mnemonic asm.Mnemonic, register cpu.Register, label asm.Label) {
f.Assembler.RegisterLabel(mnemonic, register, label) f.Assembler.RegisterLabel(mnemonic, register, label)
if mnemonic == asm.MOVE { if mnemonic == asm.MOVE {