Home | History | Annotate | Download | only in x86
      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 x86
      6 
      7 import (
      8 	"cmd/compile/internal/gc"
      9 	"cmd/internal/obj"
     10 	"cmd/internal/obj/x86"
     11 )
     12 
     13 /*
     14  * attempt to generate 64-bit
     15  *	res = n
     16  * return 1 on success, 0 if op not handled.
     17  */
     18 func cgen64(n *gc.Node, res *gc.Node) {
     19 	if res.Op != gc.OINDREG && res.Op != gc.ONAME {
     20 		gc.Dump("n", n)
     21 		gc.Dump("res", res)
     22 		gc.Fatal("cgen64 %v of %v", gc.Oconv(int(n.Op), 0), gc.Oconv(int(res.Op), 0))
     23 	}
     24 
     25 	switch n.Op {
     26 	default:
     27 		gc.Fatal("cgen64 %v", gc.Oconv(int(n.Op), 0))
     28 
     29 	case gc.OMINUS:
     30 		gc.Cgen(n.Left, res)
     31 		var hi1 gc.Node
     32 		var lo1 gc.Node
     33 		split64(res, &lo1, &hi1)
     34 		gins(x86.ANEGL, nil, &lo1)
     35 		gins(x86.AADCL, ncon(0), &hi1)
     36 		gins(x86.ANEGL, nil, &hi1)
     37 		splitclean()
     38 		return
     39 
     40 	case gc.OCOM:
     41 		gc.Cgen(n.Left, res)
     42 		var lo1 gc.Node
     43 		var hi1 gc.Node
     44 		split64(res, &lo1, &hi1)
     45 		gins(x86.ANOTL, nil, &lo1)
     46 		gins(x86.ANOTL, nil, &hi1)
     47 		splitclean()
     48 		return
     49 
     50 		// binary operators.
     51 	// common setup below.
     52 	case gc.OADD,
     53 		gc.OSUB,
     54 		gc.OMUL,
     55 		gc.OLROT,
     56 		gc.OLSH,
     57 		gc.ORSH,
     58 		gc.OAND,
     59 		gc.OOR,
     60 		gc.OXOR:
     61 		break
     62 	}
     63 
     64 	l := n.Left
     65 	r := n.Right
     66 	if !l.Addable {
     67 		var t1 gc.Node
     68 		gc.Tempname(&t1, l.Type)
     69 		gc.Cgen(l, &t1)
     70 		l = &t1
     71 	}
     72 
     73 	if r != nil && !r.Addable {
     74 		var t2 gc.Node
     75 		gc.Tempname(&t2, r.Type)
     76 		gc.Cgen(r, &t2)
     77 		r = &t2
     78 	}
     79 
     80 	var ax gc.Node
     81 	gc.Nodreg(&ax, gc.Types[gc.TINT32], x86.REG_AX)
     82 	var cx gc.Node
     83 	gc.Nodreg(&cx, gc.Types[gc.TINT32], x86.REG_CX)
     84 	var dx gc.Node
     85 	gc.Nodreg(&dx, gc.Types[gc.TINT32], x86.REG_DX)
     86 
     87 	// Setup for binary operation.
     88 	var hi1 gc.Node
     89 	var lo1 gc.Node
     90 	split64(l, &lo1, &hi1)
     91 
     92 	var lo2 gc.Node
     93 	var hi2 gc.Node
     94 	if gc.Is64(r.Type) {
     95 		split64(r, &lo2, &hi2)
     96 	}
     97 
     98 	// Do op.  Leave result in DX:AX.
     99 	switch n.Op {
    100 	// TODO: Constants
    101 	case gc.OADD:
    102 		gins(x86.AMOVL, &lo1, &ax)
    103 
    104 		gins(x86.AMOVL, &hi1, &dx)
    105 		gins(x86.AADDL, &lo2, &ax)
    106 		gins(x86.AADCL, &hi2, &dx)
    107 
    108 		// TODO: Constants.
    109 	case gc.OSUB:
    110 		gins(x86.AMOVL, &lo1, &ax)
    111 
    112 		gins(x86.AMOVL, &hi1, &dx)
    113 		gins(x86.ASUBL, &lo2, &ax)
    114 		gins(x86.ASBBL, &hi2, &dx)
    115 
    116 		// let's call the next two EX and FX.
    117 	case gc.OMUL:
    118 		var ex gc.Node
    119 		gc.Regalloc(&ex, gc.Types[gc.TPTR32], nil)
    120 
    121 		var fx gc.Node
    122 		gc.Regalloc(&fx, gc.Types[gc.TPTR32], nil)
    123 
    124 		// load args into DX:AX and EX:CX.
    125 		gins(x86.AMOVL, &lo1, &ax)
    126 
    127 		gins(x86.AMOVL, &hi1, &dx)
    128 		gins(x86.AMOVL, &lo2, &cx)
    129 		gins(x86.AMOVL, &hi2, &ex)
    130 
    131 		// if DX and EX are zero, use 32 x 32 -> 64 unsigned multiply.
    132 		gins(x86.AMOVL, &dx, &fx)
    133 
    134 		gins(x86.AORL, &ex, &fx)
    135 		p1 := gc.Gbranch(x86.AJNE, nil, 0)
    136 		gins(x86.AMULL, &cx, nil) // implicit &ax
    137 		p2 := gc.Gbranch(obj.AJMP, nil, 0)
    138 		gc.Patch(p1, gc.Pc)
    139 
    140 		// full 64x64 -> 64, from 32x32 -> 64.
    141 		gins(x86.AIMULL, &cx, &dx)
    142 
    143 		gins(x86.AMOVL, &ax, &fx)
    144 		gins(x86.AIMULL, &ex, &fx)
    145 		gins(x86.AADDL, &dx, &fx)
    146 		gins(x86.AMOVL, &cx, &dx)
    147 		gins(x86.AMULL, &dx, nil) // implicit &ax
    148 		gins(x86.AADDL, &fx, &dx)
    149 		gc.Patch(p2, gc.Pc)
    150 
    151 		gc.Regfree(&ex)
    152 		gc.Regfree(&fx)
    153 
    154 		// We only rotate by a constant c in [0,64).
    155 	// if c >= 32:
    156 	//	lo, hi = hi, lo
    157 	//	c -= 32
    158 	// if c == 0:
    159 	//	no-op
    160 	// else:
    161 	//	t = hi
    162 	//	shld hi:lo, c
    163 	//	shld lo:t, c
    164 	case gc.OLROT:
    165 		v := uint64(r.Int())
    166 
    167 		if v >= 32 {
    168 			// reverse during load to do the first 32 bits of rotate
    169 			v -= 32
    170 
    171 			gins(x86.AMOVL, &lo1, &dx)
    172 			gins(x86.AMOVL, &hi1, &ax)
    173 		} else {
    174 			gins(x86.AMOVL, &lo1, &ax)
    175 			gins(x86.AMOVL, &hi1, &dx)
    176 		}
    177 
    178 		if v == 0 {
    179 		} else // done
    180 		{
    181 			gins(x86.AMOVL, &dx, &cx)
    182 			p1 := gins(x86.ASHLL, ncon(uint32(v)), &dx)
    183 			p1.From.Index = x86.REG_AX // double-width shift
    184 			p1.From.Scale = 0
    185 			p1 = gins(x86.ASHLL, ncon(uint32(v)), &ax)
    186 			p1.From.Index = x86.REG_CX // double-width shift
    187 			p1.From.Scale = 0
    188 		}
    189 
    190 	case gc.OLSH:
    191 		if r.Op == gc.OLITERAL {
    192 			v := uint64(r.Int())
    193 			if v >= 64 {
    194 				if gc.Is64(r.Type) {
    195 					splitclean()
    196 				}
    197 				splitclean()
    198 				split64(res, &lo2, &hi2)
    199 				gins(x86.AMOVL, ncon(0), &lo2)
    200 				gins(x86.AMOVL, ncon(0), &hi2)
    201 				splitclean()
    202 				return
    203 			}
    204 
    205 			if v >= 32 {
    206 				if gc.Is64(r.Type) {
    207 					splitclean()
    208 				}
    209 				split64(res, &lo2, &hi2)
    210 				gmove(&lo1, &hi2)
    211 				if v > 32 {
    212 					gins(x86.ASHLL, ncon(uint32(v-32)), &hi2)
    213 				}
    214 
    215 				gins(x86.AMOVL, ncon(0), &lo2)
    216 				splitclean()
    217 				splitclean()
    218 				return
    219 			}
    220 
    221 			// general shift
    222 			gins(x86.AMOVL, &lo1, &ax)
    223 
    224 			gins(x86.AMOVL, &hi1, &dx)
    225 			p1 := gins(x86.ASHLL, ncon(uint32(v)), &dx)
    226 			p1.From.Index = x86.REG_AX // double-width shift
    227 			p1.From.Scale = 0
    228 			gins(x86.ASHLL, ncon(uint32(v)), &ax)
    229 			break
    230 		}
    231 
    232 		// load value into DX:AX.
    233 		gins(x86.AMOVL, &lo1, &ax)
    234 
    235 		gins(x86.AMOVL, &hi1, &dx)
    236 
    237 		// load shift value into register.
    238 		// if high bits are set, zero value.
    239 		var p1 *obj.Prog
    240 
    241 		if gc.Is64(r.Type) {
    242 			gins(x86.ACMPL, &hi2, ncon(0))
    243 			p1 = gc.Gbranch(x86.AJNE, nil, +1)
    244 			gins(x86.AMOVL, &lo2, &cx)
    245 		} else {
    246 			cx.Type = gc.Types[gc.TUINT32]
    247 			gmove(r, &cx)
    248 		}
    249 
    250 		// if shift count is >=64, zero value
    251 		gins(x86.ACMPL, &cx, ncon(64))
    252 
    253 		p2 := gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1)
    254 		if p1 != nil {
    255 			gc.Patch(p1, gc.Pc)
    256 		}
    257 		gins(x86.AXORL, &dx, &dx)
    258 		gins(x86.AXORL, &ax, &ax)
    259 		gc.Patch(p2, gc.Pc)
    260 
    261 		// if shift count is >= 32, zero low.
    262 		gins(x86.ACMPL, &cx, ncon(32))
    263 
    264 		p1 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1)
    265 		gins(x86.AMOVL, &ax, &dx)
    266 		gins(x86.ASHLL, &cx, &dx) // SHLL only uses bottom 5 bits of count
    267 		gins(x86.AXORL, &ax, &ax)
    268 		p2 = gc.Gbranch(obj.AJMP, nil, 0)
    269 		gc.Patch(p1, gc.Pc)
    270 
    271 		// general shift
    272 		p1 = gins(x86.ASHLL, &cx, &dx)
    273 
    274 		p1.From.Index = x86.REG_AX // double-width shift
    275 		p1.From.Scale = 0
    276 		gins(x86.ASHLL, &cx, &ax)
    277 		gc.Patch(p2, gc.Pc)
    278 
    279 	case gc.ORSH:
    280 		if r.Op == gc.OLITERAL {
    281 			v := uint64(r.Int())
    282 			if v >= 64 {
    283 				if gc.Is64(r.Type) {
    284 					splitclean()
    285 				}
    286 				splitclean()
    287 				split64(res, &lo2, &hi2)
    288 				if hi1.Type.Etype == gc.TINT32 {
    289 					gmove(&hi1, &lo2)
    290 					gins(x86.ASARL, ncon(31), &lo2)
    291 					gmove(&hi1, &hi2)
    292 					gins(x86.ASARL, ncon(31), &hi2)
    293 				} else {
    294 					gins(x86.AMOVL, ncon(0), &lo2)
    295 					gins(x86.AMOVL, ncon(0), &hi2)
    296 				}
    297 
    298 				splitclean()
    299 				return
    300 			}
    301 
    302 			if v >= 32 {
    303 				if gc.Is64(r.Type) {
    304 					splitclean()
    305 				}
    306 				split64(res, &lo2, &hi2)
    307 				gmove(&hi1, &lo2)
    308 				if v > 32 {
    309 					gins(optoas(gc.ORSH, hi1.Type), ncon(uint32(v-32)), &lo2)
    310 				}
    311 				if hi1.Type.Etype == gc.TINT32 {
    312 					gmove(&hi1, &hi2)
    313 					gins(x86.ASARL, ncon(31), &hi2)
    314 				} else {
    315 					gins(x86.AMOVL, ncon(0), &hi2)
    316 				}
    317 				splitclean()
    318 				splitclean()
    319 				return
    320 			}
    321 
    322 			// general shift
    323 			gins(x86.AMOVL, &lo1, &ax)
    324 
    325 			gins(x86.AMOVL, &hi1, &dx)
    326 			p1 := gins(x86.ASHRL, ncon(uint32(v)), &ax)
    327 			p1.From.Index = x86.REG_DX // double-width shift
    328 			p1.From.Scale = 0
    329 			gins(optoas(gc.ORSH, hi1.Type), ncon(uint32(v)), &dx)
    330 			break
    331 		}
    332 
    333 		// load value into DX:AX.
    334 		gins(x86.AMOVL, &lo1, &ax)
    335 
    336 		gins(x86.AMOVL, &hi1, &dx)
    337 
    338 		// load shift value into register.
    339 		// if high bits are set, zero value.
    340 		var p1 *obj.Prog
    341 
    342 		if gc.Is64(r.Type) {
    343 			gins(x86.ACMPL, &hi2, ncon(0))
    344 			p1 = gc.Gbranch(x86.AJNE, nil, +1)
    345 			gins(x86.AMOVL, &lo2, &cx)
    346 		} else {
    347 			cx.Type = gc.Types[gc.TUINT32]
    348 			gmove(r, &cx)
    349 		}
    350 
    351 		// if shift count is >=64, zero or sign-extend value
    352 		gins(x86.ACMPL, &cx, ncon(64))
    353 
    354 		p2 := gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1)
    355 		if p1 != nil {
    356 			gc.Patch(p1, gc.Pc)
    357 		}
    358 		if hi1.Type.Etype == gc.TINT32 {
    359 			gins(x86.ASARL, ncon(31), &dx)
    360 			gins(x86.AMOVL, &dx, &ax)
    361 		} else {
    362 			gins(x86.AXORL, &dx, &dx)
    363 			gins(x86.AXORL, &ax, &ax)
    364 		}
    365 
    366 		gc.Patch(p2, gc.Pc)
    367 
    368 		// if shift count is >= 32, sign-extend hi.
    369 		gins(x86.ACMPL, &cx, ncon(32))
    370 
    371 		p1 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1)
    372 		gins(x86.AMOVL, &dx, &ax)
    373 		if hi1.Type.Etype == gc.TINT32 {
    374 			gins(x86.ASARL, &cx, &ax) // SARL only uses bottom 5 bits of count
    375 			gins(x86.ASARL, ncon(31), &dx)
    376 		} else {
    377 			gins(x86.ASHRL, &cx, &ax)
    378 			gins(x86.AXORL, &dx, &dx)
    379 		}
    380 
    381 		p2 = gc.Gbranch(obj.AJMP, nil, 0)
    382 		gc.Patch(p1, gc.Pc)
    383 
    384 		// general shift
    385 		p1 = gins(x86.ASHRL, &cx, &ax)
    386 
    387 		p1.From.Index = x86.REG_DX // double-width shift
    388 		p1.From.Scale = 0
    389 		gins(optoas(gc.ORSH, hi1.Type), &cx, &dx)
    390 		gc.Patch(p2, gc.Pc)
    391 
    392 		// make constant the right side (it usually is anyway).
    393 	case gc.OXOR,
    394 		gc.OAND,
    395 		gc.OOR:
    396 		if lo1.Op == gc.OLITERAL {
    397 			nswap(&lo1, &lo2)
    398 			nswap(&hi1, &hi2)
    399 		}
    400 
    401 		if lo2.Op == gc.OLITERAL {
    402 			// special cases for constants.
    403 			lv := uint32(lo2.Int())
    404 			hv := uint32(hi2.Int())
    405 			splitclean() // right side
    406 			split64(res, &lo2, &hi2)
    407 			switch n.Op {
    408 			case gc.OXOR:
    409 				gmove(&lo1, &lo2)
    410 				gmove(&hi1, &hi2)
    411 				switch lv {
    412 				case 0:
    413 					break
    414 
    415 				case 0xffffffff:
    416 					gins(x86.ANOTL, nil, &lo2)
    417 
    418 				default:
    419 					gins(x86.AXORL, ncon(lv), &lo2)
    420 				}
    421 
    422 				switch hv {
    423 				case 0:
    424 					break
    425 
    426 				case 0xffffffff:
    427 					gins(x86.ANOTL, nil, &hi2)
    428 
    429 				default:
    430 					gins(x86.AXORL, ncon(hv), &hi2)
    431 				}
    432 
    433 			case gc.OAND:
    434 				switch lv {
    435 				case 0:
    436 					gins(x86.AMOVL, ncon(0), &lo2)
    437 
    438 				default:
    439 					gmove(&lo1, &lo2)
    440 					if lv != 0xffffffff {
    441 						gins(x86.AANDL, ncon(lv), &lo2)
    442 					}
    443 				}
    444 
    445 				switch hv {
    446 				case 0:
    447 					gins(x86.AMOVL, ncon(0), &hi2)
    448 
    449 				default:
    450 					gmove(&hi1, &hi2)
    451 					if hv != 0xffffffff {
    452 						gins(x86.AANDL, ncon(hv), &hi2)
    453 					}
    454 				}
    455 
    456 			case gc.OOR:
    457 				switch lv {
    458 				case 0:
    459 					gmove(&lo1, &lo2)
    460 
    461 				case 0xffffffff:
    462 					gins(x86.AMOVL, ncon(0xffffffff), &lo2)
    463 
    464 				default:
    465 					gmove(&lo1, &lo2)
    466 					gins(x86.AORL, ncon(lv), &lo2)
    467 				}
    468 
    469 				switch hv {
    470 				case 0:
    471 					gmove(&hi1, &hi2)
    472 
    473 				case 0xffffffff:
    474 					gins(x86.AMOVL, ncon(0xffffffff), &hi2)
    475 
    476 				default:
    477 					gmove(&hi1, &hi2)
    478 					gins(x86.AORL, ncon(hv), &hi2)
    479 				}
    480 			}
    481 
    482 			splitclean()
    483 			splitclean()
    484 			return
    485 		}
    486 
    487 		gins(x86.AMOVL, &lo1, &ax)
    488 		gins(x86.AMOVL, &hi1, &dx)
    489 		gins(optoas(int(n.Op), lo1.Type), &lo2, &ax)
    490 		gins(optoas(int(n.Op), lo1.Type), &hi2, &dx)
    491 	}
    492 
    493 	if gc.Is64(r.Type) {
    494 		splitclean()
    495 	}
    496 	splitclean()
    497 
    498 	split64(res, &lo1, &hi1)
    499 	gins(x86.AMOVL, &ax, &lo1)
    500 	gins(x86.AMOVL, &dx, &hi1)
    501 	splitclean()
    502 }
    503 
    504 /*
    505  * generate comparison of nl, nr, both 64-bit.
    506  * nl is memory; nr is constant or memory.
    507  */
    508 func cmp64(nl *gc.Node, nr *gc.Node, op int, likely int, to *obj.Prog) {
    509 	var lo1 gc.Node
    510 	var hi1 gc.Node
    511 	var lo2 gc.Node
    512 	var hi2 gc.Node
    513 	var rr gc.Node
    514 
    515 	split64(nl, &lo1, &hi1)
    516 	split64(nr, &lo2, &hi2)
    517 
    518 	// compare most significant word;
    519 	// if they differ, we're done.
    520 	t := hi1.Type
    521 
    522 	if nl.Op == gc.OLITERAL || nr.Op == gc.OLITERAL {
    523 		gins(x86.ACMPL, &hi1, &hi2)
    524 	} else {
    525 		gc.Regalloc(&rr, gc.Types[gc.TINT32], nil)
    526 		gins(x86.AMOVL, &hi1, &rr)
    527 		gins(x86.ACMPL, &rr, &hi2)
    528 		gc.Regfree(&rr)
    529 	}
    530 
    531 	var br *obj.Prog
    532 	switch op {
    533 	default:
    534 		gc.Fatal("cmp64 %v %v", gc.Oconv(int(op), 0), t)
    535 
    536 		// cmp hi
    537 	// jne L
    538 	// cmp lo
    539 	// jeq to
    540 	// L:
    541 	case gc.OEQ:
    542 		br = gc.Gbranch(x86.AJNE, nil, -likely)
    543 
    544 		// cmp hi
    545 	// jne to
    546 	// cmp lo
    547 	// jne to
    548 	case gc.ONE:
    549 		gc.Patch(gc.Gbranch(x86.AJNE, nil, likely), to)
    550 
    551 		// cmp hi
    552 	// jgt to
    553 	// jlt L
    554 	// cmp lo
    555 	// jge to (or jgt to)
    556 	// L:
    557 	case gc.OGE,
    558 		gc.OGT:
    559 		gc.Patch(gc.Gbranch(optoas(gc.OGT, t), nil, likely), to)
    560 
    561 		br = gc.Gbranch(optoas(gc.OLT, t), nil, -likely)
    562 
    563 		// cmp hi
    564 	// jlt to
    565 	// jgt L
    566 	// cmp lo
    567 	// jle to (or jlt to)
    568 	// L:
    569 	case gc.OLE,
    570 		gc.OLT:
    571 		gc.Patch(gc.Gbranch(optoas(gc.OLT, t), nil, likely), to)
    572 
    573 		br = gc.Gbranch(optoas(gc.OGT, t), nil, -likely)
    574 	}
    575 
    576 	// compare least significant word
    577 	t = lo1.Type
    578 
    579 	if nl.Op == gc.OLITERAL || nr.Op == gc.OLITERAL {
    580 		gins(x86.ACMPL, &lo1, &lo2)
    581 	} else {
    582 		gc.Regalloc(&rr, gc.Types[gc.TINT32], nil)
    583 		gins(x86.AMOVL, &lo1, &rr)
    584 		gins(x86.ACMPL, &rr, &lo2)
    585 		gc.Regfree(&rr)
    586 	}
    587 
    588 	// jump again
    589 	gc.Patch(gc.Gbranch(optoas(op, t), nil, likely), to)
    590 
    591 	// point first branch down here if appropriate
    592 	if br != nil {
    593 		gc.Patch(br, gc.Pc)
    594 	}
    595 
    596 	splitclean()
    597 	splitclean()
    598 }
    599