Home | History | Annotate | Download | only in arm
      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 arm
      6 
      7 import (
      8 	"cmd/compile/internal/gc"
      9 	"cmd/internal/obj"
     10 	"cmd/internal/obj/arm"
     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 	l := n.Left
     26 	var t1 gc.Node
     27 	if !l.Addable {
     28 		gc.Tempname(&t1, l.Type)
     29 		gc.Cgen(l, &t1)
     30 		l = &t1
     31 	}
     32 
     33 	var hi1 gc.Node
     34 	var lo1 gc.Node
     35 	split64(l, &lo1, &hi1)
     36 	switch n.Op {
     37 	default:
     38 		gc.Fatal("cgen64 %v", gc.Oconv(int(n.Op), 0))
     39 
     40 	case gc.OMINUS:
     41 		var lo2 gc.Node
     42 		var hi2 gc.Node
     43 		split64(res, &lo2, &hi2)
     44 
     45 		gc.Regalloc(&t1, lo1.Type, nil)
     46 		var al gc.Node
     47 		gc.Regalloc(&al, lo1.Type, nil)
     48 		var ah gc.Node
     49 		gc.Regalloc(&ah, hi1.Type, nil)
     50 
     51 		gins(arm.AMOVW, &lo1, &al)
     52 		gins(arm.AMOVW, &hi1, &ah)
     53 
     54 		gmove(ncon(0), &t1)
     55 		p1 := gins(arm.ASUB, &al, &t1)
     56 		p1.Scond |= arm.C_SBIT
     57 		gins(arm.AMOVW, &t1, &lo2)
     58 
     59 		gmove(ncon(0), &t1)
     60 		gins(arm.ASBC, &ah, &t1)
     61 		gins(arm.AMOVW, &t1, &hi2)
     62 
     63 		gc.Regfree(&t1)
     64 		gc.Regfree(&al)
     65 		gc.Regfree(&ah)
     66 		splitclean()
     67 		splitclean()
     68 		return
     69 
     70 	case gc.OCOM:
     71 		gc.Regalloc(&t1, lo1.Type, nil)
     72 		gmove(ncon(^uint32(0)), &t1)
     73 
     74 		var lo2 gc.Node
     75 		var hi2 gc.Node
     76 		split64(res, &lo2, &hi2)
     77 		var n1 gc.Node
     78 		gc.Regalloc(&n1, lo1.Type, nil)
     79 
     80 		gins(arm.AMOVW, &lo1, &n1)
     81 		gins(arm.AEOR, &t1, &n1)
     82 		gins(arm.AMOVW, &n1, &lo2)
     83 
     84 		gins(arm.AMOVW, &hi1, &n1)
     85 		gins(arm.AEOR, &t1, &n1)
     86 		gins(arm.AMOVW, &n1, &hi2)
     87 
     88 		gc.Regfree(&t1)
     89 		gc.Regfree(&n1)
     90 		splitclean()
     91 		splitclean()
     92 		return
     93 
     94 		// binary operators.
     95 	// common setup below.
     96 	case gc.OADD,
     97 		gc.OSUB,
     98 		gc.OMUL,
     99 		gc.OLSH,
    100 		gc.ORSH,
    101 		gc.OAND,
    102 		gc.OOR,
    103 		gc.OXOR,
    104 		gc.OLROT:
    105 		break
    106 	}
    107 
    108 	// setup for binary operators
    109 	r := n.Right
    110 
    111 	if r != nil && !r.Addable {
    112 		var t2 gc.Node
    113 		gc.Tempname(&t2, r.Type)
    114 		gc.Cgen(r, &t2)
    115 		r = &t2
    116 	}
    117 
    118 	var hi2 gc.Node
    119 	var lo2 gc.Node
    120 	if gc.Is64(r.Type) {
    121 		split64(r, &lo2, &hi2)
    122 	}
    123 
    124 	var al gc.Node
    125 	gc.Regalloc(&al, lo1.Type, nil)
    126 	var ah gc.Node
    127 	gc.Regalloc(&ah, hi1.Type, nil)
    128 
    129 	// Do op.  Leave result in ah:al.
    130 	switch n.Op {
    131 	default:
    132 		gc.Fatal("cgen64: not implemented: %v\n", n)
    133 
    134 		// TODO: Constants
    135 	case gc.OADD:
    136 		var bl gc.Node
    137 		gc.Regalloc(&bl, gc.Types[gc.TPTR32], nil)
    138 
    139 		var bh gc.Node
    140 		gc.Regalloc(&bh, gc.Types[gc.TPTR32], nil)
    141 		gins(arm.AMOVW, &hi1, &ah)
    142 		gins(arm.AMOVW, &lo1, &al)
    143 		gins(arm.AMOVW, &hi2, &bh)
    144 		gins(arm.AMOVW, &lo2, &bl)
    145 		p1 := gins(arm.AADD, &bl, &al)
    146 		p1.Scond |= arm.C_SBIT
    147 		gins(arm.AADC, &bh, &ah)
    148 		gc.Regfree(&bl)
    149 		gc.Regfree(&bh)
    150 
    151 		// TODO: Constants.
    152 	case gc.OSUB:
    153 		var bl gc.Node
    154 		gc.Regalloc(&bl, gc.Types[gc.TPTR32], nil)
    155 
    156 		var bh gc.Node
    157 		gc.Regalloc(&bh, gc.Types[gc.TPTR32], nil)
    158 		gins(arm.AMOVW, &lo1, &al)
    159 		gins(arm.AMOVW, &hi1, &ah)
    160 		gins(arm.AMOVW, &lo2, &bl)
    161 		gins(arm.AMOVW, &hi2, &bh)
    162 		p1 := gins(arm.ASUB, &bl, &al)
    163 		p1.Scond |= arm.C_SBIT
    164 		gins(arm.ASBC, &bh, &ah)
    165 		gc.Regfree(&bl)
    166 		gc.Regfree(&bh)
    167 
    168 		// TODO(kaib): this can be done with 4 regs and does not need 6
    169 	case gc.OMUL:
    170 		var bl gc.Node
    171 		gc.Regalloc(&bl, gc.Types[gc.TPTR32], nil)
    172 
    173 		var bh gc.Node
    174 		gc.Regalloc(&bh, gc.Types[gc.TPTR32], nil)
    175 		var cl gc.Node
    176 		gc.Regalloc(&cl, gc.Types[gc.TPTR32], nil)
    177 		var ch gc.Node
    178 		gc.Regalloc(&ch, gc.Types[gc.TPTR32], nil)
    179 
    180 		// load args into bh:bl and bh:bl.
    181 		gins(arm.AMOVW, &hi1, &bh)
    182 
    183 		gins(arm.AMOVW, &lo1, &bl)
    184 		gins(arm.AMOVW, &hi2, &ch)
    185 		gins(arm.AMOVW, &lo2, &cl)
    186 
    187 		// bl * cl -> ah al
    188 		p1 := gins(arm.AMULLU, nil, nil)
    189 
    190 		p1.From.Type = obj.TYPE_REG
    191 		p1.From.Reg = bl.Reg
    192 		p1.Reg = cl.Reg
    193 		p1.To.Type = obj.TYPE_REGREG
    194 		p1.To.Reg = ah.Reg
    195 		p1.To.Offset = int64(al.Reg)
    196 
    197 		//print("%v\n", p1);
    198 
    199 		// bl * ch + ah -> ah
    200 		p1 = gins(arm.AMULA, nil, nil)
    201 
    202 		p1.From.Type = obj.TYPE_REG
    203 		p1.From.Reg = bl.Reg
    204 		p1.Reg = ch.Reg
    205 		p1.To.Type = obj.TYPE_REGREG2
    206 		p1.To.Reg = ah.Reg
    207 		p1.To.Offset = int64(ah.Reg)
    208 
    209 		//print("%v\n", p1);
    210 
    211 		// bh * cl + ah -> ah
    212 		p1 = gins(arm.AMULA, nil, nil)
    213 
    214 		p1.From.Type = obj.TYPE_REG
    215 		p1.From.Reg = bh.Reg
    216 		p1.Reg = cl.Reg
    217 		p1.To.Type = obj.TYPE_REGREG2
    218 		p1.To.Reg = ah.Reg
    219 		p1.To.Offset = int64(ah.Reg)
    220 
    221 		//print("%v\n", p1);
    222 
    223 		gc.Regfree(&bh)
    224 
    225 		gc.Regfree(&bl)
    226 		gc.Regfree(&ch)
    227 		gc.Regfree(&cl)
    228 
    229 		// We only rotate by a constant c in [0,64).
    230 	// if c >= 32:
    231 	//	lo, hi = hi, lo
    232 	//	c -= 32
    233 	// if c == 0:
    234 	//	no-op
    235 	// else:
    236 	//	t = hi
    237 	//	shld hi:lo, c
    238 	//	shld lo:t, c
    239 	case gc.OLROT:
    240 		v := uint64(r.Int())
    241 
    242 		var bl gc.Node
    243 		gc.Regalloc(&bl, lo1.Type, nil)
    244 		var bh gc.Node
    245 		gc.Regalloc(&bh, hi1.Type, nil)
    246 		if v >= 32 {
    247 			// reverse during load to do the first 32 bits of rotate
    248 			v -= 32
    249 
    250 			gins(arm.AMOVW, &hi1, &bl)
    251 			gins(arm.AMOVW, &lo1, &bh)
    252 		} else {
    253 			gins(arm.AMOVW, &hi1, &bh)
    254 			gins(arm.AMOVW, &lo1, &bl)
    255 		}
    256 
    257 		if v == 0 {
    258 			gins(arm.AMOVW, &bh, &ah)
    259 			gins(arm.AMOVW, &bl, &al)
    260 		} else {
    261 			// rotate by 1 <= v <= 31
    262 			//	MOVW	bl<<v, al
    263 			//	MOVW	bh<<v, ah
    264 			//	OR		bl>>(32-v), ah
    265 			//	OR		bh>>(32-v), al
    266 			gshift(arm.AMOVW, &bl, arm.SHIFT_LL, int32(v), &al)
    267 
    268 			gshift(arm.AMOVW, &bh, arm.SHIFT_LL, int32(v), &ah)
    269 			gshift(arm.AORR, &bl, arm.SHIFT_LR, int32(32-v), &ah)
    270 			gshift(arm.AORR, &bh, arm.SHIFT_LR, int32(32-v), &al)
    271 		}
    272 
    273 		gc.Regfree(&bl)
    274 		gc.Regfree(&bh)
    275 
    276 	case gc.OLSH:
    277 		var bl gc.Node
    278 		gc.Regalloc(&bl, lo1.Type, nil)
    279 		var bh gc.Node
    280 		gc.Regalloc(&bh, hi1.Type, nil)
    281 		gins(arm.AMOVW, &hi1, &bh)
    282 		gins(arm.AMOVW, &lo1, &bl)
    283 
    284 		var p6 *obj.Prog
    285 		var s gc.Node
    286 		var n1 gc.Node
    287 		var creg gc.Node
    288 		var p1 *obj.Prog
    289 		var p2 *obj.Prog
    290 		var p3 *obj.Prog
    291 		var p4 *obj.Prog
    292 		var p5 *obj.Prog
    293 		if r.Op == gc.OLITERAL {
    294 			v := uint64(r.Int())
    295 			if v >= 64 {
    296 				// TODO(kaib): replace with gins(AMOVW, nodintconst(0), &al)
    297 				// here and below (verify it optimizes to EOR)
    298 				gins(arm.AEOR, &al, &al)
    299 
    300 				gins(arm.AEOR, &ah, &ah)
    301 			} else if v > 32 {
    302 				gins(arm.AEOR, &al, &al)
    303 
    304 				//	MOVW	bl<<(v-32), ah
    305 				gshift(arm.AMOVW, &bl, arm.SHIFT_LL, int32(v-32), &ah)
    306 			} else if v == 32 {
    307 				gins(arm.AEOR, &al, &al)
    308 				gins(arm.AMOVW, &bl, &ah)
    309 			} else if v > 0 {
    310 				//	MOVW	bl<<v, al
    311 				gshift(arm.AMOVW, &bl, arm.SHIFT_LL, int32(v), &al)
    312 
    313 				//	MOVW	bh<<v, ah
    314 				gshift(arm.AMOVW, &bh, arm.SHIFT_LL, int32(v), &ah)
    315 
    316 				//	OR		bl>>(32-v), ah
    317 				gshift(arm.AORR, &bl, arm.SHIFT_LR, int32(32-v), &ah)
    318 			} else {
    319 				gins(arm.AMOVW, &bl, &al)
    320 				gins(arm.AMOVW, &bh, &ah)
    321 			}
    322 
    323 			goto olsh_break
    324 		}
    325 
    326 		gc.Regalloc(&s, gc.Types[gc.TUINT32], nil)
    327 		gc.Regalloc(&creg, gc.Types[gc.TUINT32], nil)
    328 		if gc.Is64(r.Type) {
    329 			// shift is >= 1<<32
    330 			var cl gc.Node
    331 			var ch gc.Node
    332 			split64(r, &cl, &ch)
    333 
    334 			gmove(&ch, &s)
    335 			gins(arm.ATST, &s, nil)
    336 			p6 = gc.Gbranch(arm.ABNE, nil, 0)
    337 			gmove(&cl, &s)
    338 			splitclean()
    339 		} else {
    340 			gmove(r, &s)
    341 			p6 = nil
    342 		}
    343 
    344 		gins(arm.ATST, &s, nil)
    345 
    346 		// shift == 0
    347 		p1 = gins(arm.AMOVW, &bl, &al)
    348 
    349 		p1.Scond = arm.C_SCOND_EQ
    350 		p1 = gins(arm.AMOVW, &bh, &ah)
    351 		p1.Scond = arm.C_SCOND_EQ
    352 		p2 = gc.Gbranch(arm.ABEQ, nil, 0)
    353 
    354 		// shift is < 32
    355 		gc.Nodconst(&n1, gc.Types[gc.TUINT32], 32)
    356 
    357 		gmove(&n1, &creg)
    358 		gins(arm.ACMP, &s, &creg)
    359 
    360 		//	MOVW.LO		bl<<s, al
    361 		p1 = gregshift(arm.AMOVW, &bl, arm.SHIFT_LL, &s, &al)
    362 
    363 		p1.Scond = arm.C_SCOND_LO
    364 
    365 		//	MOVW.LO		bh<<s, ah
    366 		p1 = gregshift(arm.AMOVW, &bh, arm.SHIFT_LL, &s, &ah)
    367 
    368 		p1.Scond = arm.C_SCOND_LO
    369 
    370 		//	SUB.LO		s, creg
    371 		p1 = gins(arm.ASUB, &s, &creg)
    372 
    373 		p1.Scond = arm.C_SCOND_LO
    374 
    375 		//	OR.LO		bl>>creg, ah
    376 		p1 = gregshift(arm.AORR, &bl, arm.SHIFT_LR, &creg, &ah)
    377 
    378 		p1.Scond = arm.C_SCOND_LO
    379 
    380 		//	BLO	end
    381 		p3 = gc.Gbranch(arm.ABLO, nil, 0)
    382 
    383 		// shift == 32
    384 		p1 = gins(arm.AEOR, &al, &al)
    385 
    386 		p1.Scond = arm.C_SCOND_EQ
    387 		p1 = gins(arm.AMOVW, &bl, &ah)
    388 		p1.Scond = arm.C_SCOND_EQ
    389 		p4 = gc.Gbranch(arm.ABEQ, nil, 0)
    390 
    391 		// shift is < 64
    392 		gc.Nodconst(&n1, gc.Types[gc.TUINT32], 64)
    393 
    394 		gmove(&n1, &creg)
    395 		gins(arm.ACMP, &s, &creg)
    396 
    397 		//	EOR.LO	al, al
    398 		p1 = gins(arm.AEOR, &al, &al)
    399 
    400 		p1.Scond = arm.C_SCOND_LO
    401 
    402 		//	MOVW.LO		creg>>1, creg
    403 		p1 = gshift(arm.AMOVW, &creg, arm.SHIFT_LR, 1, &creg)
    404 
    405 		p1.Scond = arm.C_SCOND_LO
    406 
    407 		//	SUB.LO		creg, s
    408 		p1 = gins(arm.ASUB, &creg, &s)
    409 
    410 		p1.Scond = arm.C_SCOND_LO
    411 
    412 		//	MOVW	bl<<s, ah
    413 		p1 = gregshift(arm.AMOVW, &bl, arm.SHIFT_LL, &s, &ah)
    414 
    415 		p1.Scond = arm.C_SCOND_LO
    416 
    417 		p5 = gc.Gbranch(arm.ABLO, nil, 0)
    418 
    419 		// shift >= 64
    420 		if p6 != nil {
    421 			gc.Patch(p6, gc.Pc)
    422 		}
    423 		gins(arm.AEOR, &al, &al)
    424 		gins(arm.AEOR, &ah, &ah)
    425 
    426 		gc.Patch(p2, gc.Pc)
    427 		gc.Patch(p3, gc.Pc)
    428 		gc.Patch(p4, gc.Pc)
    429 		gc.Patch(p5, gc.Pc)
    430 		gc.Regfree(&s)
    431 		gc.Regfree(&creg)
    432 
    433 	olsh_break:
    434 		gc.Regfree(&bl)
    435 		gc.Regfree(&bh)
    436 
    437 	case gc.ORSH:
    438 		var bl gc.Node
    439 		gc.Regalloc(&bl, lo1.Type, nil)
    440 		var bh gc.Node
    441 		gc.Regalloc(&bh, hi1.Type, nil)
    442 		gins(arm.AMOVW, &hi1, &bh)
    443 		gins(arm.AMOVW, &lo1, &bl)
    444 
    445 		var p4 *obj.Prog
    446 		var p5 *obj.Prog
    447 		var n1 gc.Node
    448 		var p6 *obj.Prog
    449 		var s gc.Node
    450 		var p1 *obj.Prog
    451 		var p2 *obj.Prog
    452 		var creg gc.Node
    453 		var p3 *obj.Prog
    454 		if r.Op == gc.OLITERAL {
    455 			v := uint64(r.Int())
    456 			if v >= 64 {
    457 				if bh.Type.Etype == gc.TINT32 {
    458 					//	MOVW	bh->31, al
    459 					gshift(arm.AMOVW, &bh, arm.SHIFT_AR, 31, &al)
    460 
    461 					//	MOVW	bh->31, ah
    462 					gshift(arm.AMOVW, &bh, arm.SHIFT_AR, 31, &ah)
    463 				} else {
    464 					gins(arm.AEOR, &al, &al)
    465 					gins(arm.AEOR, &ah, &ah)
    466 				}
    467 			} else if v > 32 {
    468 				if bh.Type.Etype == gc.TINT32 {
    469 					//	MOVW	bh->(v-32), al
    470 					gshift(arm.AMOVW, &bh, arm.SHIFT_AR, int32(v-32), &al)
    471 
    472 					//	MOVW	bh->31, ah
    473 					gshift(arm.AMOVW, &bh, arm.SHIFT_AR, 31, &ah)
    474 				} else {
    475 					//	MOVW	bh>>(v-32), al
    476 					gshift(arm.AMOVW, &bh, arm.SHIFT_LR, int32(v-32), &al)
    477 
    478 					gins(arm.AEOR, &ah, &ah)
    479 				}
    480 			} else if v == 32 {
    481 				gins(arm.AMOVW, &bh, &al)
    482 				if bh.Type.Etype == gc.TINT32 {
    483 					//	MOVW	bh->31, ah
    484 					gshift(arm.AMOVW, &bh, arm.SHIFT_AR, 31, &ah)
    485 				} else {
    486 					gins(arm.AEOR, &ah, &ah)
    487 				}
    488 			} else if v > 0 {
    489 				//	MOVW	bl>>v, al
    490 				gshift(arm.AMOVW, &bl, arm.SHIFT_LR, int32(v), &al)
    491 
    492 				//	OR		bh<<(32-v), al
    493 				gshift(arm.AORR, &bh, arm.SHIFT_LL, int32(32-v), &al)
    494 
    495 				if bh.Type.Etype == gc.TINT32 {
    496 					//	MOVW	bh->v, ah
    497 					gshift(arm.AMOVW, &bh, arm.SHIFT_AR, int32(v), &ah)
    498 				} else {
    499 					//	MOVW	bh>>v, ah
    500 					gshift(arm.AMOVW, &bh, arm.SHIFT_LR, int32(v), &ah)
    501 				}
    502 			} else {
    503 				gins(arm.AMOVW, &bl, &al)
    504 				gins(arm.AMOVW, &bh, &ah)
    505 			}
    506 
    507 			goto orsh_break
    508 		}
    509 
    510 		gc.Regalloc(&s, gc.Types[gc.TUINT32], nil)
    511 		gc.Regalloc(&creg, gc.Types[gc.TUINT32], nil)
    512 		if gc.Is64(r.Type) {
    513 			// shift is >= 1<<32
    514 			var ch gc.Node
    515 			var cl gc.Node
    516 			split64(r, &cl, &ch)
    517 
    518 			gmove(&ch, &s)
    519 			gins(arm.ATST, &s, nil)
    520 			var p1 *obj.Prog
    521 			if bh.Type.Etype == gc.TINT32 {
    522 				p1 = gshift(arm.AMOVW, &bh, arm.SHIFT_AR, 31, &ah)
    523 			} else {
    524 				p1 = gins(arm.AEOR, &ah, &ah)
    525 			}
    526 			p1.Scond = arm.C_SCOND_NE
    527 			p6 = gc.Gbranch(arm.ABNE, nil, 0)
    528 			gmove(&cl, &s)
    529 			splitclean()
    530 		} else {
    531 			gmove(r, &s)
    532 			p6 = nil
    533 		}
    534 
    535 		gins(arm.ATST, &s, nil)
    536 
    537 		// shift == 0
    538 		p1 = gins(arm.AMOVW, &bl, &al)
    539 
    540 		p1.Scond = arm.C_SCOND_EQ
    541 		p1 = gins(arm.AMOVW, &bh, &ah)
    542 		p1.Scond = arm.C_SCOND_EQ
    543 		p2 = gc.Gbranch(arm.ABEQ, nil, 0)
    544 
    545 		// check if shift is < 32
    546 		gc.Nodconst(&n1, gc.Types[gc.TUINT32], 32)
    547 
    548 		gmove(&n1, &creg)
    549 		gins(arm.ACMP, &s, &creg)
    550 
    551 		//	MOVW.LO		bl>>s, al
    552 		p1 = gregshift(arm.AMOVW, &bl, arm.SHIFT_LR, &s, &al)
    553 
    554 		p1.Scond = arm.C_SCOND_LO
    555 
    556 		//	SUB.LO		s,creg
    557 		p1 = gins(arm.ASUB, &s, &creg)
    558 
    559 		p1.Scond = arm.C_SCOND_LO
    560 
    561 		//	OR.LO		bh<<(32-s), al
    562 		p1 = gregshift(arm.AORR, &bh, arm.SHIFT_LL, &creg, &al)
    563 
    564 		p1.Scond = arm.C_SCOND_LO
    565 
    566 		if bh.Type.Etype == gc.TINT32 {
    567 			//	MOVW	bh->s, ah
    568 			p1 = gregshift(arm.AMOVW, &bh, arm.SHIFT_AR, &s, &ah)
    569 		} else {
    570 			//	MOVW	bh>>s, ah
    571 			p1 = gregshift(arm.AMOVW, &bh, arm.SHIFT_LR, &s, &ah)
    572 		}
    573 
    574 		p1.Scond = arm.C_SCOND_LO
    575 
    576 		//	BLO	end
    577 		p3 = gc.Gbranch(arm.ABLO, nil, 0)
    578 
    579 		// shift == 32
    580 		p1 = gins(arm.AMOVW, &bh, &al)
    581 
    582 		p1.Scond = arm.C_SCOND_EQ
    583 		if bh.Type.Etype == gc.TINT32 {
    584 			gshift(arm.AMOVW, &bh, arm.SHIFT_AR, 31, &ah)
    585 		} else {
    586 			gins(arm.AEOR, &ah, &ah)
    587 		}
    588 		p4 = gc.Gbranch(arm.ABEQ, nil, 0)
    589 
    590 		// check if shift is < 64
    591 		gc.Nodconst(&n1, gc.Types[gc.TUINT32], 64)
    592 
    593 		gmove(&n1, &creg)
    594 		gins(arm.ACMP, &s, &creg)
    595 
    596 		//	MOVW.LO		creg>>1, creg
    597 		p1 = gshift(arm.AMOVW, &creg, arm.SHIFT_LR, 1, &creg)
    598 
    599 		p1.Scond = arm.C_SCOND_LO
    600 
    601 		//	SUB.LO		creg, s
    602 		p1 = gins(arm.ASUB, &creg, &s)
    603 
    604 		p1.Scond = arm.C_SCOND_LO
    605 
    606 		if bh.Type.Etype == gc.TINT32 {
    607 			//	MOVW	bh->(s-32), al
    608 			p1 := gregshift(arm.AMOVW, &bh, arm.SHIFT_AR, &s, &al)
    609 
    610 			p1.Scond = arm.C_SCOND_LO
    611 		} else {
    612 			//	MOVW	bh>>(v-32), al
    613 			p1 := gregshift(arm.AMOVW, &bh, arm.SHIFT_LR, &s, &al)
    614 
    615 			p1.Scond = arm.C_SCOND_LO
    616 		}
    617 
    618 		//	BLO	end
    619 		p5 = gc.Gbranch(arm.ABLO, nil, 0)
    620 
    621 		// s >= 64
    622 		if p6 != nil {
    623 			gc.Patch(p6, gc.Pc)
    624 		}
    625 		if bh.Type.Etype == gc.TINT32 {
    626 			//	MOVW	bh->31, al
    627 			gshift(arm.AMOVW, &bh, arm.SHIFT_AR, 31, &al)
    628 		} else {
    629 			gins(arm.AEOR, &al, &al)
    630 		}
    631 
    632 		gc.Patch(p2, gc.Pc)
    633 		gc.Patch(p3, gc.Pc)
    634 		gc.Patch(p4, gc.Pc)
    635 		gc.Patch(p5, gc.Pc)
    636 		gc.Regfree(&s)
    637 		gc.Regfree(&creg)
    638 
    639 	orsh_break:
    640 		gc.Regfree(&bl)
    641 		gc.Regfree(&bh)
    642 
    643 		// TODO(kaib): literal optimizations
    644 	// make constant the right side (it usually is anyway).
    645 	//		if(lo1.op == OLITERAL) {
    646 	//			nswap(&lo1, &lo2);
    647 	//			nswap(&hi1, &hi2);
    648 	//		}
    649 	//		if(lo2.op == OLITERAL) {
    650 	//			// special cases for constants.
    651 	//			lv = mpgetfix(lo2.val.u.xval);
    652 	//			hv = mpgetfix(hi2.val.u.xval);
    653 	//			splitclean();	// right side
    654 	//			split64(res, &lo2, &hi2);
    655 	//			switch(n->op) {
    656 	//			case OXOR:
    657 	//				gmove(&lo1, &lo2);
    658 	//				gmove(&hi1, &hi2);
    659 	//				switch(lv) {
    660 	//				case 0:
    661 	//					break;
    662 	//				case 0xffffffffu:
    663 	//					gins(ANOTL, N, &lo2);
    664 	//					break;
    665 	//				default:
    666 	//					gins(AXORL, ncon(lv), &lo2);
    667 	//					break;
    668 	//				}
    669 	//				switch(hv) {
    670 	//				case 0:
    671 	//					break;
    672 	//				case 0xffffffffu:
    673 	//					gins(ANOTL, N, &hi2);
    674 	//					break;
    675 	//				default:
    676 	//					gins(AXORL, ncon(hv), &hi2);
    677 	//					break;
    678 	//				}
    679 	//				break;
    680 
    681 	//			case OAND:
    682 	//				switch(lv) {
    683 	//				case 0:
    684 	//					gins(AMOVL, ncon(0), &lo2);
    685 	//					break;
    686 	//				default:
    687 	//					gmove(&lo1, &lo2);
    688 	//					if(lv != 0xffffffffu)
    689 	//						gins(AANDL, ncon(lv), &lo2);
    690 	//					break;
    691 	//				}
    692 	//				switch(hv) {
    693 	//				case 0:
    694 	//					gins(AMOVL, ncon(0), &hi2);
    695 	//					break;
    696 	//				default:
    697 	//					gmove(&hi1, &hi2);
    698 	//					if(hv != 0xffffffffu)
    699 	//						gins(AANDL, ncon(hv), &hi2);
    700 	//					break;
    701 	//				}
    702 	//				break;
    703 
    704 	//			case OOR:
    705 	//				switch(lv) {
    706 	//				case 0:
    707 	//					gmove(&lo1, &lo2);
    708 	//					break;
    709 	//				case 0xffffffffu:
    710 	//					gins(AMOVL, ncon(0xffffffffu), &lo2);
    711 	//					break;
    712 	//				default:
    713 	//					gmove(&lo1, &lo2);
    714 	//					gins(AORL, ncon(lv), &lo2);
    715 	//					break;
    716 	//				}
    717 	//				switch(hv) {
    718 	//				case 0:
    719 	//					gmove(&hi1, &hi2);
    720 	//					break;
    721 	//				case 0xffffffffu:
    722 	//					gins(AMOVL, ncon(0xffffffffu), &hi2);
    723 	//					break;
    724 	//				default:
    725 	//					gmove(&hi1, &hi2);
    726 	//					gins(AORL, ncon(hv), &hi2);
    727 	//					break;
    728 	//				}
    729 	//				break;
    730 	//			}
    731 	//			splitclean();
    732 	//			splitclean();
    733 	//			goto out;
    734 	//		}
    735 	case gc.OXOR,
    736 		gc.OAND,
    737 		gc.OOR:
    738 		var n1 gc.Node
    739 		gc.Regalloc(&n1, lo1.Type, nil)
    740 
    741 		gins(arm.AMOVW, &lo1, &al)
    742 		gins(arm.AMOVW, &hi1, &ah)
    743 		gins(arm.AMOVW, &lo2, &n1)
    744 		gins(optoas(int(n.Op), lo1.Type), &n1, &al)
    745 		gins(arm.AMOVW, &hi2, &n1)
    746 		gins(optoas(int(n.Op), lo1.Type), &n1, &ah)
    747 		gc.Regfree(&n1)
    748 	}
    749 
    750 	if gc.Is64(r.Type) {
    751 		splitclean()
    752 	}
    753 	splitclean()
    754 
    755 	split64(res, &lo1, &hi1)
    756 	gins(arm.AMOVW, &al, &lo1)
    757 	gins(arm.AMOVW, &ah, &hi1)
    758 	splitclean()
    759 
    760 	//out:
    761 	gc.Regfree(&al)
    762 
    763 	gc.Regfree(&ah)
    764 }
    765 
    766 /*
    767  * generate comparison of nl, nr, both 64-bit.
    768  * nl is memory; nr is constant or memory.
    769  */
    770 func cmp64(nl *gc.Node, nr *gc.Node, op int, likely int, to *obj.Prog) {
    771 	var lo1 gc.Node
    772 	var hi1 gc.Node
    773 	var lo2 gc.Node
    774 	var hi2 gc.Node
    775 	var r1 gc.Node
    776 	var r2 gc.Node
    777 
    778 	split64(nl, &lo1, &hi1)
    779 	split64(nr, &lo2, &hi2)
    780 
    781 	// compare most significant word;
    782 	// if they differ, we're done.
    783 	t := hi1.Type
    784 
    785 	gc.Regalloc(&r1, gc.Types[gc.TINT32], nil)
    786 	gc.Regalloc(&r2, gc.Types[gc.TINT32], nil)
    787 	gins(arm.AMOVW, &hi1, &r1)
    788 	gins(arm.AMOVW, &hi2, &r2)
    789 	gins(arm.ACMP, &r1, &r2)
    790 	gc.Regfree(&r1)
    791 	gc.Regfree(&r2)
    792 
    793 	var br *obj.Prog
    794 	switch op {
    795 	default:
    796 		gc.Fatal("cmp64 %v %v", gc.Oconv(int(op), 0), t)
    797 
    798 		// cmp hi
    799 	// bne L
    800 	// cmp lo
    801 	// beq to
    802 	// L:
    803 	case gc.OEQ:
    804 		br = gc.Gbranch(arm.ABNE, nil, -likely)
    805 
    806 		// cmp hi
    807 	// bne to
    808 	// cmp lo
    809 	// bne to
    810 	case gc.ONE:
    811 		gc.Patch(gc.Gbranch(arm.ABNE, nil, likely), to)
    812 
    813 		// cmp hi
    814 	// bgt to
    815 	// blt L
    816 	// cmp lo
    817 	// bge to (or bgt to)
    818 	// L:
    819 	case gc.OGE,
    820 		gc.OGT:
    821 		gc.Patch(gc.Gbranch(optoas(gc.OGT, t), nil, likely), to)
    822 
    823 		br = gc.Gbranch(optoas(gc.OLT, t), nil, -likely)
    824 
    825 		// cmp hi
    826 	// blt to
    827 	// bgt L
    828 	// cmp lo
    829 	// ble to (or jlt to)
    830 	// L:
    831 	case gc.OLE,
    832 		gc.OLT:
    833 		gc.Patch(gc.Gbranch(optoas(gc.OLT, t), nil, likely), to)
    834 
    835 		br = gc.Gbranch(optoas(gc.OGT, t), nil, -likely)
    836 	}
    837 
    838 	// compare least significant word
    839 	t = lo1.Type
    840 
    841 	gc.Regalloc(&r1, gc.Types[gc.TINT32], nil)
    842 	gc.Regalloc(&r2, gc.Types[gc.TINT32], nil)
    843 	gins(arm.AMOVW, &lo1, &r1)
    844 	gins(arm.AMOVW, &lo2, &r2)
    845 	gins(arm.ACMP, &r1, &r2)
    846 	gc.Regfree(&r1)
    847 	gc.Regfree(&r2)
    848 
    849 	// jump again
    850 	gc.Patch(gc.Gbranch(optoas(op, t), nil, likely), to)
    851 
    852 	// point first branch down here if appropriate
    853 	if br != nil {
    854 		gc.Patch(br, gc.Pc)
    855 	}
    856 
    857 	splitclean()
    858 	splitclean()
    859 }
    860