github.com/tetratelabs/wazero@v1.7.3-0.20240513003603-48f702e154b5/internal/engine/wazevo/backend/isa/arm64/abi_go_call_test.go (about) 1 package arm64 2 3 import ( 4 "context" 5 "sort" 6 "testing" 7 8 "github.com/tetratelabs/wazero/internal/engine/wazevo/backend" 9 "github.com/tetratelabs/wazero/internal/engine/wazevo/backend/regalloc" 10 "github.com/tetratelabs/wazero/internal/engine/wazevo/ssa" 11 "github.com/tetratelabs/wazero/internal/engine/wazevo/wazevoapi" 12 "github.com/tetratelabs/wazero/internal/testing/require" 13 ) 14 15 func Test_calleeSavedRegistersSorted(t *testing.T) { 16 var exp []regalloc.VReg 17 regInfo.CalleeSavedRegisters.Range(func(r regalloc.RealReg) { 18 exp = append(exp, regInfo.RealRegToVReg[r]) 19 }) 20 sort.Slice(exp, func(i, j int) bool { 21 return exp[i].RealReg() < exp[j].RealReg() 22 }) 23 24 require.Equal(t, exp, calleeSavedRegistersSorted) 25 } 26 27 func TestMachine_CompileGoFunctionTrampoline(t *testing.T) { 28 for _, tc := range []struct { 29 name string 30 exitCode wazevoapi.ExitCode 31 sig *ssa.Signature 32 needModuleContextPtr bool 33 exp string 34 }{ 35 { 36 name: "listener", 37 exitCode: wazevoapi.ExitCodeCallListenerBefore, 38 needModuleContextPtr: true, 39 sig: &ssa.Signature{ 40 Params: []ssa.Type{ 41 ssa.TypeI64, ssa.TypeI64, ssa.TypeV128, ssa.TypeF32, ssa.TypeV128, 42 ssa.TypeI64, ssa.TypeI64, ssa.TypeV128, ssa.TypeF32, ssa.TypeV128, 43 ssa.TypeI64, ssa.TypeI64, ssa.TypeV128, ssa.TypeF32, ssa.TypeV128, 44 ssa.TypeI64, ssa.TypeI64, ssa.TypeV128, ssa.TypeF32, ssa.TypeV128, 45 }, 46 Results: []ssa.Type{ 47 ssa.TypeV128, ssa.TypeI32, ssa.TypeI64, ssa.TypeV128, ssa.TypeF32, 48 ssa.TypeV128, ssa.TypeI32, ssa.TypeI64, ssa.TypeV128, ssa.TypeF32, 49 ssa.TypeV128, ssa.TypeI32, ssa.TypeI64, ssa.TypeV128, ssa.TypeF32, 50 ssa.TypeV128, ssa.TypeI32, ssa.TypeI64, ssa.TypeV128, ssa.TypeF32, 51 ssa.TypeV128, ssa.TypeI32, ssa.TypeI64, ssa.TypeV128, ssa.TypeF32, 52 }, 53 }, 54 exp: ` 55 movz x27, #0xa0, lsl 0 56 sub sp, sp, x27 57 stp x30, x27, [sp, #-0x10]! 58 sub x27, sp, #0x130 59 ldr x11, [x0, #0x28] 60 subs xzr, x27, x11 61 b.ge #0x14 62 movz x27, #0x130, lsl 0 63 str x27, [x0, #0x40] 64 ldr x27, [x0, #0x50] 65 bl x27 66 add x17, sp, #0x10 67 str x19, [x0, #0x60] 68 str x20, [x0, #0x70] 69 str x21, [x0, #0x80] 70 str x22, [x0, #0x90] 71 str x23, [x0, #0xa0] 72 str x24, [x0, #0xb0] 73 str x25, [x0, #0xc0] 74 str x26, [x0, #0xd0] 75 str x28, [x0, #0xe0] 76 str q18, [x0, #0xf0] 77 str q19, [x0, #0x100] 78 str q20, [x0, #0x110] 79 str q21, [x0, #0x120] 80 str q22, [x0, #0x130] 81 str q23, [x0, #0x140] 82 str q24, [x0, #0x150] 83 str q25, [x0, #0x160] 84 str q26, [x0, #0x170] 85 str q27, [x0, #0x180] 86 str q28, [x0, #0x190] 87 str q29, [x0, #0x1a0] 88 str q30, [x0, #0x1b0] 89 str q31, [x0, #0x1c0] 90 str x1, [x0, #0x460] 91 sub sp, sp, #0x120 92 mov x15, sp 93 str q0, [x15], #0x10 94 str d1, [x15], #0x8 95 str q2, [x15], #0x10 96 str x2, [x15], #0x8 97 str x3, [x15], #0x8 98 str q3, [x15], #0x10 99 str d4, [x15], #0x8 100 str q5, [x15], #0x10 101 str x4, [x15], #0x8 102 str x5, [x15], #0x8 103 str q6, [x15], #0x10 104 str d7, [x15], #0x8 105 ldr q11, [x17], #0x10 106 str q11, [x15], #0x10 107 str x6, [x15], #0x8 108 str x7, [x15], #0x8 109 ldr q11, [x17], #0x10 110 str q11, [x15], #0x10 111 ldr s11, [x17], #0x8 112 str d11, [x15], #0x8 113 ldr q11, [x17], #0x10 114 str q11, [x15], #0x10 115 movz x27, #0x120, lsl 0 116 movz x16, #0x23, lsl 0 117 stp x27, x16, [sp, #-0x10]! 118 orr w17, wzr, #0xe 119 str w17, [x0] 120 mov x27, sp 121 str x27, [x0, #0x38] 122 adr x27, #0x20 123 str x27, [x0, #0x30] 124 exit_sequence x0 125 ldr x19, [x0, #0x60] 126 ldr x20, [x0, #0x70] 127 ldr x21, [x0, #0x80] 128 ldr x22, [x0, #0x90] 129 ldr x23, [x0, #0xa0] 130 ldr x24, [x0, #0xb0] 131 ldr x25, [x0, #0xc0] 132 ldr x26, [x0, #0xd0] 133 ldr x28, [x0, #0xe0] 134 ldr q18, [x0, #0xf0] 135 ldr q19, [x0, #0x100] 136 ldr q20, [x0, #0x110] 137 ldr q21, [x0, #0x120] 138 ldr q22, [x0, #0x130] 139 ldr q23, [x0, #0x140] 140 ldr q24, [x0, #0x150] 141 ldr q25, [x0, #0x160] 142 ldr q26, [x0, #0x170] 143 ldr q27, [x0, #0x180] 144 ldr q28, [x0, #0x190] 145 ldr q29, [x0, #0x1a0] 146 ldr q30, [x0, #0x1b0] 147 ldr q31, [x0, #0x1c0] 148 add x15, sp, #0x10 149 add sp, sp, #0x130 150 ldr x30, [sp], #0x10 151 add x17, sp, #0x38 152 add sp, sp, #0xa0 153 ldr q0, [x15], #0x10 154 ldr w0, [x15], #0x8 155 ldr x1, [x15], #0x8 156 ldr q1, [x15], #0x10 157 ldr s2, [x15], #0x8 158 ldr q3, [x15], #0x10 159 ldr w2, [x15], #0x8 160 ldr x3, [x15], #0x8 161 ldr q4, [x15], #0x10 162 ldr s5, [x15], #0x8 163 ldr q6, [x15], #0x10 164 ldr w4, [x15], #0x8 165 ldr x5, [x15], #0x8 166 ldr q7, [x15], #0x10 167 ldr s11, [x15], #0x8 168 str s11, [x17], #0x8 169 ldr q11, [x15], #0x10 170 str q11, [x17], #0x10 171 ldr w6, [x15], #0x8 172 ldr x7, [x15], #0x8 173 ldr q11, [x15], #0x10 174 str q11, [x17], #0x10 175 ldr s11, [x15], #0x8 176 str s11, [x17], #0x8 177 ldr q11, [x15], #0x10 178 str q11, [x17], #0x10 179 ldr w11, [x15], #0x8 180 str w11, [x17], #0x8 181 ldr x11, [x15], #0x8 182 str x11, [x17], #0x8 183 ldr q11, [x15], #0x10 184 str q11, [x17], #0x10 185 ldr s11, [x15], #0x8 186 str s11, [x17], #0x8 187 ret 188 `, 189 }, 190 { 191 name: "go call", 192 exitCode: wazevoapi.ExitCodeCallGoFunctionWithIndex(100, false), 193 sig: &ssa.Signature{ 194 Params: []ssa.Type{ssa.TypeI64, ssa.TypeI64, ssa.TypeF64}, 195 Results: []ssa.Type{ssa.TypeI32, ssa.TypeI64, ssa.TypeF32, ssa.TypeF64}, 196 }, 197 needModuleContextPtr: true, 198 exp: ` 199 stp x30, xzr, [sp, #-0x10]! 200 sub x27, sp, #0x30 201 ldr x11, [x0, #0x28] 202 subs xzr, x27, x11 203 b.ge #0x14 204 orr x27, xzr, #0x30 205 str x27, [x0, #0x40] 206 ldr x27, [x0, #0x50] 207 bl x27 208 str x19, [x0, #0x60] 209 str x20, [x0, #0x70] 210 str x21, [x0, #0x80] 211 str x22, [x0, #0x90] 212 str x23, [x0, #0xa0] 213 str x24, [x0, #0xb0] 214 str x25, [x0, #0xc0] 215 str x26, [x0, #0xd0] 216 str x28, [x0, #0xe0] 217 str q18, [x0, #0xf0] 218 str q19, [x0, #0x100] 219 str q20, [x0, #0x110] 220 str q21, [x0, #0x120] 221 str q22, [x0, #0x130] 222 str q23, [x0, #0x140] 223 str q24, [x0, #0x150] 224 str q25, [x0, #0x160] 225 str q26, [x0, #0x170] 226 str q27, [x0, #0x180] 227 str q28, [x0, #0x190] 228 str q29, [x0, #0x1a0] 229 str q30, [x0, #0x1b0] 230 str q31, [x0, #0x1c0] 231 str x1, [x0, #0x460] 232 sub sp, sp, #0x20 233 mov x15, sp 234 str d0, [x15], #0x8 235 orr x27, xzr, #0x20 236 orr x16, xzr, #0x4 237 stp x27, x16, [sp, #-0x10]! 238 movz w17, #0x6406, lsl 0 239 str w17, [x0] 240 mov x27, sp 241 str x27, [x0, #0x38] 242 adr x27, #0x20 243 str x27, [x0, #0x30] 244 exit_sequence x0 245 ldr x19, [x0, #0x60] 246 ldr x20, [x0, #0x70] 247 ldr x21, [x0, #0x80] 248 ldr x22, [x0, #0x90] 249 ldr x23, [x0, #0xa0] 250 ldr x24, [x0, #0xb0] 251 ldr x25, [x0, #0xc0] 252 ldr x26, [x0, #0xd0] 253 ldr x28, [x0, #0xe0] 254 ldr q18, [x0, #0xf0] 255 ldr q19, [x0, #0x100] 256 ldr q20, [x0, #0x110] 257 ldr q21, [x0, #0x120] 258 ldr q22, [x0, #0x130] 259 ldr q23, [x0, #0x140] 260 ldr q24, [x0, #0x150] 261 ldr q25, [x0, #0x160] 262 ldr q26, [x0, #0x170] 263 ldr q27, [x0, #0x180] 264 ldr q28, [x0, #0x190] 265 ldr q29, [x0, #0x1a0] 266 ldr q30, [x0, #0x1b0] 267 ldr q31, [x0, #0x1c0] 268 add x15, sp, #0x10 269 add sp, sp, #0x30 270 ldr x30, [sp], #0x10 271 ldr w0, [x15], #0x8 272 ldr x1, [x15], #0x8 273 ldr s0, [x15], #0x8 274 ldr d1, [x15], #0x8 275 ret 276 `, 277 }, 278 { 279 name: "go call", 280 exitCode: wazevoapi.ExitCodeCallGoFunctionWithIndex(100, false), 281 sig: &ssa.Signature{ 282 Params: []ssa.Type{ssa.TypeI64, ssa.TypeI64, ssa.TypeF64, ssa.TypeF64, ssa.TypeI32, ssa.TypeI32}, 283 Results: []ssa.Type{}, 284 }, 285 needModuleContextPtr: true, 286 exp: ` 287 stp x30, xzr, [sp, #-0x10]! 288 sub x27, sp, #0x30 289 ldr x11, [x0, #0x28] 290 subs xzr, x27, x11 291 b.ge #0x14 292 orr x27, xzr, #0x30 293 str x27, [x0, #0x40] 294 ldr x27, [x0, #0x50] 295 bl x27 296 str x19, [x0, #0x60] 297 str x20, [x0, #0x70] 298 str x21, [x0, #0x80] 299 str x22, [x0, #0x90] 300 str x23, [x0, #0xa0] 301 str x24, [x0, #0xb0] 302 str x25, [x0, #0xc0] 303 str x26, [x0, #0xd0] 304 str x28, [x0, #0xe0] 305 str q18, [x0, #0xf0] 306 str q19, [x0, #0x100] 307 str q20, [x0, #0x110] 308 str q21, [x0, #0x120] 309 str q22, [x0, #0x130] 310 str q23, [x0, #0x140] 311 str q24, [x0, #0x150] 312 str q25, [x0, #0x160] 313 str q26, [x0, #0x170] 314 str q27, [x0, #0x180] 315 str q28, [x0, #0x190] 316 str q29, [x0, #0x1a0] 317 str q30, [x0, #0x1b0] 318 str q31, [x0, #0x1c0] 319 str x1, [x0, #0x460] 320 sub sp, sp, #0x20 321 mov x15, sp 322 str d0, [x15], #0x8 323 str d1, [x15], #0x8 324 str x2, [x15], #0x8 325 str x3, [x15], #0x8 326 orr x27, xzr, #0x20 327 orr x16, xzr, #0x4 328 stp x27, x16, [sp, #-0x10]! 329 movz w17, #0x6406, lsl 0 330 str w17, [x0] 331 mov x27, sp 332 str x27, [x0, #0x38] 333 adr x27, #0x20 334 str x27, [x0, #0x30] 335 exit_sequence x0 336 ldr x19, [x0, #0x60] 337 ldr x20, [x0, #0x70] 338 ldr x21, [x0, #0x80] 339 ldr x22, [x0, #0x90] 340 ldr x23, [x0, #0xa0] 341 ldr x24, [x0, #0xb0] 342 ldr x25, [x0, #0xc0] 343 ldr x26, [x0, #0xd0] 344 ldr x28, [x0, #0xe0] 345 ldr q18, [x0, #0xf0] 346 ldr q19, [x0, #0x100] 347 ldr q20, [x0, #0x110] 348 ldr q21, [x0, #0x120] 349 ldr q22, [x0, #0x130] 350 ldr q23, [x0, #0x140] 351 ldr q24, [x0, #0x150] 352 ldr q25, [x0, #0x160] 353 ldr q26, [x0, #0x170] 354 ldr q27, [x0, #0x180] 355 ldr q28, [x0, #0x190] 356 ldr q29, [x0, #0x1a0] 357 ldr q30, [x0, #0x1b0] 358 ldr q31, [x0, #0x1c0] 359 add sp, sp, #0x30 360 ldr x30, [sp], #0x10 361 ret 362 `, 363 }, 364 { 365 name: "grow memory", 366 exitCode: wazevoapi.ExitCodeGrowMemory, 367 sig: &ssa.Signature{ 368 Params: []ssa.Type{ssa.TypeI32, ssa.TypeI32}, 369 Results: []ssa.Type{ssa.TypeI32}, 370 }, 371 exp: ` 372 stp x30, xzr, [sp, #-0x10]! 373 sub x27, sp, #0x20 374 ldr x11, [x0, #0x28] 375 subs xzr, x27, x11 376 b.ge #0x14 377 orr x27, xzr, #0x20 378 str x27, [x0, #0x40] 379 ldr x27, [x0, #0x50] 380 bl x27 381 str x19, [x0, #0x60] 382 str x20, [x0, #0x70] 383 str x21, [x0, #0x80] 384 str x22, [x0, #0x90] 385 str x23, [x0, #0xa0] 386 str x24, [x0, #0xb0] 387 str x25, [x0, #0xc0] 388 str x26, [x0, #0xd0] 389 str x28, [x0, #0xe0] 390 str q18, [x0, #0xf0] 391 str q19, [x0, #0x100] 392 str q20, [x0, #0x110] 393 str q21, [x0, #0x120] 394 str q22, [x0, #0x130] 395 str q23, [x0, #0x140] 396 str q24, [x0, #0x150] 397 str q25, [x0, #0x160] 398 str q26, [x0, #0x170] 399 str q27, [x0, #0x180] 400 str q28, [x0, #0x190] 401 str q29, [x0, #0x1a0] 402 str q30, [x0, #0x1b0] 403 str q31, [x0, #0x1c0] 404 sub sp, sp, #0x10 405 mov x15, sp 406 str x1, [x15], #0x8 407 orr x27, xzr, #0x10 408 orr x16, xzr, #0x1 409 stp x27, x16, [sp, #-0x10]! 410 orr w17, wzr, #0x2 411 str w17, [x0] 412 mov x27, sp 413 str x27, [x0, #0x38] 414 adr x27, #0x20 415 str x27, [x0, #0x30] 416 exit_sequence x0 417 ldr x19, [x0, #0x60] 418 ldr x20, [x0, #0x70] 419 ldr x21, [x0, #0x80] 420 ldr x22, [x0, #0x90] 421 ldr x23, [x0, #0xa0] 422 ldr x24, [x0, #0xb0] 423 ldr x25, [x0, #0xc0] 424 ldr x26, [x0, #0xd0] 425 ldr x28, [x0, #0xe0] 426 ldr q18, [x0, #0xf0] 427 ldr q19, [x0, #0x100] 428 ldr q20, [x0, #0x110] 429 ldr q21, [x0, #0x120] 430 ldr q22, [x0, #0x130] 431 ldr q23, [x0, #0x140] 432 ldr q24, [x0, #0x150] 433 ldr q25, [x0, #0x160] 434 ldr q26, [x0, #0x170] 435 ldr q27, [x0, #0x180] 436 ldr q28, [x0, #0x190] 437 ldr q29, [x0, #0x1a0] 438 ldr q30, [x0, #0x1b0] 439 ldr q31, [x0, #0x1c0] 440 add x15, sp, #0x10 441 add sp, sp, #0x20 442 ldr x30, [sp], #0x10 443 ldr w0, [x15], #0x8 444 ret 445 `, 446 }, 447 } { 448 t.Run(tc.name, func(t *testing.T) { 449 _, _, m := newSetupWithMockContext() 450 m.CompileGoFunctionTrampoline(tc.exitCode, tc.sig, tc.needModuleContextPtr) 451 452 require.Equal(t, tc.exp, m.Format()) 453 454 err := m.Encode(context.Background()) 455 require.NoError(t, err) 456 }) 457 } 458 } 459 460 func Test_goFunctionCallLoadStackArg(t *testing.T) { 461 originalArg0Reg := x17VReg 462 intVReg := x11VReg 463 floatVReg := v11VReg 464 for _, tc := range []struct { 465 name string 466 arg *backend.ABIArg 467 expResultReg regalloc.VReg 468 exp string 469 }{ 470 { 471 name: "i32", 472 arg: &backend.ABIArg{Type: ssa.TypeI32}, 473 expResultReg: x11VReg, 474 exp: ` 475 ldr w11, [x17], #0x8 476 `, 477 }, 478 { 479 name: "i64", 480 arg: &backend.ABIArg{Type: ssa.TypeI64}, 481 expResultReg: x11VReg, 482 exp: ` 483 ldr x11, [x17], #0x8 484 `, 485 }, 486 { 487 name: "f32", 488 arg: &backend.ABIArg{Type: ssa.TypeF32}, 489 expResultReg: v11VReg, 490 exp: ` 491 ldr s11, [x17], #0x8 492 `, 493 }, 494 { 495 name: "f64", 496 arg: &backend.ABIArg{Type: ssa.TypeF64}, 497 expResultReg: v11VReg, 498 exp: ` 499 ldr d11, [x17], #0x8 500 `, 501 }, 502 { 503 name: "v128", 504 arg: &backend.ABIArg{Type: ssa.TypeV128}, 505 expResultReg: v11VReg, 506 exp: ` 507 ldr q11, [x17], #0x10 508 `, 509 }, 510 } { 511 tc := tc 512 t.Run(tc.name, func(t *testing.T) { 513 t.Run(tc.name, func(t *testing.T) { 514 _, _, m := newSetupWithMockContext() 515 516 nop := m.allocateNop() 517 _, result := m.goFunctionCallLoadStackArg(nop, originalArg0Reg, tc.arg, intVReg, floatVReg) 518 require.Equal(t, tc.expResultReg, result) 519 520 m.executableContext.RootInstr = nop 521 522 require.Equal(t, tc.exp, m.Format()) 523 err := m.Encode(context.Background()) 524 require.NoError(t, err) 525 }) 526 }) 527 } 528 } 529 530 func Test_goFunctionCallStoreStackResult(t *testing.T) { 531 for _, tc := range []struct { 532 name string 533 result *backend.ABIArg 534 resultReg regalloc.VReg 535 exp string 536 }{ 537 { 538 name: "i32", 539 result: &backend.ABIArg{Offset: 16 * 3, Type: ssa.TypeI32}, 540 resultReg: x11VReg, 541 exp: ` 542 str w11, [sp], #0x8 543 `, 544 }, 545 { 546 name: "i64", 547 result: &backend.ABIArg{Offset: 16 * 3, Type: ssa.TypeI64}, 548 resultReg: x11VReg, 549 exp: ` 550 str x11, [sp], #0x8 551 `, 552 }, 553 { 554 name: "f32", 555 result: &backend.ABIArg{Offset: 16 * 3, Type: ssa.TypeF32}, 556 resultReg: v11VReg, 557 exp: ` 558 str s11, [sp], #0x8 559 `, 560 }, 561 { 562 name: "f64", 563 result: &backend.ABIArg{Offset: 16 * 3, Type: ssa.TypeF64}, 564 resultReg: v11VReg, 565 exp: ` 566 str d11, [sp], #0x8 567 `, 568 }, 569 { 570 name: "v128", 571 result: &backend.ABIArg{Offset: 16 * 3, Type: ssa.TypeV128}, 572 resultReg: v11VReg, 573 exp: ` 574 str q11, [sp], #0x10 575 `, 576 }, 577 } { 578 tc := tc 579 t.Run(tc.name, func(t *testing.T) { 580 t.Run(tc.name, func(t *testing.T) { 581 _, _, m := newSetupWithMockContext() 582 m.currentABI = &backend.FunctionABI{ArgStackSize: 8} 583 584 nop := m.allocateNop() 585 m.goFunctionCallStoreStackResult(nop, spVReg, tc.result, tc.resultReg) 586 587 m.executableContext.RootInstr = nop 588 589 require.Equal(t, tc.exp, m.Format()) 590 err := m.Encode(context.Background()) 591 require.NoError(t, err) 592 }) 593 }) 594 } 595 }