Source file src/cmd/compile/internal/test/memcombine_test.go

     1  // Copyright 2023 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 test
     6  
     7  import (
     8  	"encoding/binary"
     9  	"testing"
    10  )
    11  
    12  var gv = [16]byte{0, 1, 2, 3, 4, 5, 6, 7, 8}
    13  
    14  //go:noinline
    15  func readGlobalUnaligned() uint64 {
    16  	return binary.LittleEndian.Uint64(gv[1:])
    17  }
    18  
    19  func TestUnalignedGlobal(t *testing.T) {
    20  	// Note: this is a test not so much of the result of the read, but of
    21  	// the correct compilation of that read. On s390x unaligned global
    22  	// accesses fail to compile.
    23  	if got, want := readGlobalUnaligned(), uint64(0x0807060504030201); got != want {
    24  		t.Errorf("read global %x, want %x", got, want)
    25  	}
    26  }
    27  
    28  func TestSpillOfExtendedEndianLoads(t *testing.T) {
    29  	b := []byte{0xaa, 0xbb, 0xcc, 0xdd}
    30  
    31  	var testCases = []struct {
    32  		fn   func([]byte) uint64
    33  		want uint64
    34  	}{
    35  		{readUint16le, 0xbbaa},
    36  		{readUint16be, 0xaabb},
    37  		{readUint32le, 0xddccbbaa},
    38  		{readUint32be, 0xaabbccdd},
    39  	}
    40  	for _, test := range testCases {
    41  		if got := test.fn(b); got != test.want {
    42  			t.Errorf("got %x, want %x", got, test.want)
    43  		}
    44  	}
    45  }
    46  
    47  func readUint16le(b []byte) uint64 {
    48  	y := uint64(binary.LittleEndian.Uint16(b))
    49  	nop() // force spill
    50  	return y
    51  }
    52  
    53  func readUint16be(b []byte) uint64 {
    54  	y := uint64(binary.BigEndian.Uint16(b))
    55  	nop() // force spill
    56  	return y
    57  }
    58  
    59  func readUint32le(b []byte) uint64 {
    60  	y := uint64(binary.LittleEndian.Uint32(b))
    61  	nop() // force spill
    62  	return y
    63  }
    64  
    65  func readUint32be(b []byte) uint64 {
    66  	y := uint64(binary.BigEndian.Uint32(b))
    67  	nop() // force spill
    68  	return y
    69  }
    70  
    71  //go:noinline
    72  func nop() {
    73  }
    74  
    75  type T32 struct {
    76  	a, b uint32
    77  }
    78  
    79  //go:noinline
    80  func (t *T32) bigEndianLoad() uint64 {
    81  	return uint64(t.a)<<32 | uint64(t.b)
    82  }
    83  
    84  //go:noinline
    85  func (t *T32) littleEndianLoad() uint64 {
    86  	return uint64(t.a) | (uint64(t.b) << 32)
    87  }
    88  
    89  //go:noinline
    90  func (t *T32) bigEndianStore(x uint64) {
    91  	t.a = uint32(x >> 32)
    92  	t.b = uint32(x)
    93  }
    94  
    95  //go:noinline
    96  func (t *T32) littleEndianStore(x uint64) {
    97  	t.a = uint32(x)
    98  	t.b = uint32(x >> 32)
    99  }
   100  
   101  type T16 struct {
   102  	a, b uint16
   103  }
   104  
   105  //go:noinline
   106  func (t *T16) bigEndianLoad() uint32 {
   107  	return uint32(t.a)<<16 | uint32(t.b)
   108  }
   109  
   110  //go:noinline
   111  func (t *T16) littleEndianLoad() uint32 {
   112  	return uint32(t.a) | (uint32(t.b) << 16)
   113  }
   114  
   115  //go:noinline
   116  func (t *T16) bigEndianStore(x uint32) {
   117  	t.a = uint16(x >> 16)
   118  	t.b = uint16(x)
   119  }
   120  
   121  //go:noinline
   122  func (t *T16) littleEndianStore(x uint32) {
   123  	t.a = uint16(x)
   124  	t.b = uint16(x >> 16)
   125  }
   126  
   127  type T8 struct {
   128  	a, b uint8
   129  }
   130  
   131  //go:noinline
   132  func (t *T8) bigEndianLoad() uint16 {
   133  	return uint16(t.a)<<8 | uint16(t.b)
   134  }
   135  
   136  //go:noinline
   137  func (t *T8) littleEndianLoad() uint16 {
   138  	return uint16(t.a) | (uint16(t.b) << 8)
   139  }
   140  
   141  //go:noinline
   142  func (t *T8) bigEndianStore(x uint16) {
   143  	t.a = uint8(x >> 8)
   144  	t.b = uint8(x)
   145  }
   146  
   147  //go:noinline
   148  func (t *T8) littleEndianStore(x uint16) {
   149  	t.a = uint8(x)
   150  	t.b = uint8(x >> 8)
   151  }
   152  
   153  func TestIssue64468(t *testing.T) {
   154  	t32 := T32{1, 2}
   155  	if got, want := t32.bigEndianLoad(), uint64(1<<32+2); got != want {
   156  		t.Errorf("T32.bigEndianLoad got %x want %x\n", got, want)
   157  	}
   158  	if got, want := t32.littleEndianLoad(), uint64(1+2<<32); got != want {
   159  		t.Errorf("T32.littleEndianLoad got %x want %x\n", got, want)
   160  	}
   161  	t16 := T16{1, 2}
   162  	if got, want := t16.bigEndianLoad(), uint32(1<<16+2); got != want {
   163  		t.Errorf("T16.bigEndianLoad got %x want %x\n", got, want)
   164  	}
   165  	if got, want := t16.littleEndianLoad(), uint32(1+2<<16); got != want {
   166  		t.Errorf("T16.littleEndianLoad got %x want %x\n", got, want)
   167  	}
   168  	t8 := T8{1, 2}
   169  	if got, want := t8.bigEndianLoad(), uint16(1<<8+2); got != want {
   170  		t.Errorf("T8.bigEndianLoad got %x want %x\n", got, want)
   171  	}
   172  	if got, want := t8.littleEndianLoad(), uint16(1+2<<8); got != want {
   173  		t.Errorf("T8.littleEndianLoad got %x want %x\n", got, want)
   174  	}
   175  	t32.bigEndianStore(1<<32 + 2)
   176  	if got, want := t32, (T32{1, 2}); got != want {
   177  		t.Errorf("T32.bigEndianStore got %x want %x\n", got, want)
   178  	}
   179  	t32.littleEndianStore(1<<32 + 2)
   180  	if got, want := t32, (T32{2, 1}); got != want {
   181  		t.Errorf("T32.littleEndianStore got %x want %x\n", got, want)
   182  	}
   183  	t16.bigEndianStore(1<<16 + 2)
   184  	if got, want := t16, (T16{1, 2}); got != want {
   185  		t.Errorf("T16.bigEndianStore got %x want %x\n", got, want)
   186  	}
   187  	t16.littleEndianStore(1<<16 + 2)
   188  	if got, want := t16, (T16{2, 1}); got != want {
   189  		t.Errorf("T16.littleEndianStore got %x want %x\n", got, want)
   190  	}
   191  	t8.bigEndianStore(1<<8 + 2)
   192  	if got, want := t8, (T8{1, 2}); got != want {
   193  		t.Errorf("T8.bigEndianStore got %x want %x\n", got, want)
   194  	}
   195  	t8.littleEndianStore(1<<8 + 2)
   196  	if got, want := t8, (T8{2, 1}); got != want {
   197  		t.Errorf("T8.littleEndianStore got %x want %x\n", got, want)
   198  	}
   199  }
   200  

View as plain text