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