Implemented dependency tracking

This commit is contained in:
Eduard Urbach 2025-03-03 12:14:53 +01:00
parent 08660ad845
commit 751614e7c0
Signed by: akyoto
GPG Key ID: C874F672B1AF20C0
12 changed files with 75 additions and 69 deletions

View File

@ -1,6 +1,8 @@
package asmc package asmc
import ( import (
"fmt"
"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"
) )
@ -21,7 +23,7 @@ func (c *compiler) call(x asm.Instruction) {
destination, exists := c.codeLabels[data.Name] destination, exists := c.codeLabels[data.Name]
if !exists { if !exists {
panic("unknown jump label") panic(fmt.Sprintf("unknown jump label %s", data.Name))
} }
distance := destination - (pointer.Position + Address(pointer.Size)) distance := destination - (pointer.Position + Address(pointer.Size))

View File

@ -1,6 +1,8 @@
package asmc package asmc
import ( import (
"fmt"
"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"
) )
@ -36,7 +38,7 @@ func (c *compiler) jump(x asm.Instruction) {
destination, exists := c.codeLabels[label.Name] destination, exists := c.codeLabels[label.Name]
if !exists { if !exists {
panic("unknown jump label") panic(fmt.Sprintf("unknown jump label %s", label.Name))
} }
distance := destination - (pointer.Position + Address(pointer.Size)) distance := destination - (pointer.Position + Address(pointer.Size))

View File

@ -82,6 +82,20 @@ func Compile(constants <-chan *core.Constant, files <-chan *fs.File, functions <
} }
} }
// Check for existence of `init`
init, exists := all.Functions["core.init"]
if !exists {
return result, errors.MissingInitFunction
}
// Check for existence of `main`
main, exists := all.Functions["main.main"]
if !exists {
return result, errors.MissingMainFunction
}
// Start parallel compilation // Start parallel compilation
CompileFunctions(all.Functions) CompileFunctions(all.Functions)
@ -104,20 +118,6 @@ func Compile(constants <-chan *core.Constant, files <-chan *fs.File, functions <
} }
} }
// Check for existence of `init`
init, exists := all.Functions["core.init"]
if !exists {
return result, errors.MissingInitFunction
}
// Check for existence of `main`
main, exists := all.Functions["main.main"]
if !exists {
return result, errors.MissingMainFunction
}
result.Init = init result.Init = init
result.Main = main result.Main = main
result.Functions = all.Functions result.Functions = all.Functions

View File

@ -1,37 +1,20 @@
package compiler package compiler
import ( import (
"git.urbach.dev/cli/q/src/asm"
"git.urbach.dev/cli/q/src/core" "git.urbach.dev/cli/q/src/core"
) )
// eachFunction recursively finds all the calls to external functions. // eachFunction recursively finds all the calls to other functions.
// It avoids calling the same function twice with the help of a hashmap. // It avoids calling the same function twice with the help of a hashmap.
func (r *Result) eachFunction(caller *core.Function, traversed map[*core.Function]bool, call func(*core.Function)) { func (r *Result) eachFunction(caller *core.Function, traversed map[*core.Function]bool, call func(*core.Function)) {
call(caller) call(caller)
traversed[caller] = true traversed[caller] = true
for _, x := range caller.Assembler.Instructions { for _, function := range caller.Dependencies {
if x.Mnemonic != asm.CALL { if traversed[function] {
continue continue
} }
label, isLabel := x.Data.(*asm.Label) r.eachFunction(function, traversed, call)
if !isLabel {
continue
}
callee, exists := r.Functions[label.Name]
if !exists {
continue
}
if traversed[callee] {
continue
}
r.eachFunction(callee, traversed, call)
} }
} }

View File

@ -43,16 +43,7 @@ func (f *Function) CompileCall(root *expression.Expression) ([]types.Type, error
switch value := value.(type) { switch value := value.(type) {
case *eval.Label: case *eval.Label:
fn, exists := f.All.Functions[value.Label] fn := f.All.Functions[value.Label]
if !exists {
if value.Label == "main.main" && f.UniqueName == "core.init" {
f.Label(asm.CALL, "main.main")
return nil, nil
}
return nil, errors.New(&errors.UnknownIdentifier{Name: value.Label}, f.File, root.Children[0].Token.Position)
}
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

@ -22,6 +22,8 @@ func (f *Function) CompileDelete(root *expression.Expression) error {
f.SaveRegister(f.CPU.Input[1]) f.SaveRegister(f.CPU.Input[1])
f.RegisterRegister(asm.MOVE, f.CPU.Input[0], variable.Value.Register) f.RegisterRegister(asm.MOVE, f.CPU.Input[0], variable.Value.Register)
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())
f.CallSafe(f.All.Functions["mem.free"], f.CPU.Input[:2]) free := f.All.Functions["mem.free"]
f.CallSafe(free, f.CPU.Input[:2])
f.Dependencies = append(f.Dependencies, free)
return nil return nil
} }

View File

@ -45,6 +45,8 @@ func (f *Function) CompileNew(root *expression.Expression) (types.Type, error) {
f.SaveRegister(f.CPU.Input[0]) f.SaveRegister(f.CPU.Input[0])
f.RegisterNumber(asm.MOVE, f.CPU.Input[0], typ.Size()) f.RegisterNumber(asm.MOVE, f.CPU.Input[0], typ.Size())
f.CallSafe(f.All.Functions["mem.alloc"], f.CPU.Input[:1]) alloc := f.All.Functions["mem.alloc"]
f.CallSafe(alloc, f.CPU.Input[:1])
f.Dependencies = append(f.Dependencies, alloc)
return &types.Pointer{To: typ}, nil return &types.Pointer{To: typ}, nil
} }

View File

@ -42,7 +42,8 @@ func (f *Function) EvaluateDot(expr *expression.Expression) (eval.Value, error)
return value, nil return value, nil
} }
constant, isConst := f.All.Constants[f.Package+"."+leftText+"."+rightText] label := fmt.Sprintf("%s.%s", leftText, rightText)
constant, isConst := f.All.Constants[f.Package+"."+label]
if isConst { if isConst {
number, err := ToNumber(constant.Token, constant.File) number, err := ToNumber(constant.Token, constant.File)
@ -73,10 +74,18 @@ func (f *Function) EvaluateDot(expr *expression.Expression) (eval.Value, error)
} }
} }
value := &eval.Label{ function, exists := f.All.Functions[label]
Typ: types.AnyPointer,
Label: fmt.Sprintf("%s.%s", leftText, rightText), if exists {
f.Dependencies = append(f.Dependencies, function)
value := &eval.Label{
Typ: types.AnyPointer,
Label: label,
}
return value, nil
} }
return value, nil return nil, errors.New(&errors.UnknownIdentifier{Name: label}, f.File, left.Token.Position)
} }

View File

@ -41,6 +41,8 @@ func (f *Function) EvaluateToken(t token.Token) (eval.Value, error) {
} }
if function != nil { if function != nil {
f.Dependencies = append(f.Dependencies, function)
value := &eval.Label{ value := &eval.Label{
Typ: types.AnyPointer, Typ: types.AnyPointer,
Label: function.UniqueName, Label: function.UniqueName,

View File

@ -11,17 +11,18 @@ import (
// Function represents the smallest unit of code. // Function represents the smallest unit of code.
type Function struct { type Function struct {
register.Machine register.Machine
Package string Package string
Name string Name string
UniqueName string UniqueName string
All *Environment All *Environment
File *fs.File File *fs.File
Body token.List Body token.List
Input []*Parameter Input []*Parameter
Output []*Parameter Output []*Parameter
OutputTypes []types.Type OutputTypes []types.Type
DLLs dll.List Dependencies []*Function
Err error DLLs dll.List
deferred []func() Err error
count count deferred []func()
count count
} }

View File

@ -1,4 +1,4 @@
import core import sys
struct Struct { struct Struct {
func *any func *any
@ -6,6 +6,11 @@ struct Struct {
main() { main() {
s := new(Struct) s := new(Struct)
s.func = core.exit s.func = f
s.func() s.func()
sys.exit(1)
}
f() {
sys.exit(0)
} }

View File

@ -1,6 +1,13 @@
import core import core
import sys
main() { main() {
func := f
func()
sys.exit(1)
}
f() {
exit := core.exit exit := core.exit
exit() exit()
} }