// Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Tests load/store ordering package main import "testing" // testLoadStoreOrder tests for reordering of stores/loads. func testLoadStoreOrder(t *testing.T) { z := uint32(1000) if testLoadStoreOrder_ssa(&z, 100) == 0 { t.Errorf("testLoadStoreOrder failed") } } //go:noinline func testLoadStoreOrder_ssa(z *uint32, prec uint) int { old := *z // load *z = uint32(prec) // store if *z < old { // load return 1 } return 0 } func testStoreSize(t *testing.T) { a := [4]uint16{11, 22, 33, 44} testStoreSize_ssa(&a[0], &a[2], 77) want := [4]uint16{77, 22, 33, 44} if a != want { t.Errorf("testStoreSize failed. want = %d, got = %d", want, a) } } //go:noinline func testStoreSize_ssa(p *uint16, q *uint16, v uint32) { // Test to make sure that (Store ptr (Trunc32to16 val) mem) // does not end up as a 32-bit store. It must stay a 16 bit store // even when Trunc32to16 is rewritten to be a nop. // To ensure that we get rewrite the Trunc32to16 before // we rewrite the Store, we force the truncate into an // earlier basic block by using it on both branches. w := uint16(v) if p != nil { *p = w } else { *q = w } } //go:noinline func testExtStore_ssa(p *byte, b bool) int { x := *p *p = 7 if b { return int(x) } return 0 } func testExtStore(t *testing.T) { const start = 8 var b byte = start if got := testExtStore_ssa(&b, true); got != start { t.Errorf("testExtStore failed. want = %d, got = %d", start, got) } } var b int // testDeadStorePanic_ssa ensures that we don't optimize away stores // that could be read by after recover(). Modeled after fixedbugs/issue1304. //go:noinline func testDeadStorePanic_ssa(a int) (r int) { defer func() { recover() r = a }() a = 2 // store b := a - a // optimized to zero c := 4 a = c / b // store, but panics a = 3 // store r = a return } func testDeadStorePanic(t *testing.T) { if want, got := 2, testDeadStorePanic_ssa(1); want != got { t.Errorf("testDeadStorePanic failed. want = %d, got = %d", want, got) } } //go:noinline func loadHitStore8(x int8, p *int8) int32 { x *= x // try to trash high bits (arch-dependent) *p = x // store return int32(*p) // load and cast } //go:noinline func loadHitStoreU8(x uint8, p *uint8) uint32 { x *= x // try to trash high bits (arch-dependent) *p = x // store return uint32(*p) // load and cast } //go:noinline func loadHitStore16(x int16, p *int16) int32 { x *= x // try to trash high bits (arch-dependent) *p = x // store return int32(*p) // load and cast } //go:noinline func loadHitStoreU16(x uint16, p *uint16) uint32 { x *= x // try to trash high bits (arch-dependent) *p = x // store return uint32(*p) // load and cast } //go:noinline func loadHitStore32(x int32, p *int32) int64 { x *= x // try to trash high bits (arch-dependent) *p = x // store return int64(*p) // load and cast } //go:noinline func loadHitStoreU32(x uint32, p *uint32) uint64 { x *= x // try to trash high bits (arch-dependent) *p = x // store return uint64(*p) // load and cast } func testLoadHitStore(t *testing.T) { // Test that sign/zero extensions are kept when a load-hit-store // is replaced by a register-register move. { var in int8 = (1 << 6) + 1 var p int8 got := loadHitStore8(in, &p) want := int32(in * in) if got != want { t.Errorf("testLoadHitStore (int8) failed. want = %d, got = %d", want, got) } } { var in uint8 = (1 << 6) + 1 var p uint8 got := loadHitStoreU8(in, &p) want := uint32(in * in) if got != want { t.Errorf("testLoadHitStore (uint8) failed. want = %d, got = %d", want, got) } } { var in int16 = (1 << 10) + 1 var p int16 got := loadHitStore16(in, &p) want := int32(in * in) if got != want { t.Errorf("testLoadHitStore (int16) failed. want = %d, got = %d", want, got) } } { var in uint16 = (1 << 10) + 1 var p uint16 got := loadHitStoreU16(in, &p) want := uint32(in * in) if got != want { t.Errorf("testLoadHitStore (uint16) failed. want = %d, got = %d", want, got) } } { var in int32 = (1 << 30) + 1 var p int32 got := loadHitStore32(in, &p) want := int64(in * in) if got != want { t.Errorf("testLoadHitStore (int32) failed. want = %d, got = %d", want, got) } } { var in uint32 = (1 << 30) + 1 var p uint32 got := loadHitStoreU32(in, &p) want := uint64(in * in) if got != want { t.Errorf("testLoadHitStore (uint32) failed. want = %d, got = %d", want, got) } } } func TestLoadStore(t *testing.T) { testLoadStoreOrder(t) testStoreSize(t) testExtStore(t) testDeadStorePanic(t) testLoadHitStore(t) }