Something went wrong. Try again.
🌱 A minimal programming language and compiler. git.urbach.dev/cli/q
high-performance programming-language compiler
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292package verbose
import ( "fmt" "reflect"
"git.urbach.dev/cli/q/src/asm" "git.urbach.dev/cli/q/src/core" "git.urbach.dev/cli/q/src/cpu" "git.urbach.dev/cli/q/src/ssa" "git.urbach.dev/go/color/ansi")
// ASM shows the assembly code.func ASM(env *core.Environment, pattern string) { for f := range env.LiveFunctions() { if filter(f.FullName, pattern) { continue }
printAssembly(f) }}
// printAssembly shows the assembly instructions.func printAssembly(f *core.Function) { var ( mnemonic = ansi.Green function = ansi.Yellow imm = ansi.Cyan label = ansi.Reset other = ansi.Reset register = ansi.Reset )
rrr := func(name string, d cpu.Register, s cpu.Register, o cpu.Register) { mnemonic.Print(" " + name) register.Print(d) other.Print(", ") register.Print(s) other.Print(", ") register.Print(o) }
rrn := func(name string, d cpu.Register, s cpu.Register, n int) { mnemonic.Print(" " + name) register.Print(d) other.Print(", ") register.Print(s) other.Print(", ") imm.Print(n) }
rr := func(name string, d any, s any) { mnemonic.Print(" " + name) register.Print(d) other.Print(", ") register.Print(s) }
dn := func(name string, d cpu.Register, n int) { mnemonic.Print(" " + name) register.Print(d) other.Print(", ") imm.Print(n) }
regs := func(name string, registers []cpu.Register) { mnemonic.Print(" " + name)
for i, reg := range registers { if i != 0 { other.Print(", ") }
register.Print(reg) } }
printValue := func(value any) { switch value := value.(type) { case cpu.Register: register.Print(value) case int, int32: imm.Print(value) } }
load := func(length byte, d cpu.Register, base cpu.Register, index any, scale bool) { mnemonic.Printf(" load %db ", length) register.Print(d) other.Print(", [") register.Print(base) other.Print(" + ") printValue(index)
if scale { other.Print(" * ") imm.Print(length) }
other.Print("]") }
store := func(length byte, base cpu.Register, index any, source any, scale bool) { mnemonic.Printf(" store %db ", length) other.Print("[") register.Print(base) other.Print(" + ") printValue(index)
if scale { other.Print(" * ") imm.Print(length) }
other.Print("], ") printValue(source) }
condition := func(c asm.Condition) string { switch c { case asm.Equal: return "if == " case asm.NotEqual: return "if != " case asm.Greater: return "if.s > " case asm.GreaterEqual: return "if.s >= " case asm.Less: return "if.s < " case asm.LessEqual: return "if.s <= " case asm.UnsignedGreater: return "if.u > " case asm.UnsignedGreaterEqual: return "if.u >= " case asm.UnsignedLess: return "if.u < " case asm.UnsignedLessEqual: return "if.u <= " default: return "" } }
for _, instr := range f.Assembler.Instructions { switch instr := instr.(type) { case *asm.Add: rrr("add ", instr.Destination, instr.Source, instr.Operand) case *asm.AddNumber: rrn("add ", instr.Destination, instr.Source, instr.Number) case *asm.And: rrr("and ", instr.Destination, instr.Source, instr.Operand) case *asm.AndNumber: rrn("and ", instr.Destination, instr.Source, instr.Number) case *asm.Call: mnemonic.Print(" call ") label.Print(ssa.CleanLabel(instr.Label)) case *asm.CallExtern: mnemonic.Print(" call extern ") label.Print(instr.Library + "." + instr.Function) case *asm.Compare: rr("compare ", instr.Destination, instr.Source) case *asm.CompareAndSwap: rrr("cas ", instr.OldValue, instr.NewValue, instr.Address) case *asm.CompareNumber: dn("compare ", instr.Destination, instr.Number) case *asm.ConditionalSet: if suffix := condition(instr.Condition); suffix != "" { mnemonic.Print(" set " + suffix) } else { ansi.Red.Print(" set: unknown condition: " + fmt.Sprint(instr.Condition) + " ") }
register.Print(instr.Destination) case *asm.Divide: rrr("div.u ", instr.Destination, instr.Source, instr.Operand) case *asm.DivideSigned: rrr("div.s ", instr.Destination, instr.Source, instr.Operand) case *asm.Jump: switch instr.Condition { case asm.None: mnemonic.Print(" jump ") default: suffix := condition(instr.Condition)
if suffix != "" { mnemonic.Print(" jump " + suffix) } else { ansi.Red.Print(" jump: unknown condition: " + fmt.Sprint(instr.Condition) + " ") } }
label.Print(ssa.CleanLabel(instr.Label)) case *asm.Label: if instr.Name == f.FullName { function.Printf("%s:", instr.Name) } else { label.Printf("\n%s:", ssa.CleanLabel(instr.Name)) } case *asm.Load: load(instr.Length, instr.Destination, instr.Base, instr.Index, instr.Scale) case *asm.LoadFixedOffset: load(instr.Length, instr.Destination, instr.Base, instr.Index, instr.Scale) case *asm.Modulo: rrr("mod.u ", instr.Destination, instr.Source, instr.Operand) case *asm.ModuloSigned: rrr("mod.s ", instr.Destination, instr.Source, instr.Operand) case *asm.Move: rr("move ", instr.Destination, instr.Source) case *asm.MoveLabel: mnemonic.Print(" address ") register.Print(instr.Destination) other.Print(", ") label.Print(ssa.CleanLabel(instr.Label)) case *asm.MoveNumber: dn("move ", instr.Destination, instr.Number) case *asm.Multiply: rrr("mul ", instr.Destination, instr.Source, instr.Operand) case *asm.Negate: rr("neg ", instr.Destination, instr.Source) case *asm.Or: rrr("or ", instr.Destination, instr.Source, instr.Operand) case *asm.OrNumber: rrn("or ", instr.Destination, instr.Source, instr.Number) case *asm.Pop: regs("pop ", instr.Registers) case *asm.Push: regs("push ", instr.Registers) case *asm.ReadSystemRegister: rr("move ", instr.Destination, instr.SystemRegister) case *asm.Return: mnemonic.Print(" return") case *asm.ShiftLeft: rrr("shift << ", instr.Destination, instr.Source, instr.Operand) case *asm.ShiftLeftNumber: rrn("shift << ", instr.Destination, instr.Source, instr.Number) case *asm.ShiftRight: rrr("shift.u >> ", instr.Destination, instr.Source, instr.Operand) case *asm.ShiftRightNumber: rrn("shift.u >> ", instr.Destination, instr.Source, instr.Number) case *asm.ShiftRightSigned: rrr("shift.s >> ", instr.Destination, instr.Source, instr.Operand) case *asm.ShiftRightSignedNumber: rrn("shift.s >> ", instr.Destination, instr.Source, instr.Number) case *asm.Store: store(instr.Length, instr.Base, instr.Index, instr.Source, instr.Scale) case *asm.StoreFixedOffset: store(instr.Length, instr.Base, instr.Index, instr.Source, instr.Scale) case *asm.StoreFixedOffsetNumber: store(instr.Length, instr.Base, instr.Index, instr.Number, instr.Scale) case *asm.StoreNumber: store(instr.Length, instr.Base, instr.Index, instr.Number, instr.Scale) case *asm.Subtract: rrr("sub ", instr.Destination, instr.Source, instr.Operand) case *asm.SubtractNumber: rrn("sub ", instr.Destination, instr.Source, instr.Number) case *asm.StackFrameStart: mnemonic.Print(" frame start ")
if instr.FramePointer { other.Print("fp ") }
if instr.ExternCalls { other.Print("extern ") } case *asm.StackFrameEnd: mnemonic.Print(" frame end ")
if instr.FramePointer { other.Print("fp ") } case *asm.Syscall: mnemonic.Print(" syscall") case *asm.WriteSystemRegister: rr("move ", instr.SystemRegister, instr.Source) case *asm.Xor: rrr("xor ", instr.Destination, instr.Source, instr.Operand) case *asm.XorNumber: rrn("xor ", instr.Destination, instr.Source, instr.Number) default: ansi.Red.Print(" unknown: " + reflect.TypeOf(instr).String()) }
fmt.Println() }
fmt.Println()}