github.com/gocuntian/go@v0.0.0-20160610041250-fee02d270bf8/src/cmd/compile/internal/gc/testdata/arith_ssa.go (about)

     1  // run
     2  
     3  // Copyright 2015 The Go Authors. All rights reserved.
     4  // Use of this source code is governed by a BSD-style
     5  // license that can be found in the LICENSE file.
     6  
     7  // Tests arithmetic expressions
     8  
     9  package main
    10  
    11  import "fmt"
    12  
    13  const (
    14  	y = 0x0fffFFFF
    15  )
    16  
    17  //go:noinline
    18  func lshNop1(x uint64) uint64 {
    19  	// two outer shifts should be removed
    20  	return (((x << 5) >> 2) << 2)
    21  }
    22  
    23  //go:noinline
    24  func lshNop2(x uint64) uint64 {
    25  	return (((x << 5) >> 2) << 3)
    26  }
    27  
    28  //go:noinline
    29  func lshNop3(x uint64) uint64 {
    30  	return (((x << 5) >> 2) << 6)
    31  }
    32  
    33  //go:noinline
    34  func lshNotNop(x uint64) uint64 {
    35  	// outer shift can't be removed
    36  	return (((x << 5) >> 2) << 1)
    37  }
    38  
    39  //go:noinline
    40  func rshNop1(x uint64) uint64 {
    41  	return (((x >> 5) << 2) >> 2)
    42  }
    43  
    44  //go:noinline
    45  func rshNop2(x uint64) uint64 {
    46  	return (((x >> 5) << 2) >> 3)
    47  }
    48  
    49  //go:noinline
    50  func rshNop3(x uint64) uint64 {
    51  	return (((x >> 5) << 2) >> 6)
    52  }
    53  
    54  //go:noinline
    55  func rshNotNop(x uint64) uint64 {
    56  	return (((x >> 5) << 2) >> 1)
    57  }
    58  
    59  func testShiftRemoval() {
    60  	allSet := ^uint64(0)
    61  	if want, got := uint64(0x7ffffffffffffff), rshNop1(allSet); want != got {
    62  		println("testShiftRemoval rshNop1 failed, wanted", want, "got", got)
    63  		failed = true
    64  	}
    65  	if want, got := uint64(0x3ffffffffffffff), rshNop2(allSet); want != got {
    66  		println("testShiftRemoval rshNop2 failed, wanted", want, "got", got)
    67  		failed = true
    68  	}
    69  	if want, got := uint64(0x7fffffffffffff), rshNop3(allSet); want != got {
    70  		println("testShiftRemoval rshNop3 failed, wanted", want, "got", got)
    71  		failed = true
    72  	}
    73  	if want, got := uint64(0xffffffffffffffe), rshNotNop(allSet); want != got {
    74  		println("testShiftRemoval rshNotNop failed, wanted", want, "got", got)
    75  		failed = true
    76  	}
    77  	if want, got := uint64(0xffffffffffffffe0), lshNop1(allSet); want != got {
    78  		println("testShiftRemoval lshNop1 failed, wanted", want, "got", got)
    79  		failed = true
    80  	}
    81  	if want, got := uint64(0xffffffffffffffc0), lshNop2(allSet); want != got {
    82  		println("testShiftRemoval lshNop2 failed, wanted", want, "got", got)
    83  		failed = true
    84  	}
    85  	if want, got := uint64(0xfffffffffffffe00), lshNop3(allSet); want != got {
    86  		println("testShiftRemoval lshNop3 failed, wanted", want, "got", got)
    87  		failed = true
    88  	}
    89  	if want, got := uint64(0x7ffffffffffffff0), lshNotNop(allSet); want != got {
    90  		println("testShiftRemoval lshNotNop failed, wanted", want, "got", got)
    91  		failed = true
    92  	}
    93  }
    94  
    95  //go:noinline
    96  func parseLE64(b []byte) uint64 {
    97  	// skip the first two bytes, and parse the remaining 8 as a uint64
    98  	return uint64(b[2]) | uint64(b[3])<<8 | uint64(b[4])<<16 | uint64(b[5])<<24 |
    99  		uint64(b[6])<<32 | uint64(b[7])<<40 | uint64(b[8])<<48 | uint64(b[9])<<56
   100  }
   101  
   102  //go:noinline
   103  func parseLE32(b []byte) uint32 {
   104  	return uint32(b[2]) | uint32(b[3])<<8 | uint32(b[4])<<16 | uint32(b[5])<<24
   105  }
   106  
   107  //go:noinline
   108  func parseLE16(b []byte) uint16 {
   109  	return uint16(b[2]) | uint16(b[3])<<8
   110  }
   111  
   112  // testLoadCombine tests for issue #14694 where load combining didn't respect the pointer offset.
   113  func testLoadCombine() {
   114  	testData := []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09}
   115  	if want, got := uint64(0x0908070605040302), parseLE64(testData); want != got {
   116  		println("testLoadCombine failed, wanted", want, "got", got)
   117  		failed = true
   118  	}
   119  	if want, got := uint32(0x05040302), parseLE32(testData); want != got {
   120  		println("testLoadCombine failed, wanted", want, "got", got)
   121  		failed = true
   122  	}
   123  	if want, got := uint16(0x0302), parseLE16(testData); want != got {
   124  		println("testLoadCombine failed, wanted", want, "got", got)
   125  		failed = true
   126  	}
   127  }
   128  
   129  var loadSymData = [...]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}
   130  
   131  func testLoadSymCombine() {
   132  	w2 := uint16(0x0201)
   133  	g2 := uint16(loadSymData[0]) | uint16(loadSymData[1])<<8
   134  	if g2 != w2 {
   135  		println("testLoadSymCombine failed, wanted", w2, "got", g2)
   136  		failed = true
   137  	}
   138  	w4 := uint32(0x04030201)
   139  	g4 := uint32(loadSymData[0]) | uint32(loadSymData[1])<<8 |
   140  		uint32(loadSymData[2])<<16 | uint32(loadSymData[3])<<24
   141  	if g4 != w4 {
   142  		println("testLoadSymCombine failed, wanted", w4, "got", g4)
   143  		failed = true
   144  	}
   145  	w8 := uint64(0x0807060504030201)
   146  	g8 := uint64(loadSymData[0]) | uint64(loadSymData[1])<<8 |
   147  		uint64(loadSymData[2])<<16 | uint64(loadSymData[3])<<24 |
   148  		uint64(loadSymData[4])<<32 | uint64(loadSymData[5])<<40 |
   149  		uint64(loadSymData[6])<<48 | uint64(loadSymData[7])<<56
   150  	if g8 != w8 {
   151  		println("testLoadSymCombine failed, wanted", w8, "got", g8)
   152  		failed = true
   153  	}
   154  }
   155  
   156  //go:noinline
   157  func invalidAdd_ssa(x uint32) uint32 {
   158  	return x + y + y + y + y + y + y + y + y + y + y + y + y + y + y + y + y + y
   159  }
   160  
   161  //go:noinline
   162  func invalidSub_ssa(x uint32) uint32 {
   163  	return x - y - y - y - y - y - y - y - y - y - y - y - y - y - y - y - y - y
   164  }
   165  
   166  //go:noinline
   167  func invalidMul_ssa(x uint32) uint32 {
   168  	return x * y * y * y * y * y * y * y * y * y * y * y * y * y * y * y * y * y
   169  }
   170  
   171  // testLargeConst tests a situation where larger than 32 bit consts were passed to ADDL
   172  // causing an invalid instruction error.
   173  func testLargeConst() {
   174  	if want, got := uint32(268435440), invalidAdd_ssa(1); want != got {
   175  		println("testLargeConst add failed, wanted", want, "got", got)
   176  		failed = true
   177  	}
   178  	if want, got := uint32(4026531858), invalidSub_ssa(1); want != got {
   179  		println("testLargeConst sub failed, wanted", want, "got", got)
   180  		failed = true
   181  	}
   182  	if want, got := uint32(268435455), invalidMul_ssa(1); want != got {
   183  		println("testLargeConst mul failed, wanted", want, "got", got)
   184  		failed = true
   185  	}
   186  }
   187  
   188  // testArithRshConst ensures that "const >> const" right shifts correctly perform
   189  // sign extension on the lhs constant
   190  func testArithRshConst() {
   191  	wantu := uint64(0x4000000000000000)
   192  	if got := arithRshuConst_ssa(); got != wantu {
   193  		println("arithRshuConst failed, wanted", wantu, "got", got)
   194  		failed = true
   195  	}
   196  
   197  	wants := int64(-0x4000000000000000)
   198  	if got := arithRshConst_ssa(); got != wants {
   199  		println("arithRshuConst failed, wanted", wants, "got", got)
   200  		failed = true
   201  	}
   202  }
   203  
   204  //go:noinline
   205  func arithRshuConst_ssa() uint64 {
   206  	y := uint64(0x8000000000000001)
   207  	z := uint64(1)
   208  	return uint64(y >> z)
   209  }
   210  
   211  //go:noinline
   212  func arithRshConst_ssa() int64 {
   213  	y := int64(-0x8000000000000000)
   214  	z := uint64(1)
   215  	return int64(y >> z)
   216  }
   217  
   218  //go:noinline
   219  func arithConstShift_ssa(x int64) int64 {
   220  	return x >> 100
   221  }
   222  
   223  // testArithConstShift tests that right shift by large constants preserve
   224  // the sign of the input.
   225  func testArithConstShift() {
   226  	want := int64(-1)
   227  	if got := arithConstShift_ssa(-1); want != got {
   228  		println("arithConstShift_ssa(-1) failed, wanted", want, "got", got)
   229  		failed = true
   230  	}
   231  	want = 0
   232  	if got := arithConstShift_ssa(1); want != got {
   233  		println("arithConstShift_ssa(1) failed, wanted", want, "got", got)
   234  		failed = true
   235  	}
   236  }
   237  
   238  // overflowConstShift_ssa verifes that constant folding for shift
   239  // doesn't wrap (i.e. x << MAX_INT << 1 doesn't get folded to x << 0).
   240  //go:noinline
   241  func overflowConstShift64_ssa(x int64) int64 {
   242  	return x << uint64(0xffffffffffffffff) << uint64(1)
   243  }
   244  
   245  //go:noinline
   246  func overflowConstShift32_ssa(x int64) int32 {
   247  	return int32(x) << uint32(0xffffffff) << uint32(1)
   248  }
   249  
   250  //go:noinline
   251  func overflowConstShift16_ssa(x int64) int16 {
   252  	return int16(x) << uint16(0xffff) << uint16(1)
   253  }
   254  
   255  //go:noinline
   256  func overflowConstShift8_ssa(x int64) int8 {
   257  	return int8(x) << uint8(0xff) << uint8(1)
   258  }
   259  
   260  func testOverflowConstShift() {
   261  	want := int64(0)
   262  	for x := int64(-127); x < int64(127); x++ {
   263  		got := overflowConstShift64_ssa(x)
   264  		if want != got {
   265  			fmt.Printf("overflowShift64 failed, wanted %d got %d\n", want, got)
   266  		}
   267  		got = int64(overflowConstShift32_ssa(x))
   268  		if want != got {
   269  			fmt.Printf("overflowShift32 failed, wanted %d got %d\n", want, got)
   270  		}
   271  		got = int64(overflowConstShift16_ssa(x))
   272  		if want != got {
   273  			fmt.Printf("overflowShift16 failed, wanted %d got %d\n", want, got)
   274  		}
   275  		got = int64(overflowConstShift8_ssa(x))
   276  		if want != got {
   277  			fmt.Printf("overflowShift8 failed, wanted %d got %d\n", want, got)
   278  		}
   279  	}
   280  }
   281  
   282  // test64BitConstMult tests that rewrite rules don't fold 64 bit constants
   283  // into multiply instructions.
   284  func test64BitConstMult() {
   285  	want := int64(103079215109)
   286  	if got := test64BitConstMult_ssa(1, 2); want != got {
   287  		println("test64BitConstMult failed, wanted", want, "got", got)
   288  		failed = true
   289  	}
   290  }
   291  
   292  //go:noinline
   293  func test64BitConstMult_ssa(a, b int64) int64 {
   294  	return 34359738369*a + b*34359738370
   295  }
   296  
   297  // test64BitConstAdd tests that rewrite rules don't fold 64 bit constants
   298  // into add instructions.
   299  func test64BitConstAdd() {
   300  	want := int64(3567671782835376650)
   301  	if got := test64BitConstAdd_ssa(1, 2); want != got {
   302  		println("test64BitConstAdd failed, wanted", want, "got", got)
   303  		failed = true
   304  	}
   305  }
   306  
   307  //go:noinline
   308  func test64BitConstAdd_ssa(a, b int64) int64 {
   309  	return a + 575815584948629622 + b + 2991856197886747025
   310  }
   311  
   312  // testRegallocCVSpill tests that regalloc spills a value whose last use is the
   313  // current value.
   314  func testRegallocCVSpill() {
   315  	want := int8(-9)
   316  	if got := testRegallocCVSpill_ssa(1, 2, 3, 4); want != got {
   317  		println("testRegallocCVSpill failed, wanted", want, "got", got)
   318  		failed = true
   319  	}
   320  }
   321  
   322  //go:noinline
   323  func testRegallocCVSpill_ssa(a, b, c, d int8) int8 {
   324  	return a + -32 + b + 63*c*-87*d
   325  }
   326  
   327  func testBitwiseLogic() {
   328  	a, b := uint32(57623283), uint32(1314713839)
   329  	if want, got := uint32(38551779), testBitwiseAnd_ssa(a, b); want != got {
   330  		println("testBitwiseAnd failed, wanted", want, "got", got)
   331  		failed = true
   332  	}
   333  	if want, got := uint32(1333785343), testBitwiseOr_ssa(a, b); want != got {
   334  		println("testBitwiseOr failed, wanted", want, "got", got)
   335  		failed = true
   336  	}
   337  	if want, got := uint32(1295233564), testBitwiseXor_ssa(a, b); want != got {
   338  		println("testBitwiseXor failed, wanted", want, "got", got)
   339  		failed = true
   340  	}
   341  	if want, got := int32(832), testBitwiseLsh_ssa(13, 4, 2); want != got {
   342  		println("testBitwiseLsh failed, wanted", want, "got", got)
   343  		failed = true
   344  	}
   345  	if want, got := int32(0), testBitwiseLsh_ssa(13, 25, 15); want != got {
   346  		println("testBitwiseLsh failed, wanted", want, "got", got)
   347  		failed = true
   348  	}
   349  	if want, got := int32(0), testBitwiseLsh_ssa(-13, 25, 15); want != got {
   350  		println("testBitwiseLsh failed, wanted", want, "got", got)
   351  		failed = true
   352  	}
   353  	if want, got := int32(-13), testBitwiseRsh_ssa(-832, 4, 2); want != got {
   354  		println("testBitwiseRsh failed, wanted", want, "got", got)
   355  		failed = true
   356  	}
   357  	if want, got := int32(0), testBitwiseRsh_ssa(13, 25, 15); want != got {
   358  		println("testBitwiseRsh failed, wanted", want, "got", got)
   359  		failed = true
   360  	}
   361  	if want, got := int32(-1), testBitwiseRsh_ssa(-13, 25, 15); want != got {
   362  		println("testBitwiseRsh failed, wanted", want, "got", got)
   363  		failed = true
   364  	}
   365  	if want, got := uint32(0x3ffffff), testBitwiseRshU_ssa(0xffffffff, 4, 2); want != got {
   366  		println("testBitwiseRshU failed, wanted", want, "got", got)
   367  		failed = true
   368  	}
   369  	if want, got := uint32(0), testBitwiseRshU_ssa(13, 25, 15); want != got {
   370  		println("testBitwiseRshU failed, wanted", want, "got", got)
   371  		failed = true
   372  	}
   373  	if want, got := uint32(0), testBitwiseRshU_ssa(0x8aaaaaaa, 25, 15); want != got {
   374  		println("testBitwiseRshU failed, wanted", want, "got", got)
   375  		failed = true
   376  	}
   377  }
   378  
   379  //go:noinline
   380  func testBitwiseAnd_ssa(a, b uint32) uint32 {
   381  	return a & b
   382  }
   383  
   384  //go:noinline
   385  func testBitwiseOr_ssa(a, b uint32) uint32 {
   386  	return a | b
   387  }
   388  
   389  //go:noinline
   390  func testBitwiseXor_ssa(a, b uint32) uint32 {
   391  	return a ^ b
   392  }
   393  
   394  //go:noinline
   395  func testBitwiseLsh_ssa(a int32, b, c uint32) int32 {
   396  	return a << b << c
   397  }
   398  
   399  //go:noinline
   400  func testBitwiseRsh_ssa(a int32, b, c uint32) int32 {
   401  	return a >> b >> c
   402  }
   403  
   404  //go:noinline
   405  func testBitwiseRshU_ssa(a uint32, b, c uint32) uint32 {
   406  	return a >> b >> c
   407  }
   408  
   409  //go:noinline
   410  func testShiftCX_ssa() int {
   411  	v1 := uint8(3)
   412  	v4 := (v1 * v1) ^ v1 | v1 - v1 - v1&v1 ^ uint8(3+2) + v1*1>>0 - v1 | 1 | v1<<(2*3|0-0*0^1)
   413  	v5 := v4>>(3-0-uint(3)) | v1 | v1 + v1 ^ v4<<(0+1|3&1)<<(uint64(1)<<0*2*0<<0) ^ v1
   414  	v6 := v5 ^ (v1+v1)*v1 | v1 | v1*v1>>(v1&v1)>>(uint(1)<<0*uint(3)>>1)*v1<<2*v1<<v1 - v1>>2 | (v4 - v1) ^ v1 + v1 ^ v1>>1 | v1 + v1 - v1 ^ v1
   415  	v7 := v6 & v5 << 0
   416  	v1++
   417  	v11 := 2&1 ^ 0 + 3 | int(0^0)<<1>>(1*0*3) ^ 0*0 ^ 3&0*3&3 ^ 3*3 ^ 1 ^ int(2)<<(2*3) + 2 | 2 | 2 ^ 2 + 1 | 3 | 0 ^ int(1)>>1 ^ 2 // int
   418  	v7--
   419  	return int(uint64(2*1)<<(3-2)<<uint(3>>v7)-2)&v11 | v11 - int(2)<<0>>(2-1)*(v11*0&v11<<1<<(uint8(2)+v4))
   420  }
   421  
   422  func testShiftCX() {
   423  	want := 141
   424  	if got := testShiftCX_ssa(); want != got {
   425  		println("testShiftCX failed, wanted", want, "got", got)
   426  		failed = true
   427  	}
   428  }
   429  
   430  // testSubqToNegq ensures that the SUBQ -> NEGQ translation works correctly.
   431  func testSubqToNegq() {
   432  	want := int64(-318294940372190156)
   433  	if got := testSubqToNegq_ssa(1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2); want != got {
   434  		println("testSubqToNegq failed, wanted", want, "got", got)
   435  		failed = true
   436  	}
   437  }
   438  
   439  //go:noinline
   440  func testSubqToNegq_ssa(a, b, c, d, e, f, g, h, i, j, k int64) int64 {
   441  	return a + 8207351403619448057 - b - 1779494519303207690 + c*8810076340510052032*d - 4465874067674546219 - e*4361839741470334295 - f + 8688847565426072650*g*8065564729145417479
   442  }
   443  
   444  func testOcom() {
   445  	want1, want2 := int32(0x55555555), int32(-0x55555556)
   446  	if got1, got2 := testOcom_ssa(0x55555555, 0x55555555); want1 != got1 || want2 != got2 {
   447  		println("testSubqToNegq failed, wanted", want1, "and", want2,
   448  			"got", got1, "and", got2)
   449  		failed = true
   450  	}
   451  }
   452  
   453  //go:noinline
   454  func testOcom_ssa(a, b int32) (int32, int32) {
   455  	return ^^^^a, ^^^^^b
   456  }
   457  
   458  func lrot1_ssa(w uint8, x uint16, y uint32, z uint64) (a uint8, b uint16, c uint32, d uint64) {
   459  	a = (w << 5) | (w >> 3)
   460  	b = (x << 13) | (x >> 3)
   461  	c = (y << 29) | (y >> 3)
   462  	d = (z << 61) | (z >> 3)
   463  	return
   464  }
   465  
   466  //go:noinline
   467  func lrot2_ssa(w, n uint32) uint32 {
   468  	// Want to be sure that a "rotate by 32" which
   469  	// is really 0 | (w >> 0) == w
   470  	// is correctly compiled.
   471  	return (w << n) | (w >> (32 - n))
   472  }
   473  
   474  //go:noinline
   475  func lrot3_ssa(w uint32) uint32 {
   476  	// Want to be sure that a "rotate by 32" which
   477  	// is really 0 | (w >> 0) == w
   478  	// is correctly compiled.
   479  	return (w << 32) | (w >> (32 - 32))
   480  }
   481  
   482  func testLrot() {
   483  	wantA, wantB, wantC, wantD := uint8(0xe1), uint16(0xe001),
   484  		uint32(0xe0000001), uint64(0xe000000000000001)
   485  	a, b, c, d := lrot1_ssa(0xf, 0xf, 0xf, 0xf)
   486  	if a != wantA || b != wantB || c != wantC || d != wantD {
   487  		println("lrot1_ssa(0xf, 0xf, 0xf, 0xf)=",
   488  			wantA, wantB, wantC, wantD, ", got", a, b, c, d)
   489  		failed = true
   490  	}
   491  	x := lrot2_ssa(0xb0000001, 32)
   492  	wantX := uint32(0xb0000001)
   493  	if x != wantX {
   494  		println("lrot2_ssa(0xb0000001, 32)=",
   495  			wantX, ", got", x)
   496  		failed = true
   497  	}
   498  	x = lrot3_ssa(0xb0000001)
   499  	if x != wantX {
   500  		println("lrot3_ssa(0xb0000001)=",
   501  			wantX, ", got", x)
   502  		failed = true
   503  	}
   504  
   505  }
   506  
   507  //go:noinline
   508  func sub1_ssa() uint64 {
   509  	v1 := uint64(3) // uint64
   510  	return v1*v1 - (v1&v1)&v1
   511  }
   512  
   513  //go:noinline
   514  func sub2_ssa() uint8 {
   515  	v1 := uint8(0)
   516  	v3 := v1 + v1 + v1 ^ v1 | 3 + v1 ^ v1 | v1 ^ v1
   517  	v1-- // dev.ssa doesn't see this one
   518  	return v1 ^ v1*v1 - v3
   519  }
   520  
   521  func testSubConst() {
   522  	x1 := sub1_ssa()
   523  	want1 := uint64(6)
   524  	if x1 != want1 {
   525  		println("sub1_ssa()=", want1, ", got", x1)
   526  		failed = true
   527  	}
   528  	x2 := sub2_ssa()
   529  	want2 := uint8(251)
   530  	if x2 != want2 {
   531  		println("sub2_ssa()=", want2, ", got", x2)
   532  		failed = true
   533  	}
   534  }
   535  
   536  //go:noinline
   537  func orPhi_ssa(a bool, x int) int {
   538  	v := 0
   539  	if a {
   540  		v = -1
   541  	} else {
   542  		v = -1
   543  	}
   544  	return x | v
   545  }
   546  
   547  func testOrPhi() {
   548  	if want, got := -1, orPhi_ssa(true, 4); got != want {
   549  		println("orPhi_ssa(true, 4)=", got, " want ", want)
   550  	}
   551  	if want, got := -1, orPhi_ssa(false, 0); got != want {
   552  		println("orPhi_ssa(false, 0)=", got, " want ", want)
   553  	}
   554  }
   555  
   556  var failed = false
   557  
   558  func main() {
   559  
   560  	test64BitConstMult()
   561  	test64BitConstAdd()
   562  	testRegallocCVSpill()
   563  	testSubqToNegq()
   564  	testBitwiseLogic()
   565  	testOcom()
   566  	testLrot()
   567  	testShiftCX()
   568  	testSubConst()
   569  	testOverflowConstShift()
   570  	testArithConstShift()
   571  	testArithRshConst()
   572  	testLargeConst()
   573  	testLoadCombine()
   574  	testLoadSymCombine()
   575  	testShiftRemoval()
   576  
   577  	if failed {
   578  		panic("failed")
   579  	}
   580  }