github.com/tetratelabs/wazero@v1.7.3-0.20240513003603-48f702e154b5/internal/engine/wazevo/backend/isa/amd64/machine_regalloc_test.go (about)

     1  package amd64
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/tetratelabs/wazero/internal/engine/wazevo/backend/regalloc"
     7  	"github.com/tetratelabs/wazero/internal/engine/wazevo/ssa"
     8  	"github.com/tetratelabs/wazero/internal/testing/require"
     9  )
    10  
    11  func TestMachine_InsertStoreRegisterAt(t *testing.T) {
    12  	for _, tc := range []struct {
    13  		spillSlotSize int64
    14  		expected      string
    15  	}{
    16  		{
    17  			spillSlotSize: 16,
    18  			expected: `
    19  	ud2
    20  	movsd %xmm1, 16(%rsp)
    21  	mov.q %rax, 24(%rsp)
    22  	ret
    23  `,
    24  		},
    25  		{
    26  			spillSlotSize: 160,
    27  			expected: `
    28  	ud2
    29  	movsd %xmm1, 160(%rsp)
    30  	mov.q %rax, 168(%rsp)
    31  	ret
    32  `,
    33  		},
    34  	} {
    35  		t.Run(tc.expected, func(t *testing.T) {
    36  			ctx, _, m := newSetupWithMockContext()
    37  			m.spillSlotSize = tc.spillSlotSize
    38  
    39  			for _, after := range []bool{false, true} {
    40  				var name string
    41  				if after {
    42  					name = "after"
    43  				} else {
    44  					name = "before"
    45  				}
    46  				t.Run(name, func(t *testing.T) {
    47  					ctx.typeOf = map[regalloc.VRegID]ssa.Type{
    48  						raxVReg.ID(): ssa.TypeI64, xmm1VReg.ID(): ssa.TypeF64,
    49  					}
    50  					i1, i2 := m.allocateInstr().asUD2(), m.allocateInstr().asRet()
    51  					i1.next = i2
    52  					i2.prev = i1
    53  
    54  					if after {
    55  						m.InsertStoreRegisterAt(raxVReg, i1, after)
    56  						m.InsertStoreRegisterAt(xmm1VReg, i1, after)
    57  					} else {
    58  						m.InsertStoreRegisterAt(xmm1VReg, i2, after)
    59  						m.InsertStoreRegisterAt(raxVReg, i2, after)
    60  					}
    61  					m.ectx.RootInstr = i1
    62  					require.Equal(t, tc.expected, m.Format())
    63  				})
    64  			}
    65  		})
    66  	}
    67  }
    68  
    69  func TestMachine_InsertReloadRegisterAt(t *testing.T) {
    70  	for _, tc := range []struct {
    71  		spillSlotSize int64
    72  		expected      string
    73  	}{
    74  		{
    75  			spillSlotSize: 16,
    76  			expected: `
    77  	ud2
    78  	movq 16(%rsp), %rax
    79  	movdqu 24(%rsp), %xmm1
    80  	ret
    81  `,
    82  		},
    83  		{
    84  			spillSlotSize: 160,
    85  			expected: `
    86  	ud2
    87  	movq 160(%rsp), %rax
    88  	movdqu 168(%rsp), %xmm1
    89  	ret
    90  `,
    91  		},
    92  	} {
    93  		t.Run(tc.expected, func(t *testing.T) {
    94  			ctx, _, m := newSetupWithMockContext()
    95  			m.spillSlotSize = tc.spillSlotSize
    96  
    97  			for _, after := range []bool{false, true} {
    98  				var name string
    99  				if after {
   100  					name = "after"
   101  				} else {
   102  					name = "before"
   103  				}
   104  				t.Run(name, func(t *testing.T) {
   105  					ctx.typeOf = map[regalloc.VRegID]ssa.Type{
   106  						raxVReg.ID(): ssa.TypeI64, xmm1VReg.ID(): ssa.TypeV128,
   107  					}
   108  					i1, i2 := m.allocateInstr().asUD2(), m.allocateInstr().asRet()
   109  					i1.next = i2
   110  					i2.prev = i1
   111  
   112  					if after {
   113  						m.InsertReloadRegisterAt(xmm1VReg, i1, after)
   114  						m.InsertReloadRegisterAt(raxVReg, i1, after)
   115  					} else {
   116  						m.InsertReloadRegisterAt(raxVReg, i2, after)
   117  						m.InsertReloadRegisterAt(xmm1VReg, i2, after)
   118  					}
   119  					m.ectx.RootInstr = i1
   120  					require.Equal(t, tc.expected, m.Format())
   121  				})
   122  			}
   123  		})
   124  	}
   125  }
   126  
   127  func TestMachine_InsertMoveBefore(t *testing.T) {
   128  	for _, tc := range []struct {
   129  		src, dst regalloc.VReg
   130  		expected string
   131  	}{
   132  		{
   133  			src: raxVReg,
   134  			dst: rdxVReg,
   135  			expected: `
   136  	ud2
   137  	movq %rax, %rdx
   138  	ret
   139  `,
   140  		},
   141  		{
   142  			src: xmm1VReg,
   143  			dst: xmm2VReg,
   144  			expected: `
   145  	ud2
   146  	movdqu %xmm1, %xmm2
   147  	ret
   148  `,
   149  		},
   150  	} {
   151  		t.Run(tc.expected, func(t *testing.T) {
   152  			_, _, m := newSetupWithMockContext()
   153  			i1, i2 := m.allocateInstr().asUD2(), m.allocateInstr().asRet()
   154  			i1.next = i2
   155  			i2.prev = i1
   156  
   157  			m.InsertMoveBefore(tc.dst, tc.src, i2)
   158  			m.ectx.RootInstr = i1
   159  			require.Equal(t, tc.expected, m.Format())
   160  		})
   161  	}
   162  }
   163  
   164  func TestMachineSwap(t *testing.T) {
   165  	for _, tc := range []struct {
   166  		x1, x2, tmp regalloc.VReg
   167  		expected    string
   168  	}{
   169  		{
   170  			x1:  r15VReg,
   171  			x2:  raxVReg,
   172  			tmp: rdiVReg,
   173  			expected: `
   174  	ud2
   175  	xchg.q %r15, %rax
   176  	exit_sequence %rsi
   177  `,
   178  		},
   179  		{
   180  			x1: r15VReg,
   181  			x2: raxVReg,
   182  			expected: `
   183  	ud2
   184  	xchg.q %r15, %rax
   185  	exit_sequence %rsi
   186  `,
   187  		},
   188  		{
   189  			x1:  xmm1VReg,
   190  			x2:  xmm12VReg,
   191  			tmp: xmm11VReg,
   192  			expected: `
   193  	ud2
   194  	movdqu %xmm1, %xmm11
   195  	movdqu %xmm12, %xmm1
   196  	movdqu %xmm11, %xmm12
   197  	exit_sequence %rsi
   198  `,
   199  		},
   200  		{
   201  			x1: xmm1VReg,
   202  			x2: xmm12VReg,
   203  			// Tmp not given.
   204  			expected: `
   205  	ud2
   206  	movsd %xmm1, (%rsp)
   207  	movdqa %xmm12, %xmm1
   208  	movsd (%rsp), %xmm12
   209  	exit_sequence %rsi
   210  `,
   211  		},
   212  	} {
   213  		t.Run(tc.expected, func(t *testing.T) {
   214  			ctx, _, m := newSetupWithMockContext()
   215  
   216  			ctx.typeOf = map[regalloc.VRegID]ssa.Type{
   217  				r15VReg.ID(): ssa.TypeI64, raxVReg.ID(): ssa.TypeI64,
   218  				xmm1VReg.ID(): ssa.TypeF64, xmm12VReg.ID(): ssa.TypeF64,
   219  			}
   220  			cur, i2 := m.allocateInstr().asUD2(), m.allocateExitSeq(rsiVReg)
   221  			cur.next = i2
   222  			i2.prev = cur
   223  
   224  			m.Swap(cur, tc.x1, tc.x2, tc.tmp)
   225  			m.ectx.RootInstr = cur
   226  
   227  			require.Equal(t, tc.expected, m.Format())
   228  
   229  			m.encodeWithoutSSA(cur)
   230  		})
   231  	}
   232  }