Implemented dead code elimination
This commit is contained in:
parent
d86d411959
commit
526b92aa09
@ -27,6 +27,7 @@ func TestErrors(t *testing.T) {
|
|||||||
{"MissingBlockStart.q", errors.MissingBlockStart},
|
{"MissingBlockStart.q", errors.MissingBlockStart},
|
||||||
{"MissingGroupEnd.q", errors.MissingGroupEnd},
|
{"MissingGroupEnd.q", errors.MissingGroupEnd},
|
||||||
{"MissingGroupStart.q", errors.MissingGroupStart},
|
{"MissingGroupStart.q", errors.MissingGroupStart},
|
||||||
|
{"MissingMainFunction.q", errors.MissingMainFunction},
|
||||||
{"VariableAlreadyExists.q", &errors.VariableAlreadyExists{Name: "x"}},
|
{"VariableAlreadyExists.q", &errors.VariableAlreadyExists{Name: "x"}},
|
||||||
{"UnknownIdentifier.q", &errors.UnknownIdentifier{Name: "x"}},
|
{"UnknownIdentifier.q", &errors.UnknownIdentifier{Name: "x"}},
|
||||||
{"UnknownIdentifier2.q", &errors.UnknownIdentifier{Name: "x"}},
|
{"UnknownIdentifier2.q", &errors.UnknownIdentifier{Name: "x"}},
|
||||||
|
@ -13,4 +13,8 @@ print(address, length) {
|
|||||||
|
|
||||||
write(fd, address, length) {
|
write(fd, address, length) {
|
||||||
syscall(1, fd, address, length)
|
syscall(1, fd, address, length)
|
||||||
|
}
|
||||||
|
|
||||||
|
empty() {
|
||||||
|
|
||||||
}
|
}
|
@ -8,7 +8,8 @@ import (
|
|||||||
|
|
||||||
// Result contains all the compiled functions in a build.
|
// Result contains all the compiled functions in a build.
|
||||||
type Result struct {
|
type Result struct {
|
||||||
Functions map[string]*Function
|
Used []*Function
|
||||||
|
Unused map[string]*Function
|
||||||
instructionCount int
|
instructionCount int
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,13 +28,8 @@ func (r Result) Finalize() ([]byte, []byte) {
|
|||||||
final.RegisterNumber(asm.MOVE, x64.SyscallRegisters[1], 0)
|
final.RegisterNumber(asm.MOVE, x64.SyscallRegisters[1], 0)
|
||||||
final.Syscall()
|
final.Syscall()
|
||||||
|
|
||||||
// Place the `main` function immediately after the entry point.
|
// Merge all the called functions.
|
||||||
main := r.Functions["main"]
|
for _, f := range r.Used {
|
||||||
delete(r.Functions, "main")
|
|
||||||
final.Merge(&main.Assembler)
|
|
||||||
|
|
||||||
// Merge all the remaining functions.
|
|
||||||
for _, f := range r.Functions {
|
|
||||||
final.Merge(&f.Assembler)
|
final.Merge(&f.Assembler)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,12 +2,15 @@ package build
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"git.akyoto.dev/cli/q/src/build/asm"
|
||||||
|
fail "git.akyoto.dev/cli/q/src/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// compile waits for the scan to finish and compiles all functions.
|
// compile waits for the scan to finish and compiles all functions.
|
||||||
func compile(functions <-chan *Function, errors <-chan error) (Result, error) {
|
func compile(functions <-chan *Function, errors <-chan error) (Result, error) {
|
||||||
result := Result{
|
result := Result{
|
||||||
Functions: map[string]*Function{},
|
Unused: map[string]*Function{},
|
||||||
}
|
}
|
||||||
|
|
||||||
for functions != nil || errors != nil {
|
for functions != nil || errors != nil {
|
||||||
@ -26,13 +29,13 @@ func compile(functions <-chan *Function, errors <-chan error) (Result, error) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
result.Functions[function.Name] = function
|
result.Unused[function.Name] = function
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
compileFunctions(result.Functions)
|
compileFunctions(result.Unused)
|
||||||
|
|
||||||
for _, function := range result.Functions {
|
for _, function := range result.Unused {
|
||||||
if function.Error != nil {
|
if function.Error != nil {
|
||||||
return result, function.Error
|
return result, function.Error
|
||||||
}
|
}
|
||||||
@ -40,9 +43,38 @@ func compile(functions <-chan *Function, errors <-chan error) (Result, error) {
|
|||||||
result.instructionCount += len(function.Assembler.Instructions)
|
result.instructionCount += len(function.Assembler.Instructions)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
main, exists := result.Unused["main"]
|
||||||
|
|
||||||
|
if !exists {
|
||||||
|
return result, fail.MissingMainFunction
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Used = append(result.Used, main)
|
||||||
|
delete(result.Unused, "main")
|
||||||
|
result.findCalls(main)
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (result *Result) findCalls(f *Function) {
|
||||||
|
for _, x := range f.Assembler.Instructions {
|
||||||
|
if x.Mnemonic != asm.CALL {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
name := x.Data.(*asm.Label).Name
|
||||||
|
called, exists := result.Unused[name]
|
||||||
|
|
||||||
|
if !exists {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Used = append(result.Used, called)
|
||||||
|
delete(result.Unused, name)
|
||||||
|
result.findCalls(called)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// compileFunctions starts a goroutine for each function compilation and waits for completion.
|
// compileFunctions starts a goroutine for each function compilation and waits for completion.
|
||||||
func compileFunctions(functions map[string]*Function) {
|
func compileFunctions(functions map[string]*Function) {
|
||||||
wg := sync.WaitGroup{}
|
wg := sync.WaitGroup{}
|
||||||
|
@ -43,7 +43,7 @@ func Build(args []string) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if config.Verbose {
|
if config.Verbose {
|
||||||
for _, function := range result.Functions {
|
for _, function := range result.Used {
|
||||||
function.PrintAsm()
|
function.PrintAsm()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
package errors
|
package errors
|
||||||
|
|
||||||
var (
|
var (
|
||||||
InvalidStatement = &Base{"Invalid statement"}
|
InvalidStatement = &Base{"Invalid statement"}
|
||||||
InvalidExpression = &Base{"Invalid expression"}
|
InvalidExpression = &Base{"Invalid expression"}
|
||||||
MissingAssignValue = &Base{"Missing assignment value"}
|
MissingAssignValue = &Base{"Missing assignment value"}
|
||||||
NotImplemented = &Base{"Not implemented"}
|
MissingMainFunction = &Base{"Missing main function"}
|
||||||
|
NotImplemented = &Base{"Not implemented"}
|
||||||
)
|
)
|
||||||
|
0
tests/errors/MissingMainFunction.q
Normal file
0
tests/errors/MissingMainFunction.q
Normal file
Loading…
Reference in New Issue
Block a user