Home | History | Annotate | Download | only in gc
      1 // Copyright 2009 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 package gc
      6 
      7 import "cmd/internal/obj"
      8 
      9 func overlap_cplx(f *Node, t *Node) bool {
     10 	// check whether f and t could be overlapping stack references.
     11 	// not exact, because it's hard to check for the stack register
     12 	// in portable code.  close enough: worst case we will allocate
     13 	// an extra temporary and the registerizer will clean it up.
     14 	return f.Op == OINDREG && t.Op == OINDREG && f.Xoffset+f.Type.Width >= t.Xoffset && t.Xoffset+t.Type.Width >= f.Xoffset
     15 }
     16 
     17 func complexbool(op int, nl, nr, res *Node, wantTrue bool, likely int, to *obj.Prog) {
     18 	// make both sides addable in ullman order
     19 	if nr != nil {
     20 		if nl.Ullman > nr.Ullman && !nl.Addable {
     21 			nl = CgenTemp(nl)
     22 		}
     23 
     24 		if !nr.Addable {
     25 			nr = CgenTemp(nr)
     26 		}
     27 	}
     28 	if !nl.Addable {
     29 		nl = CgenTemp(nl)
     30 	}
     31 
     32 	// Break nl and nr into real and imaginary components.
     33 	var lreal, limag, rreal, rimag Node
     34 	subnode(&lreal, &limag, nl)
     35 	subnode(&rreal, &rimag, nr)
     36 
     37 	// build tree
     38 	// if branching:
     39 	// 	real(l) == real(r) && imag(l) == imag(r)
     40 	// if generating a value, use a branch-free version:
     41 	// 	real(l) == real(r) & imag(l) == imag(r)
     42 	realeq := Node{
     43 		Op:    OEQ,
     44 		Left:  &lreal,
     45 		Right: &rreal,
     46 		Type:  Types[TBOOL],
     47 	}
     48 	imageq := Node{
     49 		Op:    OEQ,
     50 		Left:  &limag,
     51 		Right: &rimag,
     52 		Type:  Types[TBOOL],
     53 	}
     54 	and := Node{
     55 		Op:    OANDAND,
     56 		Left:  &realeq,
     57 		Right: &imageq,
     58 		Type:  Types[TBOOL],
     59 	}
     60 
     61 	if res != nil {
     62 		// generating a value
     63 		and.Op = OAND
     64 		if op == ONE {
     65 			and.Op = OOR
     66 			realeq.Op = ONE
     67 			imageq.Op = ONE
     68 		}
     69 		Bvgen(&and, res, true)
     70 		return
     71 	}
     72 
     73 	// generating a branch
     74 	if op == ONE {
     75 		wantTrue = !wantTrue
     76 	}
     77 
     78 	Bgen(&and, wantTrue, likely, to)
     79 }
     80 
     81 // break addable nc-complex into nr-real and ni-imaginary
     82 func subnode(nr *Node, ni *Node, nc *Node) {
     83 	if !nc.Addable {
     84 		Fatal("subnode not addable")
     85 	}
     86 
     87 	tc := Simsimtype(nc.Type)
     88 	tc = cplxsubtype(tc)
     89 	t := Types[tc]
     90 
     91 	if nc.Op == OLITERAL {
     92 		nodfconst(nr, t, &nc.Val().U.(*Mpcplx).Real)
     93 		nodfconst(ni, t, &nc.Val().U.(*Mpcplx).Imag)
     94 		return
     95 	}
     96 
     97 	*nr = *nc
     98 	nr.Type = t
     99 
    100 	*ni = *nc
    101 	ni.Type = t
    102 	ni.Xoffset += t.Width
    103 }
    104 
    105 // generate code res = -nl
    106 func minus(nl *Node, res *Node) {
    107 	var ra Node
    108 	ra.Op = OMINUS
    109 	ra.Left = nl
    110 	ra.Type = nl.Type
    111 	Cgen(&ra, res)
    112 }
    113 
    114 // build and execute tree
    115 //	real(res) = -real(nl)
    116 //	imag(res) = -imag(nl)
    117 func complexminus(nl *Node, res *Node) {
    118 	var n1 Node
    119 	var n2 Node
    120 	var n5 Node
    121 	var n6 Node
    122 
    123 	subnode(&n1, &n2, nl)
    124 	subnode(&n5, &n6, res)
    125 
    126 	minus(&n1, &n5)
    127 	minus(&n2, &n6)
    128 }
    129 
    130 // build and execute tree
    131 //	real(res) = real(nl) op real(nr)
    132 //	imag(res) = imag(nl) op imag(nr)
    133 func complexadd(op int, nl *Node, nr *Node, res *Node) {
    134 	var n1 Node
    135 	var n2 Node
    136 	var n3 Node
    137 	var n4 Node
    138 	var n5 Node
    139 	var n6 Node
    140 
    141 	subnode(&n1, &n2, nl)
    142 	subnode(&n3, &n4, nr)
    143 	subnode(&n5, &n6, res)
    144 
    145 	var ra Node
    146 	ra.Op = uint8(op)
    147 	ra.Left = &n1
    148 	ra.Right = &n3
    149 	ra.Type = n1.Type
    150 	Cgen(&ra, &n5)
    151 
    152 	ra = Node{}
    153 	ra.Op = uint8(op)
    154 	ra.Left = &n2
    155 	ra.Right = &n4
    156 	ra.Type = n2.Type
    157 	Cgen(&ra, &n6)
    158 }
    159 
    160 // build and execute tree
    161 //	tmp       = real(nl)*real(nr) - imag(nl)*imag(nr)
    162 //	imag(res) = real(nl)*imag(nr) + imag(nl)*real(nr)
    163 //	real(res) = tmp
    164 func complexmul(nl *Node, nr *Node, res *Node) {
    165 	var n1 Node
    166 	var n2 Node
    167 	var n3 Node
    168 	var n4 Node
    169 	var n5 Node
    170 	var n6 Node
    171 	var tmp Node
    172 
    173 	subnode(&n1, &n2, nl)
    174 	subnode(&n3, &n4, nr)
    175 	subnode(&n5, &n6, res)
    176 	Tempname(&tmp, n5.Type)
    177 
    178 	// real part -> tmp
    179 	var rm1 Node
    180 
    181 	rm1.Op = OMUL
    182 	rm1.Left = &n1
    183 	rm1.Right = &n3
    184 	rm1.Type = n1.Type
    185 
    186 	var rm2 Node
    187 	rm2.Op = OMUL
    188 	rm2.Left = &n2
    189 	rm2.Right = &n4
    190 	rm2.Type = n2.Type
    191 
    192 	var ra Node
    193 	ra.Op = OSUB
    194 	ra.Left = &rm1
    195 	ra.Right = &rm2
    196 	ra.Type = rm1.Type
    197 	Cgen(&ra, &tmp)
    198 
    199 	// imag part
    200 	rm1 = Node{}
    201 
    202 	rm1.Op = OMUL
    203 	rm1.Left = &n1
    204 	rm1.Right = &n4
    205 	rm1.Type = n1.Type
    206 
    207 	rm2 = Node{}
    208 	rm2.Op = OMUL
    209 	rm2.Left = &n2
    210 	rm2.Right = &n3
    211 	rm2.Type = n2.Type
    212 
    213 	ra = Node{}
    214 	ra.Op = OADD
    215 	ra.Left = &rm1
    216 	ra.Right = &rm2
    217 	ra.Type = rm1.Type
    218 	Cgen(&ra, &n6)
    219 
    220 	// tmp ->real part
    221 	Cgen(&tmp, &n5)
    222 }
    223 
    224 func nodfconst(n *Node, t *Type, fval *Mpflt) {
    225 	*n = Node{}
    226 	n.Op = OLITERAL
    227 	n.Addable = true
    228 	ullmancalc(n)
    229 	n.SetVal(Val{fval})
    230 	n.Type = t
    231 
    232 	if !Isfloat[t.Etype] {
    233 		Fatal("nodfconst: bad type %v", t)
    234 	}
    235 }
    236 
    237 func Complexop(n *Node, res *Node) bool {
    238 	if n != nil && n.Type != nil {
    239 		if Iscomplex[n.Type.Etype] {
    240 			goto maybe
    241 		}
    242 	}
    243 
    244 	if res != nil && res.Type != nil {
    245 		if Iscomplex[res.Type.Etype] {
    246 			goto maybe
    247 		}
    248 	}
    249 
    250 	if n.Op == OREAL || n.Op == OIMAG {
    251 		//dump("\ncomplex-yes", n);
    252 		return true
    253 	}
    254 
    255 	//dump("\ncomplex-no", n);
    256 	return false
    257 
    258 maybe:
    259 	switch n.Op {
    260 	case OCONV, // implemented ops
    261 		OADD,
    262 		OSUB,
    263 		OMUL,
    264 		OMINUS,
    265 		OCOMPLEX,
    266 		OREAL,
    267 		OIMAG:
    268 		//dump("\ncomplex-yes", n);
    269 		return true
    270 
    271 	case ODOT,
    272 		ODOTPTR,
    273 		OINDEX,
    274 		OIND,
    275 		ONAME:
    276 		//dump("\ncomplex-yes", n);
    277 		return true
    278 	}
    279 
    280 	//dump("\ncomplex-no", n);
    281 	return false
    282 }
    283 
    284 func Complexmove(f *Node, t *Node) {
    285 	if Debug['g'] != 0 {
    286 		Dump("\ncomplexmove-f", f)
    287 		Dump("complexmove-t", t)
    288 	}
    289 
    290 	if !t.Addable {
    291 		Fatal("complexmove: to not addable")
    292 	}
    293 
    294 	ft := Simsimtype(f.Type)
    295 	tt := Simsimtype(t.Type)
    296 	switch uint32(ft)<<16 | uint32(tt) {
    297 	default:
    298 		Fatal("complexmove: unknown conversion: %v -> %v\n", f.Type, t.Type)
    299 
    300 		// complex to complex move/convert.
    301 	// make f addable.
    302 	// also use temporary if possible stack overlap.
    303 	case TCOMPLEX64<<16 | TCOMPLEX64,
    304 		TCOMPLEX64<<16 | TCOMPLEX128,
    305 		TCOMPLEX128<<16 | TCOMPLEX64,
    306 		TCOMPLEX128<<16 | TCOMPLEX128:
    307 		if !f.Addable || overlap_cplx(f, t) {
    308 			var tmp Node
    309 			Tempname(&tmp, f.Type)
    310 			Complexmove(f, &tmp)
    311 			f = &tmp
    312 		}
    313 
    314 		var n1 Node
    315 		var n2 Node
    316 		subnode(&n1, &n2, f)
    317 		var n4 Node
    318 		var n3 Node
    319 		subnode(&n3, &n4, t)
    320 
    321 		Cgen(&n1, &n3)
    322 		Cgen(&n2, &n4)
    323 	}
    324 }
    325 
    326 func Complexgen(n *Node, res *Node) {
    327 	if Debug['g'] != 0 {
    328 		Dump("\ncomplexgen-n", n)
    329 		Dump("complexgen-res", res)
    330 	}
    331 
    332 	for n.Op == OCONVNOP {
    333 		n = n.Left
    334 	}
    335 
    336 	// pick off float/complex opcodes
    337 	switch n.Op {
    338 	case OCOMPLEX:
    339 		if res.Addable {
    340 			var n1 Node
    341 			var n2 Node
    342 			subnode(&n1, &n2, res)
    343 			var tmp Node
    344 			Tempname(&tmp, n1.Type)
    345 			Cgen(n.Left, &tmp)
    346 			Cgen(n.Right, &n2)
    347 			Cgen(&tmp, &n1)
    348 			return
    349 		}
    350 
    351 	case OREAL, OIMAG:
    352 		nl := n.Left
    353 		if !nl.Addable {
    354 			var tmp Node
    355 			Tempname(&tmp, nl.Type)
    356 			Complexgen(nl, &tmp)
    357 			nl = &tmp
    358 		}
    359 
    360 		var n1 Node
    361 		var n2 Node
    362 		subnode(&n1, &n2, nl)
    363 		if n.Op == OREAL {
    364 			Cgen(&n1, res)
    365 			return
    366 		}
    367 
    368 		Cgen(&n2, res)
    369 		return
    370 	}
    371 
    372 	// perform conversion from n to res
    373 	tl := Simsimtype(res.Type)
    374 
    375 	tl = cplxsubtype(tl)
    376 	tr := Simsimtype(n.Type)
    377 	tr = cplxsubtype(tr)
    378 	if tl != tr {
    379 		if !n.Addable {
    380 			var n1 Node
    381 			Tempname(&n1, n.Type)
    382 			Complexmove(n, &n1)
    383 			n = &n1
    384 		}
    385 
    386 		Complexmove(n, res)
    387 		return
    388 	}
    389 
    390 	if !res.Addable {
    391 		var n1 Node
    392 		Igen(res, &n1, nil)
    393 		Cgen(n, &n1)
    394 		Regfree(&n1)
    395 		return
    396 	}
    397 
    398 	if n.Addable {
    399 		Complexmove(n, res)
    400 		return
    401 	}
    402 
    403 	switch n.Op {
    404 	default:
    405 		Dump("complexgen: unknown op", n)
    406 		Fatal("complexgen: unknown op %v", Oconv(int(n.Op), 0))
    407 
    408 	case ODOT,
    409 		ODOTPTR,
    410 		OINDEX,
    411 		OIND,
    412 		ONAME, // PHEAP or PPARAMREF var
    413 		OCALLFUNC,
    414 		OCALLMETH,
    415 		OCALLINTER:
    416 		var n1 Node
    417 		Igen(n, &n1, res)
    418 
    419 		Complexmove(&n1, res)
    420 		Regfree(&n1)
    421 		return
    422 
    423 	case OCONV,
    424 		OADD,
    425 		OSUB,
    426 		OMUL,
    427 		OMINUS,
    428 		OCOMPLEX,
    429 		OREAL,
    430 		OIMAG:
    431 		break
    432 	}
    433 
    434 	nl := n.Left
    435 	if nl == nil {
    436 		return
    437 	}
    438 	nr := n.Right
    439 
    440 	// make both sides addable in ullman order
    441 	var tnl Node
    442 	if nr != nil {
    443 		if nl.Ullman > nr.Ullman && !nl.Addable {
    444 			Tempname(&tnl, nl.Type)
    445 			Cgen(nl, &tnl)
    446 			nl = &tnl
    447 		}
    448 
    449 		if !nr.Addable {
    450 			var tnr Node
    451 			Tempname(&tnr, nr.Type)
    452 			Cgen(nr, &tnr)
    453 			nr = &tnr
    454 		}
    455 	}
    456 
    457 	if !nl.Addable {
    458 		Tempname(&tnl, nl.Type)
    459 		Cgen(nl, &tnl)
    460 		nl = &tnl
    461 	}
    462 
    463 	switch n.Op {
    464 	default:
    465 		Fatal("complexgen: unknown op %v", Oconv(int(n.Op), 0))
    466 
    467 	case OCONV:
    468 		Complexmove(nl, res)
    469 
    470 	case OMINUS:
    471 		complexminus(nl, res)
    472 
    473 	case OADD, OSUB:
    474 		complexadd(int(n.Op), nl, nr, res)
    475 
    476 	case OMUL:
    477 		complexmul(nl, nr, res)
    478 	}
    479 }
    480