github.com/tetratelabs/wazero@v1.7.3-0.20240513003603-48f702e154b5/internal/engine/wazevo/backend/isa/amd64/abi_go_call_test.go (about) 1 package amd64 2 3 import ( 4 "context" 5 "sort" 6 "testing" 7 8 "github.com/tetratelabs/wazero/internal/engine/wazevo/backend/regalloc" 9 "github.com/tetratelabs/wazero/internal/engine/wazevo/ssa" 10 "github.com/tetratelabs/wazero/internal/engine/wazevo/wazevoapi" 11 "github.com/tetratelabs/wazero/internal/testing/require" 12 ) 13 14 func Test_calleeSavedVRegs(t *testing.T) { 15 var exp []regalloc.VReg 16 regInfo.CalleeSavedRegisters.Range(func(r regalloc.RealReg) { 17 exp = append(exp, regInfo.RealRegToVReg[r]) 18 }) 19 require.Equal(t, exp, calleeSavedVRegs) 20 } 21 22 func TestMachine_CompileGoFunctionTrampoline(t *testing.T) { 23 for _, tc := range []struct { 24 name string 25 exitCode wazevoapi.ExitCode 26 sig *ssa.Signature 27 needModuleContextPtr bool 28 exp string 29 }{ 30 { 31 name: "go call", 32 exitCode: wazevoapi.ExitCodeCallGoFunctionWithIndex(100, false), 33 sig: &ssa.Signature{ 34 Params: []ssa.Type{ssa.TypeI64, ssa.TypeI64, ssa.TypeF64}, 35 Results: []ssa.Type{ssa.TypeI32, ssa.TypeI64, ssa.TypeF32, ssa.TypeF64}, 36 }, 37 needModuleContextPtr: true, 38 exp: ` 39 pushq %rbp 40 movq %rsp, %rbp 41 sub $40, %rsp 42 cmpq 40(%rax), %rsp 43 jnbe L1 44 add $40, %rsp 45 pushq %r15 46 movabsq $40, %r15 47 mov.q %r15, 64(%rax) 48 popq %r15 49 callq *80(%rax) 50 jmp L2 51 L1: 52 add $40, %rsp 53 L2: 54 mov.q %rdx, 96(%rax) 55 mov.q %r12, 112(%rax) 56 mov.q %r13, 128(%rax) 57 mov.q %r14, 144(%rax) 58 mov.q %r15, 160(%rax) 59 movdqu %xmm8, 176(%rax) 60 movdqu %xmm9, 192(%rax) 61 movdqu %xmm10, 208(%rax) 62 movdqu %xmm11, 224(%rax) 63 movdqu %xmm12, 240(%rax) 64 movdqu %xmm13, 256(%rax) 65 movdqu %xmm14, 272(%rax) 66 movdqu %xmm15, 288(%rax) 67 mov.q %rbx, 1120(%rax) 68 sub $32, %rsp 69 movsd %xmm0, (%rsp) 70 pushq $32 71 movl $25606, %r12d 72 mov.l %r12, (%rax) 73 mov.q %rsp, 56(%rax) 74 mov.q %rbp, 1152(%rax) 75 lea L3, %r12 76 mov.q %r12, 48(%rax) 77 exit_sequence %rax 78 L3: 79 add $8, %rsp 80 movq 8(%rsp), %rbx 81 movss 16(%rsp), %xmm0 82 movsd 24(%rsp), %xmm1 83 movq 96(%rax), %rdx 84 movq 112(%rax), %r12 85 movq 128(%rax), %r13 86 movq 144(%rax), %r14 87 movq 160(%rax), %r15 88 movdqu 176(%rax), %xmm8 89 movdqu 192(%rax), %xmm9 90 movdqu 208(%rax), %xmm10 91 movdqu 224(%rax), %xmm11 92 movdqu 240(%rax), %xmm12 93 movdqu 256(%rax), %xmm13 94 movdqu 272(%rax), %xmm14 95 movdqu 288(%rax), %xmm15 96 movq (%rsp), %rax 97 movq %rbp, %rsp 98 popq %rbp 99 ret 100 `, 101 }, 102 { 103 name: "go call", 104 exitCode: wazevoapi.ExitCodeCallGoFunctionWithIndex(100, false), 105 sig: &ssa.Signature{ 106 Params: []ssa.Type{ssa.TypeI64, ssa.TypeI64, ssa.TypeF64, ssa.TypeF64, ssa.TypeI32, ssa.TypeI32}, 107 Results: []ssa.Type{}, 108 }, 109 needModuleContextPtr: true, 110 exp: ` 111 pushq %rbp 112 movq %rsp, %rbp 113 sub $40, %rsp 114 cmpq 40(%rax), %rsp 115 jnbe L1 116 add $40, %rsp 117 pushq %r15 118 movabsq $40, %r15 119 mov.q %r15, 64(%rax) 120 popq %r15 121 callq *80(%rax) 122 jmp L2 123 L1: 124 add $40, %rsp 125 L2: 126 mov.q %rdx, 96(%rax) 127 mov.q %r12, 112(%rax) 128 mov.q %r13, 128(%rax) 129 mov.q %r14, 144(%rax) 130 mov.q %r15, 160(%rax) 131 movdqu %xmm8, 176(%rax) 132 movdqu %xmm9, 192(%rax) 133 movdqu %xmm10, 208(%rax) 134 movdqu %xmm11, 224(%rax) 135 movdqu %xmm12, 240(%rax) 136 movdqu %xmm13, 256(%rax) 137 movdqu %xmm14, 272(%rax) 138 movdqu %xmm15, 288(%rax) 139 mov.q %rbx, 1120(%rax) 140 sub $32, %rsp 141 movsd %xmm0, (%rsp) 142 movsd %xmm1, 8(%rsp) 143 mov.l %rcx, 16(%rsp) 144 mov.l %rdi, 24(%rsp) 145 pushq $32 146 movl $25606, %r12d 147 mov.l %r12, (%rax) 148 mov.q %rsp, 56(%rax) 149 mov.q %rbp, 1152(%rax) 150 lea L3, %r12 151 mov.q %r12, 48(%rax) 152 exit_sequence %rax 153 L3: 154 add $8, %rsp 155 movq 96(%rax), %rdx 156 movq 112(%rax), %r12 157 movq 128(%rax), %r13 158 movq 144(%rax), %r14 159 movq 160(%rax), %r15 160 movdqu 176(%rax), %xmm8 161 movdqu 192(%rax), %xmm9 162 movdqu 208(%rax), %xmm10 163 movdqu 224(%rax), %xmm11 164 movdqu 240(%rax), %xmm12 165 movdqu 256(%rax), %xmm13 166 movdqu 272(%rax), %xmm14 167 movdqu 288(%rax), %xmm15 168 movq %rbp, %rsp 169 popq %rbp 170 ret 171 `, 172 }, 173 { 174 name: "grow memory", 175 exitCode: wazevoapi.ExitCodeGrowMemory, 176 sig: &ssa.Signature{ 177 Params: []ssa.Type{ssa.TypeI32, ssa.TypeI32}, 178 Results: []ssa.Type{ssa.TypeI32}, 179 }, 180 exp: ` 181 pushq %rbp 182 movq %rsp, %rbp 183 sub $24, %rsp 184 cmpq 40(%rax), %rsp 185 jnbe L1 186 add $24, %rsp 187 pushq %r15 188 movabsq $24, %r15 189 mov.q %r15, 64(%rax) 190 popq %r15 191 callq *80(%rax) 192 jmp L2 193 L1: 194 add $24, %rsp 195 L2: 196 mov.q %rdx, 96(%rax) 197 mov.q %r12, 112(%rax) 198 mov.q %r13, 128(%rax) 199 mov.q %r14, 144(%rax) 200 mov.q %r15, 160(%rax) 201 movdqu %xmm8, 176(%rax) 202 movdqu %xmm9, 192(%rax) 203 movdqu %xmm10, 208(%rax) 204 movdqu %xmm11, 224(%rax) 205 movdqu %xmm12, 240(%rax) 206 movdqu %xmm13, 256(%rax) 207 movdqu %xmm14, 272(%rax) 208 movdqu %xmm15, 288(%rax) 209 sub $16, %rsp 210 mov.l %rbx, (%rsp) 211 pushq $8 212 movl $2, %r12d 213 mov.l %r12, (%rax) 214 mov.q %rsp, 56(%rax) 215 mov.q %rbp, 1152(%rax) 216 lea L3, %r12 217 mov.q %r12, 48(%rax) 218 exit_sequence %rax 219 L3: 220 add $8, %rsp 221 movq 96(%rax), %rdx 222 movq 112(%rax), %r12 223 movq 128(%rax), %r13 224 movq 144(%rax), %r14 225 movq 160(%rax), %r15 226 movdqu 176(%rax), %xmm8 227 movdqu 192(%rax), %xmm9 228 movdqu 208(%rax), %xmm10 229 movdqu 224(%rax), %xmm11 230 movdqu 240(%rax), %xmm12 231 movdqu 256(%rax), %xmm13 232 movdqu 272(%rax), %xmm14 233 movdqu 288(%rax), %xmm15 234 movq (%rsp), %rax 235 movq %rbp, %rsp 236 popq %rbp 237 ret 238 `, 239 }, 240 { 241 name: "many", 242 exitCode: wazevoapi.ExitCodeCallGoFunctionWithIndex(100, false), 243 sig: &ssa.Signature{ 244 Params: []ssa.Type{ 245 ssa.TypeI64, ssa.TypeI64, ssa.TypeF64, 246 ssa.TypeF64, ssa.TypeV128, ssa.TypeI32, ssa.TypeI64, ssa.TypeF32, 247 ssa.TypeF64, ssa.TypeV128, ssa.TypeI32, ssa.TypeI64, ssa.TypeF32, 248 ssa.TypeF64, ssa.TypeV128, ssa.TypeI32, ssa.TypeI64, ssa.TypeF32, 249 }, 250 Results: []ssa.Type{ 251 ssa.TypeF64, ssa.TypeV128, ssa.TypeI32, ssa.TypeI64, ssa.TypeF32, 252 ssa.TypeF64, ssa.TypeV128, ssa.TypeI32, ssa.TypeI64, ssa.TypeF32, 253 ssa.TypeF64, ssa.TypeV128, ssa.TypeI32, ssa.TypeI64, ssa.TypeF32, 254 ssa.TypeF64, ssa.TypeV128, ssa.TypeI32, ssa.TypeI64, ssa.TypeF32, 255 ssa.TypeF64, ssa.TypeV128, ssa.TypeI32, ssa.TypeI64, ssa.TypeF32, 256 }, 257 }, 258 exp: ` 259 pushq %rbp 260 movq %rsp, %rbp 261 sub $248, %rsp 262 cmpq 40(%rax), %rsp 263 jnbe L1 264 add $248, %rsp 265 pushq %r15 266 movabsq $248, %r15 267 mov.q %r15, 64(%rax) 268 popq %r15 269 callq *80(%rax) 270 jmp L2 271 L1: 272 add $248, %rsp 273 L2: 274 mov.q %rdx, 96(%rax) 275 mov.q %r12, 112(%rax) 276 mov.q %r13, 128(%rax) 277 mov.q %r14, 144(%rax) 278 mov.q %r15, 160(%rax) 279 movdqu %xmm8, 176(%rax) 280 movdqu %xmm9, 192(%rax) 281 movdqu %xmm10, 208(%rax) 282 movdqu %xmm11, 224(%rax) 283 movdqu %xmm12, 240(%rax) 284 movdqu %xmm13, 256(%rax) 285 movdqu %xmm14, 272(%rax) 286 movdqu %xmm15, 288(%rax) 287 mov.q %rbx, 1120(%rax) 288 sub $240, %rsp 289 movsd %xmm0, (%rsp) 290 movsd %xmm1, 8(%rsp) 291 movdqu %xmm2, 16(%rsp) 292 mov.l %rcx, 32(%rsp) 293 mov.q %rdi, 40(%rsp) 294 movss %xmm3, 48(%rsp) 295 movsd %xmm4, 56(%rsp) 296 movdqu %xmm5, 64(%rsp) 297 mov.l %rsi, 80(%rsp) 298 mov.q %r8, 88(%rsp) 299 movss %xmm6, 96(%rsp) 300 movsd %xmm7, 104(%rsp) 301 movdqu 16(%rbp), %xmm15 302 movdqu %xmm15, 112(%rsp) 303 mov.l %r9, 128(%rsp) 304 mov.q %r10, 136(%rsp) 305 movss 32(%rbp), %xmm15 306 movss %xmm15, 144(%rsp) 307 pushq $240 308 movl $25606, %r12d 309 mov.l %r12, (%rax) 310 mov.q %rsp, 56(%rax) 311 mov.q %rbp, 1152(%rax) 312 lea L3, %r12 313 mov.q %r12, 48(%rax) 314 exit_sequence %rax 315 L3: 316 add $8, %rsp 317 movsd (%rsp), %xmm0 318 movdqu 8(%rsp), %xmm1 319 movq 32(%rsp), %rbx 320 movss 40(%rsp), %xmm2 321 movsd 48(%rsp), %xmm3 322 movdqu 56(%rsp), %xmm4 323 movzx.lq 72(%rsp), %rcx 324 movq 80(%rsp), %rdi 325 movss 88(%rsp), %xmm5 326 movsd 96(%rsp), %xmm6 327 movdqu 104(%rsp), %xmm7 328 movzx.lq 120(%rsp), %rsi 329 movq 128(%rsp), %r8 330 movss 136(%rsp), %xmm15 331 movss %xmm15, 40(%rbp) 332 movsd 144(%rsp), %xmm15 333 movsd %xmm15, 48(%rbp) 334 movdqu 152(%rsp), %xmm15 335 movdqu %xmm15, 56(%rbp) 336 movzx.lq 168(%rsp), %r9 337 movq 176(%rsp), %r10 338 movss 184(%rsp), %xmm15 339 movss %xmm15, 72(%rbp) 340 movsd 192(%rsp), %xmm15 341 movsd %xmm15, 80(%rbp) 342 movdqu 200(%rsp), %xmm15 343 movdqu %xmm15, 88(%rbp) 344 movzx.lq 216(%rsp), %r11 345 movq 224(%rsp), %r15 346 mov.q %r15, 104(%rbp) 347 movss 232(%rsp), %xmm15 348 movss %xmm15, 112(%rbp) 349 movq 96(%rax), %rdx 350 movq 112(%rax), %r12 351 movq 128(%rax), %r13 352 movq 144(%rax), %r14 353 movq 160(%rax), %r15 354 movdqu 176(%rax), %xmm8 355 movdqu 192(%rax), %xmm9 356 movdqu 208(%rax), %xmm10 357 movdqu 224(%rax), %xmm11 358 movdqu 240(%rax), %xmm12 359 movdqu 256(%rax), %xmm13 360 movdqu 272(%rax), %xmm14 361 movdqu 288(%rax), %xmm15 362 movq 24(%rsp), %rax 363 movq %rbp, %rsp 364 popq %rbp 365 ret 366 `, 367 needModuleContextPtr: true, 368 }, 369 } { 370 t.Run(tc.name, func(t *testing.T) { 371 _, _, m := newSetupWithMockContext() 372 m.CompileGoFunctionTrampoline(tc.exitCode, tc.sig, tc.needModuleContextPtr) 373 require.Equal(t, tc.exp, m.Format()) 374 err := m.Encode(context.Background()) 375 require.NoError(t, err) 376 }) 377 } 378 } 379 380 func Test_stackGrowSaveVRegs(t *testing.T) { 381 var exp []regalloc.VReg 382 for _, rs := range regInfo.AllocatableRegisters { 383 for _, r := range rs { 384 if r != rsp && r != rbp && r != rax { 385 exp = append(exp, regInfo.RealRegToVReg[r]) 386 } 387 } 388 } 389 // Copy stackGrowSaveVRegs to avoid modifying the original. 390 var actual []regalloc.VReg 391 actual = append(actual, stackGrowSaveVRegs...) 392 sort.Slice(exp, func(i, j int) bool { return exp[i].ID() < exp[j].ID() }) 393 sort.Slice(actual, func(i, j int) bool { return actual[i].ID() < actual[j].ID() }) 394 require.Equal(t, exp, actual) 395 } 396 397 func TestMachine_CompileStackGrowCallSequence(t *testing.T) { 398 _, _, m := newSetupWithMockContext() 399 _ = m.CompileStackGrowCallSequence() 400 401 require.Equal(t, ` 402 pushq %rbp 403 movq %rsp, %rbp 404 mov.q %rdx, 96(%rax) 405 mov.q %r12, 112(%rax) 406 mov.q %r13, 128(%rax) 407 mov.q %r14, 144(%rax) 408 mov.q %r15, 160(%rax) 409 mov.q %rcx, 176(%rax) 410 mov.q %rbx, 192(%rax) 411 mov.q %rsi, 208(%rax) 412 mov.q %rdi, 224(%rax) 413 mov.q %r8, 240(%rax) 414 mov.q %r9, 256(%rax) 415 mov.q %r10, 272(%rax) 416 mov.q %r11, 288(%rax) 417 movdqu %xmm8, 304(%rax) 418 movdqu %xmm9, 320(%rax) 419 movdqu %xmm10, 336(%rax) 420 movdqu %xmm11, 352(%rax) 421 movdqu %xmm12, 368(%rax) 422 movdqu %xmm13, 384(%rax) 423 movdqu %xmm14, 400(%rax) 424 movdqu %xmm15, 416(%rax) 425 movdqu %xmm0, 432(%rax) 426 movdqu %xmm1, 448(%rax) 427 movdqu %xmm2, 464(%rax) 428 movdqu %xmm3, 480(%rax) 429 movdqu %xmm4, 496(%rax) 430 movdqu %xmm5, 512(%rax) 431 movdqu %xmm6, 528(%rax) 432 movdqu %xmm7, 544(%rax) 433 movl $1, %r12d 434 mov.l %r12, (%rax) 435 mov.q %rsp, 56(%rax) 436 mov.q %rbp, 1152(%rax) 437 lea L1, %r12 438 mov.q %r12, 48(%rax) 439 exit_sequence %rax 440 L1: 441 movq 96(%rax), %rdx 442 movq 112(%rax), %r12 443 movq 128(%rax), %r13 444 movq 144(%rax), %r14 445 movq 160(%rax), %r15 446 movq 176(%rax), %rcx 447 movq 192(%rax), %rbx 448 movq 208(%rax), %rsi 449 movq 224(%rax), %rdi 450 movq 240(%rax), %r8 451 movq 256(%rax), %r9 452 movq 272(%rax), %r10 453 movq 288(%rax), %r11 454 movdqu 304(%rax), %xmm8 455 movdqu 320(%rax), %xmm9 456 movdqu 336(%rax), %xmm10 457 movdqu 352(%rax), %xmm11 458 movdqu 368(%rax), %xmm12 459 movdqu 384(%rax), %xmm13 460 movdqu 400(%rax), %xmm14 461 movdqu 416(%rax), %xmm15 462 movdqu 432(%rax), %xmm0 463 movdqu 448(%rax), %xmm1 464 movdqu 464(%rax), %xmm2 465 movdqu 480(%rax), %xmm3 466 movdqu 496(%rax), %xmm4 467 movdqu 512(%rax), %xmm5 468 movdqu 528(%rax), %xmm6 469 movdqu 544(%rax), %xmm7 470 movq %rbp, %rsp 471 popq %rbp 472 ret 473 `, m.Format()) 474 } 475 476 func TestMachine_insertStackBoundsCheck(t *testing.T) { 477 for _, tc := range []struct { 478 exp string 479 requiredStackSize int64 480 }{ 481 { 482 requiredStackSize: 0x1000, 483 exp: ` 484 sub $4096, %rsp 485 cmpq 40(%rax), %rsp 486 jnbe L1 487 add $4096, %rsp 488 pushq %r15 489 movabsq $4096, %r15 490 mov.q %r15, 64(%rax) 491 popq %r15 492 callq *80(%rax) 493 jmp L2 494 L1: 495 add $4096, %rsp 496 L2: 497 `, 498 }, 499 { 500 requiredStackSize: 0x10, 501 exp: ` 502 sub $16, %rsp 503 cmpq 40(%rax), %rsp 504 jnbe L1 505 add $16, %rsp 506 pushq %r15 507 movabsq $16, %r15 508 mov.q %r15, 64(%rax) 509 popq %r15 510 callq *80(%rax) 511 jmp L2 512 L1: 513 add $16, %rsp 514 L2: 515 `, 516 }, 517 } { 518 tc := tc 519 t.Run(tc.exp, func(t *testing.T) { 520 _, _, m := newSetupWithMockContext() 521 m.ectx.RootInstr = m.allocateNop() 522 m.insertStackBoundsCheck(tc.requiredStackSize, m.ectx.RootInstr) 523 err := m.Encode(context.Background()) 524 require.NoError(t, err) 525 require.Equal(t, tc.exp, m.Format()) 526 }) 527 } 528 }