github.com/q45/go@v0.0.0-20151101211701-a4fb8c13db3f/src/cmd/compile/internal/arm/cgen64.go (about)

     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.Fatalf("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.Fatalf("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.Fatalf("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(n.Op, lo1.Type), &n1, &al)
   745  		gins(arm.AMOVW, &hi2, &n1)
   746  		gins(optoas(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 gc.Op, 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.Fatalf("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  }