/* * generate return. * n->left is assignments to return values. */ func cgen_ret(n *gc.Node) { if n != nil { gc.Genlist(n.List) // copy out args } if gc.Hasdefer != 0 { ginscall(gc.Deferreturn, 0) } gc.Genlist(gc.Curfn.Exit) p := gins(obj.ARET, nil, nil) if n != nil && n.Op == gc.ORETJMP { p.To.Type = obj.TYPE_MEM p.To.Name = obj.NAME_EXTERN p.To.Sym = gc.Linksym(n.Left.Sym) } }
/* * generate function call; * proc=0 normal call * proc=1 goroutine run in new proc * proc=2 defer call save away stack */ func cgen_call(n *gc.Node, proc int) { if n == nil { return } var afun gc.Node if n.Left.Ullman >= gc.UINF { // if name involves a fn call // precompute the address of the fn gc.Tempname(&afun, gc.Types[gc.Tptr]) cgen(n.Left, &afun) } gc.Genlist(n.List) // assign the args t := n.Left.Type // call tempname pointer if n.Left.Ullman >= gc.UINF { var nod gc.Node regalloc(&nod, gc.Types[gc.Tptr], nil) gc.Cgen_as(&nod, &afun) nod.Type = t ginscall(&nod, proc) regfree(&nod) return } // call pointer if n.Left.Op != gc.ONAME || n.Left.Class != gc.PFUNC { var nod gc.Node regalloc(&nod, gc.Types[gc.Tptr], nil) gc.Cgen_as(&nod, n.Left) nod.Type = t ginscall(&nod, proc) regfree(&nod) return } // call direct n.Left.Method = 1 ginscall(n.Left, proc) }
/* * generate: * if(n == true) goto to; */ func bgen(n *gc.Node, true_ bool, likely int, to *obj.Prog) { if gc.Debug['g'] != 0 { gc.Dump("\nbgen", n) } if n == nil { n = gc.Nodbool(true) } if n.Ninit != nil { gc.Genlist(n.Ninit) } if n.Type == nil { gc.Convlit(&n, gc.Types[gc.TBOOL]) if n.Type == nil { return } } et := int(n.Type.Etype) if et != gc.TBOOL { gc.Yyerror("cgen: bad type %v for %v", gc.Tconv(n.Type, 0), gc.Oconv(int(n.Op), 0)) gc.Patch(gins(obj.AEND, nil, nil), to) return } var nr *gc.Node for n.Op == gc.OCONVNOP { n = n.Left if n.Ninit != nil { gc.Genlist(n.Ninit) } } var nl *gc.Node switch n.Op { default: var n1 gc.Node regalloc(&n1, n.Type, nil) cgen(n, &n1) var n2 gc.Node gc.Nodconst(&n2, n.Type, 0) gins(optoas(gc.OCMP, n.Type), &n1, &n2) a := ppc64.ABNE if !true_ { a = ppc64.ABEQ } gc.Patch(gc.Gbranch(a, n.Type, likely), to) regfree(&n1) return // need to ask if it is bool? case gc.OLITERAL: if !true_ == (n.Val.U.Bval == 0) { gc.Patch(gc.Gbranch(ppc64.ABR, nil, likely), to) } return case gc.OANDAND, gc.OOROR: if (n.Op == gc.OANDAND) == true_ { p1 := gc.Gbranch(obj.AJMP, nil, 0) p2 := gc.Gbranch(obj.AJMP, nil, 0) gc.Patch(p1, gc.Pc) bgen(n.Left, !true_, -likely, p2) bgen(n.Right, !true_, -likely, p2) p1 = gc.Gbranch(obj.AJMP, nil, 0) gc.Patch(p1, to) gc.Patch(p2, gc.Pc) } else { bgen(n.Left, true_, likely, to) bgen(n.Right, true_, likely, to) } return case gc.OEQ, gc.ONE, gc.OLT, gc.OGT, gc.OLE, gc.OGE: nr = n.Right if nr == nil || nr.Type == nil { return } fallthrough case gc.ONOT: // unary nl = n.Left if nl == nil || nl.Type == nil { return } } switch n.Op { case gc.ONOT: bgen(nl, !true_, likely, to) return case gc.OEQ, gc.ONE, gc.OLT, gc.OGT, gc.OLE, gc.OGE: a := int(n.Op) if !true_ { if gc.Isfloat[nr.Type.Etype] { // brcom is not valid on floats when NaN is involved. p1 := gc.Gbranch(ppc64.ABR, nil, 0) p2 := gc.Gbranch(ppc64.ABR, nil, 0) gc.Patch(p1, gc.Pc) ll := n.Ninit // avoid re-genning ninit n.Ninit = nil bgen(n, true, -likely, p2) n.Ninit = ll gc.Patch(gc.Gbranch(ppc64.ABR, nil, 0), to) gc.Patch(p2, gc.Pc) return } a = gc.Brcom(a) true_ = !true_ } // make simplest on right if nl.Op == gc.OLITERAL || (nl.Ullman < nr.Ullman && nl.Ullman < gc.UINF) { a = gc.Brrev(a) r := nl nl = nr nr = r } if gc.Isslice(nl.Type) { // front end should only leave cmp to literal nil if (a != gc.OEQ && a != gc.ONE) || nr.Op != gc.OLITERAL { gc.Yyerror("illegal slice comparison") break } a = optoas(a, gc.Types[gc.Tptr]) var n1 gc.Node igen(nl, &n1, nil) n1.Xoffset += int64(gc.Array_array) n1.Type = gc.Types[gc.Tptr] var tmp gc.Node gc.Nodconst(&tmp, gc.Types[gc.Tptr], 0) var n2 gc.Node regalloc(&n2, gc.Types[gc.Tptr], &n1) gmove(&n1, &n2) gins(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n2, &tmp) regfree(&n2) gc.Patch(gc.Gbranch(a, gc.Types[gc.Tptr], likely), to) regfree(&n1) break } if gc.Isinter(nl.Type) { // front end should only leave cmp to literal nil if (a != gc.OEQ && a != gc.ONE) || nr.Op != gc.OLITERAL { gc.Yyerror("illegal interface comparison") break } a = optoas(a, gc.Types[gc.Tptr]) var n1 gc.Node igen(nl, &n1, nil) n1.Type = gc.Types[gc.Tptr] var tmp gc.Node gc.Nodconst(&tmp, gc.Types[gc.Tptr], 0) var n2 gc.Node regalloc(&n2, gc.Types[gc.Tptr], &n1) gmove(&n1, &n2) gins(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n2, &tmp) regfree(&n2) gc.Patch(gc.Gbranch(a, gc.Types[gc.Tptr], likely), to) regfree(&n1) break } if gc.Iscomplex[nl.Type.Etype] { gc.Complexbool(a, nl, nr, true_, likely, to) break } var n1 gc.Node var n2 gc.Node if nr.Ullman >= gc.UINF { regalloc(&n1, nl.Type, nil) cgen(nl, &n1) var tmp gc.Node gc.Tempname(&tmp, nl.Type) gmove(&n1, &tmp) regfree(&n1) regalloc(&n2, nr.Type, nil) cgen(nr, &n2) regalloc(&n1, nl.Type, nil) cgen(&tmp, &n1) goto cmp } regalloc(&n1, nl.Type, nil) cgen(nl, &n1) // TODO(minux): cmpi does accept 16-bit signed immediate as p->to. // and cmpli accepts 16-bit unsigned immediate. //if(smallintconst(nr)) { // gins(optoas(OCMP, nr->type), &n1, nr); // patch(gbranch(optoas(a, nr->type), nr->type, likely), to); // regfree(&n1); // break; //} regalloc(&n2, nr.Type, nil) cgen(nr, &n2) cmp: l := &n1 r := &n2 gins(optoas(gc.OCMP, nr.Type), l, r) if gc.Isfloat[nr.Type.Etype] && (a == gc.OLE || a == gc.OGE) { // To get NaN right, must rewrite x <= y into separate x < y or x = y. switch a { case gc.OLE: a = gc.OLT case gc.OGE: a = gc.OGT } gc.Patch(gc.Gbranch(optoas(a, nr.Type), nr.Type, likely), to) gc.Patch(gc.Gbranch(optoas(gc.OEQ, nr.Type), nr.Type, likely), to) } else { gc.Patch(gc.Gbranch(optoas(a, nr.Type), nr.Type, likely), to) } regfree(&n1) regfree(&n2) } return }
/* * n is call to interface method. * generate res = n. */ func cgen_callinter(n *gc.Node, res *gc.Node, proc int) { i := n.Left if i.Op != gc.ODOTINTER { gc.Fatal("cgen_callinter: not ODOTINTER %v", gc.Oconv(int(i.Op), 0)) } f := i.Right // field if f.Op != gc.ONAME { gc.Fatal("cgen_callinter: not ONAME %v", gc.Oconv(int(f.Op), 0)) } i = i.Left // interface if i.Addable == 0 { var tmpi gc.Node gc.Tempname(&tmpi, i.Type) cgen(i, &tmpi) i = &tmpi } gc.Genlist(n.List) // assign the args // i is now addable, prepare an indirected // register to hold its address. var nodi gc.Node igen(i, &nodi, res) // REG = &inter var nodsp gc.Node gc.Nodindreg(&nodsp, gc.Types[gc.Tptr], x86.REG_SP) nodsp.Xoffset = 0 if proc != 0 { nodsp.Xoffset += 2 * int64(gc.Widthptr) // leave room for size & fn } nodi.Type = gc.Types[gc.Tptr] nodi.Xoffset += int64(gc.Widthptr) cgen(&nodi, &nodsp) // {0 or 8}(SP) = 4(REG) -- i.data var nodo gc.Node regalloc(&nodo, gc.Types[gc.Tptr], res) nodi.Type = gc.Types[gc.Tptr] nodi.Xoffset -= int64(gc.Widthptr) cgen(&nodi, &nodo) // REG = 0(REG) -- i.tab regfree(&nodi) var nodr gc.Node regalloc(&nodr, gc.Types[gc.Tptr], &nodo) if n.Left.Xoffset == gc.BADWIDTH { gc.Fatal("cgen_callinter: badwidth") } gc.Cgen_checknil(&nodo) nodo.Op = gc.OINDREG nodo.Xoffset = n.Left.Xoffset + 3*int64(gc.Widthptr) + 8 if proc == 0 { // plain call: use direct c function pointer - more efficient cgen(&nodo, &nodr) // REG = 20+offset(REG) -- i.tab->fun[f] proc = 3 } else { // go/defer. generate go func value. gins(x86.ALEAL, &nodo, &nodr) // REG = &(20+offset(REG)) -- i.tab->fun[f] } nodr.Type = n.Left.Type ginscall(&nodr, proc) regfree(&nodr) regfree(&nodo) }
/* * n is call to interface method. * generate res = n. */ func cgen_callinter(n *gc.Node, res *gc.Node, proc int) { i := n.Left if i.Op != gc.ODOTINTER { gc.Fatal("cgen_callinter: not ODOTINTER %v", gc.Oconv(int(i.Op), 0)) } f := i.Right // field if f.Op != gc.ONAME { gc.Fatal("cgen_callinter: not ONAME %v", gc.Oconv(int(f.Op), 0)) } i = i.Left // interface // Release res register during genlist and cgen, // which might have their own function calls. r := -1 if res != nil && (res.Op == gc.OREGISTER || res.Op == gc.OINDREG) { r = int(res.Val.U.Reg) reg[r]-- } if i.Addable == 0 { var tmpi gc.Node gc.Tempname(&tmpi, i.Type) cgen(i, &tmpi) i = &tmpi } gc.Genlist(n.List) // args if r >= 0 { reg[r]++ } var nodr gc.Node regalloc(&nodr, gc.Types[gc.Tptr], res) var nodo gc.Node regalloc(&nodo, gc.Types[gc.Tptr], &nodr) nodo.Op = gc.OINDREG agen(i, &nodr) // REG = &inter var nodsp gc.Node gc.Nodindreg(&nodsp, gc.Types[gc.Tptr], arm.REGSP) nodsp.Xoffset = int64(gc.Widthptr) if proc != 0 { nodsp.Xoffset += 2 * int64(gc.Widthptr) // leave room for size & fn } nodo.Xoffset += int64(gc.Widthptr) cgen(&nodo, &nodsp) // {4 or 12}(SP) = 4(REG) -- i.data nodo.Xoffset -= int64(gc.Widthptr) cgen(&nodo, &nodr) // REG = 0(REG) -- i.tab gc.Cgen_checknil(&nodr) // in case offset is huge nodo.Xoffset = n.Left.Xoffset + 3*int64(gc.Widthptr) + 8 if proc == 0 { // plain call: use direct c function pointer - more efficient cgen(&nodo, &nodr) // REG = 20+offset(REG) -- i.tab->fun[f] nodr.Op = gc.OINDREG proc = 3 } else { // go/defer. generate go func value. p := gins(arm.AMOVW, &nodo, &nodr) p.From.Type = obj.TYPE_ADDR // REG = &(20+offset(REG)) -- i.tab->fun[f] } nodr.Type = n.Left.Type ginscall(&nodr, proc) regfree(&nodr) regfree(&nodo) }
/* * generate: * if(n == true) goto to; */ func bgen(n *gc.Node, true_ bool, likely int, to *obj.Prog) { if gc.Debug['g'] != 0 { gc.Dump("\nbgen", n) } if n == nil { n = gc.Nodbool(true) } if n.Ninit != nil { gc.Genlist(n.Ninit) } if n.Type == nil { gc.Convlit(&n, gc.Types[gc.TBOOL]) if n.Type == nil { return } } et := int(n.Type.Etype) if et != gc.TBOOL { gc.Yyerror("cgen: bad type %v for %v", gc.Tconv(n.Type, 0), gc.Oconv(int(n.Op), 0)) gc.Patch(gins(obj.AEND, nil, nil), to) return } for n.Op == gc.OCONVNOP { n = n.Left if n.Ninit != nil { gc.Genlist(n.Ninit) } } var nl *gc.Node var nr *gc.Node switch n.Op { default: goto def // need to ask if it is bool? case gc.OLITERAL: if !true_ == (n.Val.U.Bval == 0) { gc.Patch(gc.Gbranch(obj.AJMP, nil, likely), to) } return case gc.ONAME: if n.Addable == 0 { goto def } var n1 gc.Node gc.Nodconst(&n1, n.Type, 0) gins(optoas(gc.OCMP, n.Type), n, &n1) a := x86.AJNE if !true_ { a = x86.AJEQ } gc.Patch(gc.Gbranch(a, n.Type, likely), to) return case gc.OANDAND, gc.OOROR: if (n.Op == gc.OANDAND) == true_ { p1 := gc.Gbranch(obj.AJMP, nil, 0) p2 := gc.Gbranch(obj.AJMP, nil, 0) gc.Patch(p1, gc.Pc) bgen(n.Left, !true_, -likely, p2) bgen(n.Right, !true_, -likely, p2) p1 = gc.Gbranch(obj.AJMP, nil, 0) gc.Patch(p1, to) gc.Patch(p2, gc.Pc) } else { bgen(n.Left, true_, likely, to) bgen(n.Right, true_, likely, to) } return case gc.OEQ, gc.ONE, gc.OLT, gc.OGT, gc.OLE, gc.OGE: nr = n.Right if nr == nil || nr.Type == nil { return } fallthrough case gc.ONOT: // unary nl = n.Left if nl == nil || nl.Type == nil { return } } switch n.Op { case gc.ONOT: bgen(nl, !true_, likely, to) return case gc.OEQ, gc.ONE, gc.OLT, gc.OGT, gc.OLE, gc.OGE: a := int(n.Op) if !true_ { if gc.Isfloat[nr.Type.Etype] { // brcom is not valid on floats when NaN is involved. p1 := gc.Gbranch(obj.AJMP, nil, 0) p2 := gc.Gbranch(obj.AJMP, nil, 0) gc.Patch(p1, gc.Pc) ll := n.Ninit // avoid re-genning ninit n.Ninit = nil bgen(n, true, -likely, p2) n.Ninit = ll gc.Patch(gc.Gbranch(obj.AJMP, nil, 0), to) gc.Patch(p2, gc.Pc) return } a = gc.Brcom(a) true_ = !true_ } // make simplest on right if nl.Op == gc.OLITERAL || (nl.Ullman < nr.Ullman && nl.Ullman < gc.UINF) { a = gc.Brrev(a) r := nl nl = nr nr = r } if gc.Isslice(nl.Type) { // front end should only leave cmp to literal nil if (a != gc.OEQ && a != gc.ONE) || nr.Op != gc.OLITERAL { gc.Yyerror("illegal slice comparison") break } a = optoas(a, gc.Types[gc.Tptr]) var n1 gc.Node igen(nl, &n1, nil) n1.Xoffset += int64(gc.Array_array) n1.Type = gc.Types[gc.Tptr] var tmp gc.Node gc.Nodconst(&tmp, gc.Types[gc.Tptr], 0) gins(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n1, &tmp) gc.Patch(gc.Gbranch(a, gc.Types[gc.Tptr], likely), to) regfree(&n1) break } if gc.Isinter(nl.Type) { // front end should only leave cmp to literal nil if (a != gc.OEQ && a != gc.ONE) || nr.Op != gc.OLITERAL { gc.Yyerror("illegal interface comparison") break } a = optoas(a, gc.Types[gc.Tptr]) var n1 gc.Node igen(nl, &n1, nil) n1.Type = gc.Types[gc.Tptr] var tmp gc.Node gc.Nodconst(&tmp, gc.Types[gc.Tptr], 0) gins(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n1, &tmp) gc.Patch(gc.Gbranch(a, gc.Types[gc.Tptr], likely), to) regfree(&n1) break } if gc.Iscomplex[nl.Type.Etype] { gc.Complexbool(a, nl, nr, true_, likely, to) break } var n2 gc.Node var n1 gc.Node if nr.Ullman >= gc.UINF { regalloc(&n1, nl.Type, nil) cgen(nl, &n1) var tmp gc.Node gc.Tempname(&tmp, nl.Type) gmove(&n1, &tmp) regfree(&n1) regalloc(&n2, nr.Type, nil) cgen(nr, &n2) regalloc(&n1, nl.Type, nil) cgen(&tmp, &n1) goto cmp } regalloc(&n1, nl.Type, nil) cgen(nl, &n1) if gc.Smallintconst(nr) { gins(optoas(gc.OCMP, nr.Type), &n1, nr) gc.Patch(gc.Gbranch(optoas(a, nr.Type), nr.Type, likely), to) regfree(&n1) break } regalloc(&n2, nr.Type, nil) cgen(nr, &n2) // only < and <= work right with NaN; reverse if needed cmp: l := &n1 r := &n2 if gc.Isfloat[nl.Type.Etype] && (a == gc.OGT || a == gc.OGE) { l = &n2 r = &n1 a = gc.Brrev(a) } gins(optoas(gc.OCMP, nr.Type), l, r) if gc.Isfloat[nr.Type.Etype] && (n.Op == gc.OEQ || n.Op == gc.ONE) { if n.Op == gc.OEQ { // neither NE nor P p1 := gc.Gbranch(x86.AJNE, nil, -likely) p2 := gc.Gbranch(x86.AJPS, nil, -likely) gc.Patch(gc.Gbranch(obj.AJMP, nil, 0), to) gc.Patch(p1, gc.Pc) gc.Patch(p2, gc.Pc) } else { // either NE or P gc.Patch(gc.Gbranch(x86.AJNE, nil, likely), to) gc.Patch(gc.Gbranch(x86.AJPS, nil, likely), to) } } else { gc.Patch(gc.Gbranch(optoas(a, nr.Type), nr.Type, likely), to) } regfree(&n1) regfree(&n2) } return def: var n1 gc.Node regalloc(&n1, n.Type, nil) cgen(n, &n1) var n2 gc.Node gc.Nodconst(&n2, n.Type, 0) gins(optoas(gc.OCMP, n.Type), &n1, &n2) a := x86.AJNE if !true_ { a = x86.AJEQ } gc.Patch(gc.Gbranch(a, n.Type, likely), to) regfree(&n1) return }
/* * generate: * if(n == true) goto to; */ func bgen(n *gc.Node, true_ bool, likely int, to *obj.Prog) { if gc.Debug['g'] != 0 { gc.Dump("\nbgen", n) } if n == nil { n = gc.Nodbool(true) } if n.Ninit != nil { gc.Genlist(n.Ninit) } if n.Type == nil { gc.Convlit(&n, gc.Types[gc.TBOOL]) if n.Type == nil { return } } et := int(n.Type.Etype) if et != gc.TBOOL { gc.Yyerror("cgen: bad type %v for %v", gc.Tconv(n.Type, 0), gc.Oconv(int(n.Op), 0)) gc.Patch(gins(obj.AEND, nil, nil), to) return } var nr *gc.Node var nl *gc.Node switch n.Op { default: a := gc.ONE if !true_ { a = gc.OEQ } gencmp0(n, n.Type, a, likely, to) return // need to ask if it is bool? case gc.OLITERAL: if !true_ == (n.Val.U.Bval == 0) { gc.Patch(gc.Gbranch(arm.AB, nil, 0), to) } return case gc.OANDAND, gc.OOROR: if (n.Op == gc.OANDAND) == true_ { p1 := gc.Gbranch(obj.AJMP, nil, 0) p2 := gc.Gbranch(obj.AJMP, nil, 0) gc.Patch(p1, gc.Pc) bgen(n.Left, !true_, -likely, p2) bgen(n.Right, !true_, -likely, p2) p1 = gc.Gbranch(obj.AJMP, nil, 0) gc.Patch(p1, to) gc.Patch(p2, gc.Pc) } else { bgen(n.Left, true_, likely, to) bgen(n.Right, true_, likely, to) } return case gc.OEQ, gc.ONE, gc.OLT, gc.OGT, gc.OLE, gc.OGE: nr = n.Right if nr == nil || nr.Type == nil { return } fallthrough case gc.ONOT: // unary nl = n.Left if nl == nil || nl.Type == nil { return } } switch n.Op { case gc.ONOT: bgen(nl, !true_, likely, to) return case gc.OEQ, gc.ONE, gc.OLT, gc.OGT, gc.OLE, gc.OGE: a := int(n.Op) if !true_ { if gc.Isfloat[nl.Type.Etype] { // brcom is not valid on floats when NaN is involved. p1 := gc.Gbranch(arm.AB, nil, 0) p2 := gc.Gbranch(arm.AB, nil, 0) gc.Patch(p1, gc.Pc) ll := n.Ninit n.Ninit = nil bgen(n, true, -likely, p2) n.Ninit = ll gc.Patch(gc.Gbranch(arm.AB, nil, 0), to) gc.Patch(p2, gc.Pc) return } a = gc.Brcom(a) true_ = !true_ } // make simplest on right if nl.Op == gc.OLITERAL || (nl.Ullman < gc.UINF && nl.Ullman < nr.Ullman) { a = gc.Brrev(a) r := nl nl = nr nr = r } if gc.Isslice(nl.Type) { // only valid to cmp darray to literal nil if (a != gc.OEQ && a != gc.ONE) || nr.Op != gc.OLITERAL { gc.Yyerror("illegal array comparison") break } var n1 gc.Node igen(nl, &n1, nil) n1.Xoffset += int64(gc.Array_array) n1.Type = gc.Types[gc.Tptr] gencmp0(&n1, gc.Types[gc.Tptr], a, likely, to) regfree(&n1) break } if gc.Isinter(nl.Type) { // front end shold only leave cmp to literal nil if (a != gc.OEQ && a != gc.ONE) || nr.Op != gc.OLITERAL { gc.Yyerror("illegal interface comparison") break } var n1 gc.Node igen(nl, &n1, nil) n1.Type = gc.Types[gc.Tptr] n1.Xoffset += 0 gencmp0(&n1, gc.Types[gc.Tptr], a, likely, to) regfree(&n1) break } if gc.Iscomplex[nl.Type.Etype] { gc.Complexbool(a, nl, nr, true_, likely, to) break } if gc.Is64(nr.Type) { if nl.Addable == 0 { var n1 gc.Node gc.Tempname(&n1, nl.Type) cgen(nl, &n1) nl = &n1 } if nr.Addable == 0 { var n2 gc.Node gc.Tempname(&n2, nr.Type) cgen(nr, &n2) nr = &n2 } cmp64(nl, nr, a, likely, to) break } if nr.Op == gc.OLITERAL { if gc.Isconst(nr, gc.CTINT) && gc.Mpgetfix(nr.Val.U.Xval) == 0 { gencmp0(nl, nl.Type, a, likely, to) break } if nr.Val.Ctype == gc.CTNIL { gencmp0(nl, nl.Type, a, likely, to) break } } a = optoas(a, nr.Type) if nr.Ullman >= gc.UINF { var n1 gc.Node regalloc(&n1, nl.Type, nil) cgen(nl, &n1) var tmp gc.Node gc.Tempname(&tmp, nl.Type) gmove(&n1, &tmp) regfree(&n1) var n2 gc.Node regalloc(&n2, nr.Type, nil) cgen(nr, &n2) regalloc(&n1, nl.Type, nil) cgen(&tmp, &n1) gcmp(optoas(gc.OCMP, nr.Type), &n1, &n2) gc.Patch(gc.Gbranch(a, nr.Type, likely), to) regfree(&n1) regfree(&n2) break } var n3 gc.Node gc.Tempname(&n3, nl.Type) cgen(nl, &n3) var tmp gc.Node gc.Tempname(&tmp, nr.Type) cgen(nr, &tmp) var n1 gc.Node regalloc(&n1, nl.Type, nil) gmove(&n3, &n1) var n2 gc.Node regalloc(&n2, nr.Type, nil) gmove(&tmp, &n2) gcmp(optoas(gc.OCMP, nr.Type), &n1, &n2) if gc.Isfloat[nl.Type.Etype] { if n.Op == gc.ONE { p1 := gc.Gbranch(arm.ABVS, nr.Type, likely) gc.Patch(gc.Gbranch(a, nr.Type, likely), to) gc.Patch(p1, to) } else { p1 := gc.Gbranch(arm.ABVS, nr.Type, -likely) gc.Patch(gc.Gbranch(a, nr.Type, likely), to) gc.Patch(p1, gc.Pc) } } else { gc.Patch(gc.Gbranch(a, nr.Type, likely), to) } regfree(&n1) regfree(&n2) } return }
/* * branch gen * if(n == true) goto to; */ func bgen(n *gc.Node, true_ bool, likely int, to *obj.Prog) { if gc.Debug['g'] != 0 { gc.Dump("\nbgen", n) } if n == nil { n = gc.Nodbool(true) } if n.Ninit != nil { gc.Genlist(n.Ninit) } if n.Type == nil { gc.Convlit(&n, gc.Types[gc.TBOOL]) if n.Type == nil { return } } et := int(n.Type.Etype) if et != gc.TBOOL { gc.Yyerror("cgen: bad type %v for %v", gc.Tconv(n.Type, 0), gc.Oconv(int(n.Op), 0)) gc.Patch(gins(obj.AEND, nil, nil), to) return } for n.Op == gc.OCONVNOP { n = n.Left if n.Ninit != nil { gc.Genlist(n.Ninit) } } nl := n.Left var nr *gc.Node if nl != nil && gc.Isfloat[nl.Type.Etype] { bgen_float(n, bool2int(true_), likely, to) return } switch n.Op { default: goto def // need to ask if it is bool? case gc.OLITERAL: if !true_ == (n.Val.U.Bval == 0) { gc.Patch(gc.Gbranch(obj.AJMP, nil, 0), to) } return case gc.ONAME: if n.Addable == 0 { goto def } var n1 gc.Node gc.Nodconst(&n1, n.Type, 0) gins(optoas(gc.OCMP, n.Type), n, &n1) a := x86.AJNE if !true_ { a = x86.AJEQ } gc.Patch(gc.Gbranch(a, n.Type, likely), to) return case gc.OANDAND, gc.OOROR: if (n.Op == gc.OANDAND) == true_ { p1 := gc.Gbranch(obj.AJMP, nil, 0) p2 := gc.Gbranch(obj.AJMP, nil, 0) gc.Patch(p1, gc.Pc) bgen(n.Left, !true_, -likely, p2) bgen(n.Right, !true_, -likely, p2) p1 = gc.Gbranch(obj.AJMP, nil, 0) gc.Patch(p1, to) gc.Patch(p2, gc.Pc) } else { bgen(n.Left, true_, likely, to) bgen(n.Right, true_, likely, to) } return case gc.OEQ, gc.ONE, gc.OLT, gc.OGT, gc.OLE, gc.OGE: nr = n.Right if nr == nil || nr.Type == nil { return } fallthrough case gc.ONOT: // unary nl = n.Left if nl == nil || nl.Type == nil { return } } switch n.Op { case gc.ONOT: bgen(nl, !true_, likely, to) case gc.OEQ, gc.ONE, gc.OLT, gc.OGT, gc.OLE, gc.OGE: a := int(n.Op) if !true_ { a = gc.Brcom(a) true_ = !true_ } // make simplest on right if nl.Op == gc.OLITERAL || (nl.Ullman < nr.Ullman && nl.Ullman < gc.UINF) { a = gc.Brrev(a) r := nl nl = nr nr = r } if gc.Isslice(nl.Type) { // front end should only leave cmp to literal nil if (a != gc.OEQ && a != gc.ONE) || nr.Op != gc.OLITERAL { gc.Yyerror("illegal slice comparison") break } a = optoas(a, gc.Types[gc.Tptr]) var n1 gc.Node igen(nl, &n1, nil) n1.Xoffset += int64(gc.Array_array) n1.Type = gc.Types[gc.Tptr] var tmp gc.Node gc.Nodconst(&tmp, gc.Types[gc.Tptr], 0) gins(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n1, &tmp) gc.Patch(gc.Gbranch(a, gc.Types[gc.Tptr], likely), to) regfree(&n1) break } if gc.Isinter(nl.Type) { // front end should only leave cmp to literal nil if (a != gc.OEQ && a != gc.ONE) || nr.Op != gc.OLITERAL { gc.Yyerror("illegal interface comparison") break } a = optoas(a, gc.Types[gc.Tptr]) var n1 gc.Node igen(nl, &n1, nil) n1.Type = gc.Types[gc.Tptr] var tmp gc.Node gc.Nodconst(&tmp, gc.Types[gc.Tptr], 0) gins(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n1, &tmp) gc.Patch(gc.Gbranch(a, gc.Types[gc.Tptr], likely), to) regfree(&n1) break } if gc.Iscomplex[nl.Type.Etype] { gc.Complexbool(a, nl, nr, true_, likely, to) break } if gc.Is64(nr.Type) { if nl.Addable == 0 || gc.Isconst(nl, gc.CTINT) { var n1 gc.Node gc.Tempname(&n1, nl.Type) cgen(nl, &n1) nl = &n1 } if nr.Addable == 0 { var n2 gc.Node gc.Tempname(&n2, nr.Type) cgen(nr, &n2) nr = &n2 } cmp64(nl, nr, a, likely, to) break } var n2 gc.Node if nr.Ullman >= gc.UINF { if nl.Addable == 0 { var n1 gc.Node gc.Tempname(&n1, nl.Type) cgen(nl, &n1) nl = &n1 } if nr.Addable == 0 { var tmp gc.Node gc.Tempname(&tmp, nr.Type) cgen(nr, &tmp) nr = &tmp } var n2 gc.Node regalloc(&n2, nr.Type, nil) cgen(nr, &n2) nr = &n2 goto cmp } if nl.Addable == 0 { var n1 gc.Node gc.Tempname(&n1, nl.Type) cgen(nl, &n1) nl = &n1 } if gc.Smallintconst(nr) { gins(optoas(gc.OCMP, nr.Type), nl, nr) gc.Patch(gc.Gbranch(optoas(a, nr.Type), nr.Type, likely), to) break } if nr.Addable == 0 { var tmp gc.Node gc.Tempname(&tmp, nr.Type) cgen(nr, &tmp) nr = &tmp } regalloc(&n2, nr.Type, nil) gmove(nr, &n2) nr = &n2 cmp: gins(optoas(gc.OCMP, nr.Type), nl, nr) gc.Patch(gc.Gbranch(optoas(a, nr.Type), nr.Type, likely), to) if nl.Op == gc.OREGISTER { regfree(nl) } regfree(nr) } return def: var n1 gc.Node regalloc(&n1, n.Type, nil) cgen(n, &n1) var n2 gc.Node gc.Nodconst(&n2, n.Type, 0) gins(optoas(gc.OCMP, n.Type), &n1, &n2) a := x86.AJNE if !true_ { a = x86.AJEQ } gc.Patch(gc.Gbranch(a, n.Type, likely), to) regfree(&n1) return }