// PopTo returns code to save data from the stack into the variable. // It also changes the stack size accordingly. func (s *Stack) PopTo(name string) x86.X86 { v := s.Lookup(name) off := SizeOnStack(v.Type()) if TypeToSize(v.Type()) != off { panic("I can't yet handle types with sizes that aren't a multiple of 4") } comment := "Popping to variable " + v.Name() if v.Name() == "_" { comment = fmt.Sprint("Popping to ", name, " of type ", PrettyType(v.Type()), " at ", v.InMemory()) } code := []x86.X86{x86.Comment(s.PrettyComments())} switch off { case 4: s.Size -= off vnew := s.Lookup(name) // Its location relative to stack may have changed! return x86.RawAssembly(x86.Assembly([]x86.X86{ x86.PopL(x86.EAX), x86.Commented(x86.MovL(x86.EAX, vnew.InMemory()), comment), })) case 8: s.Size -= 4 vnew := s.Lookup(name) // Its location relative to stack may have changed! code = append(code, x86.PopL(x86.EAX), x86.Commented(x86.MovL(x86.EAX, vnew.InMemory()), comment)) s.Size -= 4 vnew = s.Lookup(name) // Its location relative to stack may have changed again! code = append(code, x86.PopL(x86.EAX), x86.Commented(x86.MovL(x86.EAX, vnew.InMemory().Add(4)), comment)) return x86.RawAssembly(x86.Assembly(code)) default: panic(fmt.Sprintf("I don't pop variables with length %s", SizeOnStack(v.Type()))) } panic("This can't happen") }
func (v *CompileVisitor) Visit(n0 ast.Node) (w ast.Visitor) { // The following only handles functions (not methods) if n, ok := n0.(*ast.FuncDecl); ok && n.Recv == nil { v.FunctionPrologue(n) for _, statement := range n.Body.List { v.CompileStatement(statement) } v.FunctionPostlogue() v.Append(x86.GlobalSymbol("return_" + n.Name.Name)) v.Append(x86.Commented(x86.PopL(x86.EAX), "Pop the return address")) // Pop off function arguments... fmt.Println("Function", v.Stack.Name, "has stack size", v.Stack.Size) fmt.Println("Function", v.Stack.Name, "has return values size", v.Stack.ReturnSize) v.Append(x86.Commented(x86.AddL(x86.Imm32(v.Stack.Size-4-v.Stack.ReturnSize), x86.ESP), "Popping "+v.Stack.Name+" arguments.")) // Then we return! v.Append(x86.RawAssembly("\tjmp *%eax")) v.Stack = v.Stack.Parent return nil // No need to peek inside the func declaration! } return v }