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 }