func (w *writer) BeginStack(start, end bitgen.Line) { if w.Offset != 0 { panic("BeginStack while in stack") } next := w.ReserveLine() w.Assign(start, w.Prev, w.Stack.Ptr, next) start = next next = w.ReserveLine() w.Copy(start, bitgen.Integer{bitgen.ValueAt{w.Alloc.Ptr}, 32}, w.Stack.Num, next) start = next next = w.ReserveLine() w.Copy(start, w.Stack.Num, w.Alloc.Num, next) start = next next = w.ReserveLine() w.Assign(start, w.Stack.Ptr, w.Alloc.Ptr, next) start = next w.Offset = uint(3) next = w.ReserveLine() w.Add(start, w.Alloc.Num, uint64(w.Offset*32/8), next, 0) start = next next = w.ReserveLine() w.Assign(start, w.Alloc.Ptr, bitgen.Offset{w.Alloc.Ptr, w.Offset * 32}, next) start = next next = w.ReserveLine() w.Copy(start, w.StackOffset(32/8), w.This.Num, next) start = next next = w.ReserveLine() w.Copy(start, w.StackOffset(32/8+32/8), w.Goto, next) start = next for i := 0; i < 32; i++ { next = w.ReserveLine() w.Assign(start, w.This.Num.Bit(uint(i)), bitgen.Bit(false), next) start = next next = w.ReserveLine() w.Assign(start, w.Goto.Bit(uint(i)), bitgen.Bit(false), next) start = next } w.Assign(start, w.This.Ptr, w.Heap, end) }
func (w *writer) gotoNext(start bitgen.Line, nextVal uint32, end bitgen.Line) { for i := uint(0); i < 32; i++ { var next bitgen.Line if i == 32-1 { next = w.JumpTableEntry } else { next = w.ReserveLine() } w.Assign(start, w.Next.Bit(i), bitgen.Bit((nextVal>>i)&1 == 1), next) start = next } if w.Jumps[nextVal] != 0 || end != 0 { w.Jump(w.Jumps[nextVal], bitgen.Bit(false), end, end) } }
func (w *writer) SaveRegisters(start, end bitgen.Line) { if w.Offset == 0 { panic("SaveRegisters while not in stack") } for i := range w.General { next := w.ReserveLine() w.Save[i], _ = w.StackAlloc(start, next) start = next next = w.ReserveLine() w.Copy(start, w.Save[i], w.General[i].Num, next) start = next for j := uint(0); j < 32; j++ { next = w.ReserveLine() w.Assign(start, w.General[i].Num.Bit(j), bitgen.Bit(false), next) start = next } if i == len(w.General)-1 { next = end } else { next = w.ReserveLine() } w.Assign(start, w.General[i].Ptr, w.Heap, next) start = next } }
func (e *NullExpr) write(w *writer, start, end bitgen.Line) { for i := uint(0); i < w.Return.Num.Width; i++ { next := w.ReserveLine() w.Assign(start, w.Return.Num.Bit(i), bitgen.Bit(false), next) start = next } w.Assign(start, w.Return.Ptr, w.Heap, end) }
func TestOptAlloc64(t *testing.T) { testOptRaw(t, func(w *bitgen.Writer) (n int64, err error) { type register struct { Ptr bitgen.Variable Num bitgen.Integer } reg := register{ Ptr: w.ReserveVariable(), Num: w.ReserveInteger(32), } alloc := register{ Ptr: w.ReserveVariable(), Num: w.ReserveInteger(32), } heapStart := bitgen.AddressOf{w.ReserveHeap()} var start bitgen.Line for _, r := range []register{reg, alloc} { for i := uint(0); i < r.Num.Width; i++ { next := w.ReserveLine() w.Assign(start, r.Num.Bit(i), bitgen.Bit(false), next) start = next } next := w.ReserveLine() w.Assign(start, r.Ptr, heapStart, next) start = next } next := w.ReserveLine() w.Increment(start, alloc.Num, next, 0) start = next next = w.ReserveLine() w.Assign(start, alloc.Ptr, bitgen.Offset{alloc.Ptr, 8}, next) start = next next = w.ReserveLine() w.Copy(start, reg.Num, alloc.Num, next) start = next next = w.ReserveLine() w.Assign(start, reg.Ptr, alloc.Ptr, next) start = next const size = 64 / 8 next = w.ReserveLine() w.Add(start, alloc.Num, size, next, 0) start = next w.Assign(start, alloc.Ptr, bitgen.Offset{alloc.Ptr, 8 * size}, 0) return }) }
func (e *MatchExpr) write(w *writer, start, end bitgen.Line) { next := w.ReserveLine() e.Left.write(w, start, next) start = next next = w.ReserveLine() w.Copy(start, e.slot, w.Return.Num, next) start = next null := w.CaseNull findNull: for _, c := range e.Cases { for _, h := range c.classes { if h == basicDummyNull { null = w.ReserveLine() break findNull } } } next = w.ReserveLine() w.Cmp(start, w.Return.Num, 0, null, next) start = next for _, c := range e.Cases { hasNull := false for _, h := range c.classes { if h == basicDummyNull { hasNull = true break } } target := null if !hasNull { target = w.ReserveLine() } for _, h := range c.classes { if !w.AST.usedTypes[h] { continue } next = w.ReserveLine() w.CmpReg(start, bitgen.Integer{bitgen.ValueAt{w.Return.Ptr}, 32}, w.Classes[h].Num, target, next) start = next } c.Body.write(w, target, end) } w.Jump(start, bitgen.Bit(false), w.NoCase, w.NoCase) }
func (w *writer) MethodTables(start, end bitgen.Line) { methods := func(start bitgen.Line, c *ClassDecl, end bitgen.Line) { cr := w.Classes[c].Ptr for i := uint(0); i < uint(len(c.methods)); i++ { for _, m := range c.methods { if m.offset != i { continue } jump := w.MethodStarts[m] for j := uint(32 - 1); j < 32; j-- { if (jump>>j)&1 == 0 { continue } var next bitgen.Line if i == uint(len(c.methods))-1 && jump&(1<<j-1) == 0 { next = end } else { next = w.ReserveLine() } w.Assign(start, bitgen.ValueAt{bitgen.Offset{cr, 32 + 32*i + j}}, bitgen.Bit(true), next) start = next } } } } var next bitgen.Line for _, c := range basicClasses { next = w.ReserveLine() methods(start, c, next) start = next } var usedClasses []*ClassDecl for _, c := range w.AST.Classes { if w.AST.usedTypes == nil || w.AST.usedTypes[c] { usedClasses = append(usedClasses, c) } } for i, c := range usedClasses { if i == len(usedClasses)-1 { next = end } else { next = w.ReserveLine() } methods(start, c, next) start = next } }
func (w *writer) StaticCall(start bitgen.Line, m *StaticCallExpr, end bitgen.Line) { w.EndStack() nextVal := w.StaticCalls[m] gotoVal := w.MethodStarts[m.Name.target.(*MethodFeature)] for i := uint(0); i < 32; i++ { next := w.ReserveLine() w.Assign(start, w.Goto.Bit(i), bitgen.Bit((gotoVal>>i)&1 == 1), next) start = next } w.gotoNext(start, nextVal, end) }
func (w *writer) NewInt(start bitgen.Line, reg register, value int32, end bitgen.Line) { next := w.ReserveLine() w.NewNative(start, reg, w.basicInt, 32/8, next) start = next for i := uint(0); i < 32; i++ { if i == 32-1 { next = end } else { next = w.ReserveLine() } w.Assign(start, bitgen.ValueAt{bitgen.Offset{reg.Ptr, 32 + i}}, bitgen.Bit((uint32(value)>>uint(i))&1 == 1), next) start = next } }
func TestOptZero32(t *testing.T) { testOptRaw(t, func(w *bitgen.Writer) (n int64, err error) { num := w.ReserveInteger(32) var start bitgen.Line for i := uint(0); i < num.Width; i++ { var next bitgen.Line if i != num.Width-1 { next = w.ReserveLine() } var nn int64 nn, err = w.Assign(start, num.Bit(i), bitgen.Bit(false), next) n += nn if err != nil { return } start = next } return }) }
func (w *writer) NewArrayAny(start bitgen.Line, end bitgen.Line) { w.EndStack() next := w.ReserveLine() w.Load(start, w.General[0], w.Stack, w.Arg(0), next) start = next // 1<<2 == 32/8 for i := uint(0); i <= 2; i++ { next = w.ReserveLine() w.Jump(start, bitgen.ValueAt{bitgen.Offset{w.General[0].Ptr, 32 + 32 - 1 - i}}, next, w.IndexRange) start = next } // multiply array size by 32/8 (elements -> bytes) next = w.ReserveLine() w.Copy(start, w.Return.Num.Sub(2, 32), w.IntValue(w.General[0].Ptr).Sub(0, 32-2), next) start = next // clear the bottom 2 bits for i := uint(0); i < 2; i++ { next = w.ReserveLine() w.Assign(start, w.Return.Num.Bit(i), bitgen.Bit(false), next) start = next } next = w.ReserveLine() w.NewNativeDynamic(start, w.Return, w.basicArrayAny, w.Return.Num, next) start = next next = w.ReserveLine() w.Copy(start, bitgen.Integer{bitgen.ValueAt{bitgen.Offset{w.Return.Ptr, basicArrayAnyLength.offset * 8}}, 32}, w.General[0].Num, next) start = next w.PopStack(start, end) }
func (w *writer) NewString(start bitgen.Line, reg, length register, value string, end bitgen.Line) { next := w.ReserveLine() w.NewInt(start, length, int32(len(value)), next) start = next next = w.ReserveLine() w.NewNative(start, reg, basicString, uint(len(value)), next) start = next for i := range value { for j := 0; j < 8; j++ { next = w.ReserveLine() w.Assign(start, bitgen.ValueAt{bitgen.Offset{reg.Ptr, basicStringLength.offset*8 + 32 + uint(i*8+j)}}, bitgen.Bit((value[i]>>uint(j))&1 == 1), next) start = next } } w.Copy(start, bitgen.Integer{bitgen.ValueAt{bitgen.Offset{reg.Ptr, basicStringLength.offset * 8}}, 32}, length.Num, end) }
func (w *writer) Init() (start bitgen.Line) { w.basicInt = basicInt w.basicString = basicString w.basicArrayAny = basicArrayAny w.basicClasses = basicClasses var registers []register reg := func(r *register) { r.Ptr = w.ReserveVariable() r.Num = w.ReserveInteger(32) registers = append(registers, *r) } w.Goto = w.ReserveInteger(32) w.Next = w.ReserveInteger(32) w.Ptr = w.ReserveInteger(32) reg(&w.Alloc) reg(&w.Unit) reg(&w.True) reg(&w.False) reg(&w.Zero) reg(&w.Symbol) reg(&w.Return) reg(&w.This) reg(&w.Stack) w.Prev = w.ReserveVariable() for i := range w.General { reg(&w.General[i]) } w.Classes = make(map[*ClassDecl]register) for _, c := range basicClasses { var r register reg(&r) w.Classes[c] = r } for _, c := range w.AST.Classes { if w.AST.usedTypes == nil || w.AST.usedTypes[c] { var r register reg(&r) w.Classes[c] = r } } w.Heap = bitgen.AddressOf{w.ReserveHeap()} for _, r := range registers { for i := uint(0); i < 32; i++ { next := w.ReserveLine() w.Assign(start, r.Num.Bit(i), bitgen.Bit(false), next) start = next } next := w.ReserveLine() w.Assign(start, r.Ptr, w.Heap, next) start = next } next := w.ReserveLine() w.Increment(start, w.Alloc.Num, next, 0) start = next next = w.ReserveLine() w.Assign(start, w.Alloc.Ptr, bitgen.Offset{w.Alloc.Ptr, 8}, next) start = next w.Panic = w.ReserveLine() w.Dump(w.Panic, 0) w.Null = w.Abort("runtime error: null pointer dereference\n") w.IndexRange = w.Abort("runtime error: index out of range\n") w.CaseNull = w.ReserveLine() w.PrintString(w.CaseNull, "runtime error: missing case for Null\n", 0) w.NoCase = w.ReserveLine() noCaseB := w.ReserveLine() w.PrintString(w.NoCase, "runtime error: missing case for ", noCaseB) noCaseA := noCaseB noCaseB = w.ReserveLine() w.Copy(noCaseA, w.StackOffset(w.Arg(0)), bitgen.Integer{bitgen.ValueAt{w.Return.Ptr}, 32}, noCaseB) noCaseA = noCaseB noCaseB = w.ReserveLine() w.PrintStringArg(noCaseA, 0, noCaseB) noCaseA = noCaseB w.Print(noCaseA, '\n', 0) w.DivZero = w.Abort("runtime error: division by zero\n") w.HeapRange = w.Abort("runtime error: pointer outside of heap\n") for _, c := range basicClasses { next = w.ReserveLine() w.ClassDecl(start, c, next) start = next } for _, c := range w.AST.Classes { if w.AST.usedTypes == nil || w.AST.usedTypes[c] { next = w.ReserveLine() w.ClassDecl(start, c, next) start = next } } for _, c := range basicClasses { next = w.ReserveLine() w.ClassDeclFixup(start, c, next) start = next } for _, c := range w.AST.Classes { if w.AST.usedTypes == nil || w.AST.usedTypes[c] { next = w.ReserveLine() w.ClassDeclFixup(start, c, next) start = next } } next = w.ReserveLine() w.NewNative(start, w.Unit, basicUnit, 0, next) start = next next = w.ReserveLine() w.NewNative(start, w.True, basicBoolean, 0, next) start = next next = w.ReserveLine() w.NewNative(start, w.False, basicBoolean, 0, next) start = next next = w.ReserveLine() w.NewInt(start, w.Zero, 0, next) start = next next = w.ReserveLine() w.CopyReg(start, w.General[0], w.General[2], next) start = next next = w.ReserveLine() w.CopyReg(start, w.General[1], w.General[2], next) start = next return }