github.com/wasilibs/wazerox@v0.0.0-20240124024944-4923be63ab5f/internal/engine/wazevo/backend/isa/arm64/machine_pro_epi_logue_test.go (about) 1 package arm64 2 3 import ( 4 "testing" 5 6 "github.com/wasilibs/wazerox/internal/engine/wazevo/backend/regalloc" 7 "github.com/wasilibs/wazerox/internal/testing/require" 8 ) 9 10 func TestMachine_SetupPrologue(t *testing.T) { 11 for _, tc := range []struct { 12 spillSlotSize int64 13 clobberedRegs []regalloc.VReg 14 exp string 15 abi abiImpl 16 }{ 17 { 18 spillSlotSize: 0, 19 exp: ` 20 stp x30, xzr, [sp, #-0x10]! 21 str xzr, [sp, #-0x10]! 22 udf 23 `, 24 }, 25 { 26 spillSlotSize: 0, 27 abi: abiImpl{argStackSize: 16, retStackSize: 16}, 28 exp: ` 29 orr x27, xzr, #0x20 30 sub sp, sp, x27 31 stp x30, x27, [sp, #-0x10]! 32 str xzr, [sp, #-0x10]! 33 udf 34 `, 35 }, 36 { 37 spillSlotSize: 16, 38 exp: ` 39 stp x30, xzr, [sp, #-0x10]! 40 sub sp, sp, #0x10 41 orr x27, xzr, #0x10 42 str x27, [sp, #-0x10]! 43 udf 44 `, 45 }, 46 { 47 spillSlotSize: 0, 48 clobberedRegs: []regalloc.VReg{v18VReg, v19VReg, x18VReg, x25VReg}, 49 exp: ` 50 stp x30, xzr, [sp, #-0x10]! 51 str q18, [sp, #-0x10]! 52 str q19, [sp, #-0x10]! 53 str x18, [sp, #-0x10]! 54 str x25, [sp, #-0x10]! 55 orr x27, xzr, #0x40 56 str x27, [sp, #-0x10]! 57 udf 58 `, 59 }, 60 { 61 spillSlotSize: 320, 62 clobberedRegs: []regalloc.VReg{v18VReg, v19VReg, x18VReg, x25VReg}, 63 exp: ` 64 stp x30, xzr, [sp, #-0x10]! 65 str q18, [sp, #-0x10]! 66 str q19, [sp, #-0x10]! 67 str x18, [sp, #-0x10]! 68 str x25, [sp, #-0x10]! 69 sub sp, sp, #0x140 70 orr x27, xzr, #0x180 71 str x27, [sp, #-0x10]! 72 udf 73 `, 74 }, 75 { 76 spillSlotSize: 320, 77 abi: abiImpl{argStackSize: 320, retStackSize: 160}, 78 clobberedRegs: []regalloc.VReg{v18VReg, v19VReg, x18VReg, x25VReg}, 79 exp: ` 80 orr x27, xzr, #0x1e0 81 sub sp, sp, x27 82 stp x30, x27, [sp, #-0x10]! 83 str q18, [sp, #-0x10]! 84 str q19, [sp, #-0x10]! 85 str x18, [sp, #-0x10]! 86 str x25, [sp, #-0x10]! 87 sub sp, sp, #0x140 88 orr x27, xzr, #0x180 89 str x27, [sp, #-0x10]! 90 udf 91 `, 92 }, 93 } { 94 tc := tc 95 t.Run(tc.exp, func(t *testing.T) { 96 _, _, m := newSetupWithMockContext() 97 m.DisableStackCheck() 98 m.spillSlotSize = tc.spillSlotSize 99 m.clobberedRegs = tc.clobberedRegs 100 m.currentABI = &tc.abi 101 102 root := m.allocateNop() 103 m.rootInstr = root 104 udf := m.allocateInstr() 105 udf.asUDF() 106 root.next = udf 107 udf.prev = root 108 109 m.SetupPrologue() 110 require.Equal(t, root, m.rootInstr) 111 m.Encode() 112 require.Equal(t, tc.exp, m.Format()) 113 }) 114 } 115 } 116 117 func TestMachine_SetupEpilogue(t *testing.T) { 118 for _, tc := range []struct { 119 exp string 120 abi abiImpl 121 clobberedRegs []regalloc.VReg 122 spillSlotSize int64 123 }{ 124 { 125 exp: ` 126 add sp, sp, #0x10 127 ldr x30, [sp], #0x10 128 ret 129 `, 130 spillSlotSize: 0, 131 clobberedRegs: nil, 132 }, 133 { 134 exp: ` 135 add sp, sp, #0x10 136 add sp, sp, #0x50 137 ldr x30, [sp], #0x10 138 ret 139 `, 140 spillSlotSize: 16 * 5, 141 clobberedRegs: nil, 142 }, 143 { 144 exp: ` 145 add sp, sp, #0x10 146 add sp, sp, #0x50 147 ldr x30, [sp], #0x10 148 add sp, sp, #0x20 149 ret 150 `, 151 abi: abiImpl{argStackSize: 16, retStackSize: 16}, 152 spillSlotSize: 16 * 5, 153 clobberedRegs: nil, 154 }, 155 { 156 exp: ` 157 add sp, sp, #0x10 158 ldr q27, [sp], #0x10 159 ldr q18, [sp], #0x10 160 ldr x30, [sp], #0x10 161 ret 162 `, 163 clobberedRegs: []regalloc.VReg{v18VReg, v27VReg}, 164 }, 165 { 166 exp: ` 167 add sp, sp, #0x10 168 ldr x25, [sp], #0x10 169 ldr x18, [sp], #0x10 170 ldr q27, [sp], #0x10 171 ldr q18, [sp], #0x10 172 ldr x30, [sp], #0x10 173 ret 174 `, 175 clobberedRegs: []regalloc.VReg{v18VReg, v27VReg, x18VReg, x25VReg}, 176 }, 177 { 178 exp: ` 179 add sp, sp, #0x10 180 add sp, sp, #0xa0 181 ldr x25, [sp], #0x10 182 ldr x18, [sp], #0x10 183 ldr q27, [sp], #0x10 184 ldr q18, [sp], #0x10 185 ldr x30, [sp], #0x10 186 ret 187 `, 188 spillSlotSize: 16 * 10, 189 clobberedRegs: []regalloc.VReg{v18VReg, v27VReg, x18VReg, x25VReg}, 190 }, 191 { 192 exp: ` 193 add sp, sp, #0x10 194 add sp, sp, #0xa0 195 ldr x25, [sp], #0x10 196 ldr x18, [sp], #0x10 197 ldr q27, [sp], #0x10 198 ldr q18, [sp], #0x10 199 ldr x30, [sp], #0x10 200 add sp, sp, #0x150 201 ret 202 `, 203 spillSlotSize: 16 * 10, 204 abi: abiImpl{argStackSize: 16, retStackSize: 320}, 205 clobberedRegs: []regalloc.VReg{v18VReg, v27VReg, x18VReg, x25VReg}, 206 }, 207 } { 208 tc := tc 209 t.Run(tc.exp, func(t *testing.T) { 210 _, _, m := newSetupWithMockContext() 211 m.spillSlotSize = tc.spillSlotSize 212 m.clobberedRegs = tc.clobberedRegs 213 m.currentABI = &tc.abi 214 215 root := m.allocateNop() 216 m.rootInstr = root 217 ret := m.allocateInstr() 218 ret.asRet(nil) 219 root.next = ret 220 ret.prev = root 221 m.SetupEpilogue() 222 223 require.Equal(t, root, m.rootInstr) 224 m.Encode() 225 require.Equal(t, tc.exp, m.Format()) 226 }) 227 } 228 } 229 230 func TestMachine_insertStackBoundsCheck(t *testing.T) { 231 for _, tc := range []struct { 232 exp string 233 requiredStackSize int64 234 }{ 235 { 236 requiredStackSize: 0xfff_0, 237 exp: ` 238 movz x27, #0xfff0, lsl 0 239 sub x27, sp, x27 240 ldr x11, [x0, #0x28] 241 subs xzr, x27, x11 242 b.ge #0x14 243 movz x27, #0xfff0, lsl 0 244 str x27, [x0, #0x40] 245 ldr x27, [x0, #0x50] 246 bl x27 247 `, 248 }, 249 { 250 requiredStackSize: 0x10, 251 exp: ` 252 sub x27, sp, #0x10 253 ldr x11, [x0, #0x28] 254 subs xzr, x27, x11 255 b.ge #0x14 256 orr x27, xzr, #0x10 257 str x27, [x0, #0x40] 258 ldr x27, [x0, #0x50] 259 bl x27 260 `, 261 }, 262 } { 263 tc := tc 264 t.Run(tc.exp, func(t *testing.T) { 265 _, _, m := newSetupWithMockContext() 266 m.rootInstr = m.allocateInstr() 267 m.rootInstr.asNop0() 268 m.insertStackBoundsCheck(tc.requiredStackSize, m.rootInstr) 269 m.Encode() 270 require.Equal(t, tc.exp, m.Format()) 271 }) 272 } 273 } 274 275 func TestMachine_CompileStackGrowCallSequence(t *testing.T) { 276 _, _, m := newSetupWithMockContext() 277 _ = m.CompileStackGrowCallSequence() 278 279 require.Equal(t, ` 280 str x1, [x0, #0x60] 281 str x2, [x0, #0x70] 282 str x3, [x0, #0x80] 283 str x4, [x0, #0x90] 284 str x5, [x0, #0xa0] 285 str x6, [x0, #0xb0] 286 str x7, [x0, #0xc0] 287 str x19, [x0, #0xd0] 288 str x20, [x0, #0xe0] 289 str x21, [x0, #0xf0] 290 str x22, [x0, #0x100] 291 str x23, [x0, #0x110] 292 str x24, [x0, #0x120] 293 str x25, [x0, #0x130] 294 str x26, [x0, #0x140] 295 str x28, [x0, #0x150] 296 str x30, [x0, #0x160] 297 str q0, [x0, #0x170] 298 str q1, [x0, #0x180] 299 str q2, [x0, #0x190] 300 str q3, [x0, #0x1a0] 301 str q4, [x0, #0x1b0] 302 str q5, [x0, #0x1c0] 303 str q6, [x0, #0x1d0] 304 str q7, [x0, #0x1e0] 305 str q18, [x0, #0x1f0] 306 str q19, [x0, #0x200] 307 str q20, [x0, #0x210] 308 str q21, [x0, #0x220] 309 str q22, [x0, #0x230] 310 str q23, [x0, #0x240] 311 str q24, [x0, #0x250] 312 str q25, [x0, #0x260] 313 str q26, [x0, #0x270] 314 str q27, [x0, #0x280] 315 str q28, [x0, #0x290] 316 str q29, [x0, #0x2a0] 317 str q30, [x0, #0x2b0] 318 str q31, [x0, #0x2c0] 319 mov x27, sp 320 str x27, [x0, #0x38] 321 orr w17, wzr, #0x1 322 str w17, [x0] 323 adr x27, #0x20 324 str x27, [x0, #0x30] 325 exit_sequence x0 326 ldr x1, [x0, #0x60] 327 ldr x2, [x0, #0x70] 328 ldr x3, [x0, #0x80] 329 ldr x4, [x0, #0x90] 330 ldr x5, [x0, #0xa0] 331 ldr x6, [x0, #0xb0] 332 ldr x7, [x0, #0xc0] 333 ldr x19, [x0, #0xd0] 334 ldr x20, [x0, #0xe0] 335 ldr x21, [x0, #0xf0] 336 ldr x22, [x0, #0x100] 337 ldr x23, [x0, #0x110] 338 ldr x24, [x0, #0x120] 339 ldr x25, [x0, #0x130] 340 ldr x26, [x0, #0x140] 341 ldr x28, [x0, #0x150] 342 ldr x30, [x0, #0x160] 343 ldr q0, [x0, #0x170] 344 ldr q1, [x0, #0x180] 345 ldr q2, [x0, #0x190] 346 ldr q3, [x0, #0x1a0] 347 ldr q4, [x0, #0x1b0] 348 ldr q5, [x0, #0x1c0] 349 ldr q6, [x0, #0x1d0] 350 ldr q7, [x0, #0x1e0] 351 ldr q18, [x0, #0x1f0] 352 ldr q19, [x0, #0x200] 353 ldr q20, [x0, #0x210] 354 ldr q21, [x0, #0x220] 355 ldr q22, [x0, #0x230] 356 ldr q23, [x0, #0x240] 357 ldr q24, [x0, #0x250] 358 ldr q25, [x0, #0x260] 359 ldr q26, [x0, #0x270] 360 ldr q27, [x0, #0x280] 361 ldr q28, [x0, #0x290] 362 ldr q29, [x0, #0x2a0] 363 ldr q30, [x0, #0x2b0] 364 ldr q31, [x0, #0x2c0] 365 ret 366 `, m.Format()) 367 }