func cgenFnCall(node *Node, ops *x64.OpcodeList) { // Check function fn, ok := node.sym.(*Function) if !ok { panic(fmt.Sprintf("Unknown symbol: %v, node: %v", node.sym, node)) } switch fn.fnName { default: ops.CALL(fn.Rva()) case printlnFuncName: cgenPrintCall(node, ops) } }
func cgenPrintCall(node *Node, ops *x64.OpcodeList) { // Get symbol fn, ok := node.sym.(*Function) if !ok { panic(fmt.Sprintf("Unknown symbol: %v", node.sym)) } // Push the base/frame pointer register value onto stack and overwrite base/frame pointer register to point to // the top of stack. This stack pointer can now be modified by us and restored at the end of the function to its // previous state // TODO: commented out as we must inline this call // ops.PUSH(x64.Rbp) // ops.MOV(x64.Rbp, x64.Rsp) // Push values onto stack (string RVA & length) str, ok := node.stats[0].sym.(*StringLiteralSymbol) if !ok { panic(fmt.Sprintf("print function parameter not string literal! - %v", str)) } ops.PUSHI(str.Rva()) ops.PUSHI(uint32(len(str.Val()))) // Call print ops.CALL(fn.Rva()) // Clean up stack by overwriting the stack pointer register with the base/frame pointer register. This discards // the two values we pushed onto the stack. Then pop the old base/frame pointer value off the stack & back into // the base/frame pointer register. This restores the caller's stack. // TODO: on x64 we should use 'leave' instruction // ops.MOV(x64.Rsp, x64.Rbp) // ops.POP(x64.Rbp) // ops.RET() }