/* * call to n has already been generated. * generate: * res = &return value from call. */ func cgen_aret(n *gc.Node, res *gc.Node) { t := n.Left.Type if gc.Isptr[t.Etype] { t = t.Type } var flist gc.Iter fp := gc.Structfirst(&flist, gc.Getoutarg(t)) if fp == nil { gc.Fatal("cgen_aret: nil") } var nod1 gc.Node nod1.Op = gc.OINDREG nod1.Val.U.Reg = x86.REG_SP nod1.Addable = 1 nod1.Xoffset = fp.Width nod1.Type = fp.Type if res.Op != gc.OREGISTER { var nod2 gc.Node regalloc(&nod2, gc.Types[gc.Tptr], res) gins(x86.ALEAL, &nod1, &nod2) gins(x86.AMOVL, &nod2, res) regfree(&nod2) } else { gins(x86.ALEAL, &nod1, res) } }
/* * call to n has already been generated. * generate: * res = &return value from call. */ func cgen_aret(n *gc.Node, res *gc.Node) { t := n.Left.Type if gc.Isptr[t.Etype] { t = t.Type } var flist gc.Iter fp := gc.Structfirst(&flist, gc.Getoutarg(t)) if fp == nil { gc.Fatal("cgen_aret: nil") } var nod1 gc.Node nod1.Op = gc.OINDREG nod1.Val.U.Reg = ppc64.REGSP nod1.Addable = 1 nod1.Xoffset = fp.Width + int64(gc.Widthptr) // +widthptr: saved lr at 0(SP) nod1.Type = fp.Type if res.Op != gc.OREGISTER { var nod2 gc.Node regalloc(&nod2, gc.Types[gc.Tptr], res) agen(&nod1, &nod2) gins(ppc64.AMOVD, &nod2, res) regfree(&nod2) } else { agen(&nod1, res) } }
/* * n is on stack, either local variable * or return value from function call. * return n's offset from SP. */ func stkof(n *gc.Node) int64 { switch n.Op { case gc.OINDREG: return n.Xoffset case gc.ODOT: t := n.Left.Type if gc.Isptr[t.Etype] { break } off := stkof(n.Left) if off == -1000 || off == 1000 { return off } return off + n.Xoffset case gc.OINDEX: t := n.Left.Type if !gc.Isfixedarray(t) { break } off := stkof(n.Left) if off == -1000 || off == 1000 { return off } if gc.Isconst(n.Right, gc.CTINT) { return off + t.Type.Width*gc.Mpgetfix(n.Right.Val.U.Xval) } return 1000 case gc.OCALLMETH, gc.OCALLINTER, gc.OCALLFUNC: t := n.Left.Type if gc.Isptr[t.Etype] { t = t.Type } var flist gc.Iter t = gc.Structfirst(&flist, gc.Getoutarg(t)) if t != nil { return t.Width + int64(gc.Widthptr) // +widthptr: correct for saved LR } } // botch - probably failing to recognize address // arithmetic on the above. eg INDEX and DOT return -1000 }
/* * call to n has already been generated. * generate: * res = return value from call. */ func cgen_callret(n *gc.Node, res *gc.Node) { t := n.Left.Type if t.Etype == gc.TPTR32 || t.Etype == gc.TPTR64 { t = t.Type } var flist gc.Iter fp := gc.Structfirst(&flist, gc.Getoutarg(t)) if fp == nil { gc.Fatal("cgen_callret: nil") } var nod gc.Node nod.Op = gc.OINDREG nod.Val.U.Reg = x86.REG_SP nod.Addable = 1 nod.Xoffset = fp.Width nod.Type = fp.Type gc.Cgen_as(res, &nod) }
/* * generate: * newreg = &n; * res = newreg * * on exit, a has been changed to be *newreg. * caller must regfree(a). * The generated code checks that the result is not *nil. */ func igen(n *gc.Node, a *gc.Node, res *gc.Node) { if gc.Debug['g'] != 0 { gc.Dump("\nigen-n", n) } switch n.Op { case gc.ONAME: if (n.Class&gc.PHEAP != 0) || n.Class == gc.PPARAMREF { break } *a = *n return // Increase the refcount of the register so that igen's caller // has to call regfree. case gc.OINDREG: if n.Val.U.Reg != ppc64.REGSP { reg[n.Val.U.Reg]++ } *a = *n return case gc.ODOT: igen(n.Left, a, res) a.Xoffset += n.Xoffset a.Type = n.Type fixlargeoffset(a) return case gc.ODOTPTR: cgenr(n.Left, a, res) gc.Cgen_checknil(a) a.Op = gc.OINDREG a.Xoffset += n.Xoffset a.Type = n.Type fixlargeoffset(a) return case gc.OCALLFUNC, gc.OCALLMETH, gc.OCALLINTER: switch n.Op { case gc.OCALLFUNC: cgen_call(n, 0) case gc.OCALLMETH: gc.Cgen_callmeth(n, 0) case gc.OCALLINTER: cgen_callinter(n, nil, 0) } var flist gc.Iter fp := gc.Structfirst(&flist, gc.Getoutarg(n.Left.Type)) *a = gc.Node{} a.Op = gc.OINDREG a.Val.U.Reg = ppc64.REGSP a.Addable = 1 a.Xoffset = fp.Width + int64(gc.Widthptr) // +widthptr: saved lr at 0(SP) a.Type = n.Type return // Index of fixed-size array by constant can // put the offset in the addressing. // Could do the same for slice except that we need // to use the real index for the bounds checking. case gc.OINDEX: if gc.Isfixedarray(n.Left.Type) || (gc.Isptr[n.Left.Type.Etype] && gc.Isfixedarray(n.Left.Left.Type)) { if gc.Isconst(n.Right, gc.CTINT) { // Compute &a. if !gc.Isptr[n.Left.Type.Etype] { igen(n.Left, a, res) } else { var n1 gc.Node igen(n.Left, &n1, res) gc.Cgen_checknil(&n1) regalloc(a, gc.Types[gc.Tptr], res) gmove(&n1, a) regfree(&n1) a.Op = gc.OINDREG } // Compute &a[i] as &a + i*width. a.Type = n.Type a.Xoffset += gc.Mpgetfix(n.Right.Val.U.Xval) * n.Type.Width fixlargeoffset(a) return } } } agenr(n, a, res) a.Op = gc.OINDREG a.Type = n.Type }
/* * generate: * newreg = &n; * res = newreg * * on exit, a has been changed to be *newreg. * caller must regfree(a). * The generated code checks that the result is not *nil. */ func igen(n *gc.Node, a *gc.Node, res *gc.Node) { if gc.Debug['g'] != 0 { gc.Dump("\nigen-n", n) } switch n.Op { case gc.ONAME: if (n.Class&gc.PHEAP != 0) || n.Class == gc.PPARAMREF { break } *a = *n return // Increase the refcount of the register so that igen's caller // has to call regfree. case gc.OINDREG: if n.Val.U.Reg != x86.REG_SP { reg[n.Val.U.Reg]++ } *a = *n return case gc.ODOT: igen(n.Left, a, res) a.Xoffset += n.Xoffset a.Type = n.Type return case gc.ODOTPTR: switch n.Left.Op { // igen-able nodes. case gc.ODOT, gc.ODOTPTR, gc.OCALLFUNC, gc.OCALLMETH, gc.OCALLINTER: var n1 gc.Node igen(n.Left, &n1, res) regalloc(a, gc.Types[gc.Tptr], &n1) gmove(&n1, a) regfree(&n1) default: regalloc(a, gc.Types[gc.Tptr], res) cgen(n.Left, a) } gc.Cgen_checknil(a) a.Op = gc.OINDREG a.Xoffset += n.Xoffset a.Type = n.Type return case gc.OCALLFUNC, gc.OCALLMETH, gc.OCALLINTER: switch n.Op { case gc.OCALLFUNC: cgen_call(n, 0) case gc.OCALLMETH: gc.Cgen_callmeth(n, 0) case gc.OCALLINTER: cgen_callinter(n, nil, 0) } var flist gc.Iter fp := gc.Structfirst(&flist, gc.Getoutarg(n.Left.Type)) *a = gc.Node{} a.Op = gc.OINDREG a.Val.U.Reg = x86.REG_SP a.Addable = 1 a.Xoffset = fp.Width a.Type = n.Type return // Index of fixed-size array by constant can // put the offset in the addressing. // Could do the same for slice except that we need // to use the real index for the bounds checking. case gc.OINDEX: if gc.Isfixedarray(n.Left.Type) || (gc.Isptr[n.Left.Type.Etype] && gc.Isfixedarray(n.Left.Left.Type)) { if gc.Isconst(n.Right, gc.CTINT) { // Compute &a. if !gc.Isptr[n.Left.Type.Etype] { igen(n.Left, a, res) } else { var n1 gc.Node igen(n.Left, &n1, res) gc.Cgen_checknil(&n1) regalloc(a, gc.Types[gc.Tptr], res) gmove(&n1, a) regfree(&n1) a.Op = gc.OINDREG } // Compute &a[i] as &a + i*width. a.Type = n.Type a.Xoffset += gc.Mpgetfix(n.Right.Val.U.Xval) * n.Type.Width return } } } // release register for now, to avoid // confusing tempname. if res != nil && res.Op == gc.OREGISTER { reg[res.Val.U.Reg]-- } var n1 gc.Node gc.Tempname(&n1, gc.Types[gc.Tptr]) agen(n, &n1) if res != nil && res.Op == gc.OREGISTER { reg[res.Val.U.Reg]++ } regalloc(a, gc.Types[gc.Tptr], res) gmove(&n1, a) a.Op = gc.OINDREG a.Type = n.Type }