1# Copyright (c) 2021-2022 Huawei Device Co., Ltd. 2# Licensed under the Apache License, Version 2.0 (the "License"); 3# you may not use this file except in compliance with the License. 4# You may obtain a copy of the License at 5# 6# http://www.apache.org/licenses/LICENSE-2.0 7# 8# Unless required by applicable law or agreed to in writing, software 9# distributed under the License is distributed on an "AS IS" BASIS, 10# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11# See the License for the specific language governing permissions and 12# limitations under the License. 13 14# 15# Checked tests for basic inlining. 16# 17 18#! CHECKER Instructions limit 19#! RUN force_jit: true, options: "--compiler-regex=Test1::main --compiler-inlining-max-insts=8", entry: "Test1::main" 20#! EVENT /Inline,Test1::main,_GLOBAL::func,.*STATIC,LIMIT/ 21#! EVENT_NEXT /Inline,Test1::main,_GLOBAL::small_func,.*STATIC,SUCCESS/ 22 23#! CHECKER Instructions max size 24#! RUN force_jit: true, options: "--compiler-regex=Test1::main --compiler-inlining-max-size=6", entry: "Test1::main" 25#! EVENT /Inline,Test1::main,_GLOBAL::func,.*STATIC,LIMIT/ 26#! EVENT_NEXT /Inline,Test1::main,_GLOBAL::small_func,.*STATIC,SUCCESS/ 27 28.record Test1 {} 29 30.function i32 func(i32 a0) { 31 newobj v0, Test1 32 newobj v0, Test1 33 ldai 1 34 add2 a0 35 return 36} 37 38.function i32 small_func(i32 a0) { 39 ldai 1 40 add2 a0 41 return 42} 43 44.function i32 Test1.main() { 45 movi v1, 10 46 47 call.short func, v1 48 call.short small_func, v1 49 add2 v1 50 51 ldai 0 52 return 53} 54 55#! CHECKER Inline depth limit 56#! RUN force_jit: true, options: "--compiler-regex=Test1::main_depth --compiler-inlining-max-depth=2", entry: "Test1::main_depth" 57#! EVENTS_COUNT /Inline,Test1::main_depth,_GLOBAL::func_rec,.*STATIC,SUCCESS/, 1 58#! EVENTS_COUNT /Inline,_GLOBAL::func_rec,_GLOBAL::func_rec,.*STATIC,SUCCESS/, 1 59 60.function i32 func_rec(i32 a0) { 61 lda a0 62 jeqz exit 63 subi 1 64 sta a0 65 call.short func_rec, a0 66exit: 67 return 68} 69 70.function i32 Test1.main_depth() { 71 movi v1, 10 72 73 call.short func_rec, v1 74 75 return 76} 77 78#! CHECKER Check inlined float array 79#! RUN force_jit: true, options: "--compiler-regex=_GLOBAL::main", entry: "_GLOBAL::main" 80#! EVENT /Inline,_GLOBAL::main,_GLOBAL::farray,.*STATIC,SUCCESS/ 81#! METHOD "_GLOBAL::main" 82#! PASS_AFTER "Inline" 83#! INST "CallStatic.Inlined" 84 85.function void farray(f64[] a0) { 86 ldai 2 87 movi v0, 1 88 fstarr.64 a0, v0 89 return.void 90} 91 92.function i32 main() { 93 movi v0, 5 94 newarr v1, v0, f64[] 95 call.short farray, v1 96 ldai 0 97 return 98} 99 100#! CHECKER Inline function with dead loop 101#! RUN force_jit: true, options: "--compiler-regex=_GLOBAL::main1", entry: "_GLOBAL::main1" 102#! EVENT /Inline,_GLOBAL::main1,_GLOBAL::foo1,.*STATIC,SUCCESS/ 103#! METHOD "_GLOBAL::main1" 104#! PASS_AFTER "Inline" 105#! INST_NOT "CallStatic.Inlined" 106#! INST_NOT "Return.Inlined" 107#! INST_NOT "SaveStateDeoptimize" 108 109.function i32 foo1() { 110 movi v1, 0 111 ldai 10 112lbl: 113 jle v1, lbl # jump to 0 offset, never happens 114 ldai 0 115 return 116} 117 118.function i32 main1() { 119 call foo1 120 return 121} 122 123 124#! CHECKER Change to CallStatic by instructions limit 125#! RUN force_jit: true, options: "--compiler-regex=Test2::main --compiler-inlining-max-insts=12", entry: "Test2::main" 126#! EVENT /Inline,Test2::main,Test2::func,.*VIRTUAL,LIMIT/ 127#! EVENT_NEXT /Inline,Test2::main,Test2::func,.*VIRTUAL,DEVIRTUALIZED/ 128#! EVENT_NEXT /Inline,Test2::main,Test2::small_func,.*VIRTUAL,SUCCESS/ 129 130#! CHECKER Change to CallStatic by instructions max size 131#! RUN force_jit: true, options: "--compiler-regex=Test2::main --compiler-inlining-max-size=6", entry: "Test2::main" 132#! EVENT /Inline,Test2::main,Test2::func,.*VIRTUAL,LIMIT/ 133#! EVENT_NEXT /Inline,Test2::main,Test2::func,.*VIRTUAL,DEVIRTUALIZED/ 134#! EVENT_NEXT /Inline,Test2::main,Test2::small_func,.*VIRTUAL,SUCCESS/ 135 136.record Test2 {} 137 138.function i32 Test2.func(Test2 a0, i32 a1) { 139 newobj v0, Test1 140 newobj v0, Test1 141 newobj v0, Test1 142 newobj v0, Test1 143 ldai 1 144 add2 a1 145 return 146} 147 148.function i32 Test2.small_func(Test2 a0, i32 a1) { 149 ldai 1 150 add2 a1 151 return 152} 153 154.function i32 Test2.main() { 155 newobj v0, Test2 156 movi v1, 10 157 158 call.virt Test2.func, v0, v1 159 call.virt Test2.small_func, v0, v1 160 add2 v1 161 162 ldai 0 163 return 164} 165 166#! CHECKER Do not inline infinite loop 167#! RUN force_jit: true, entry: "Test3::main" 168#! EVENT /Inline,Test3::main,Test3::foo1,.*VIRTUAL,SUCCESS/ 169#! EVENT /Inline,Test3::main,_GLOBAL::foo_inf_loop,.*STATIC,INF_LOOP/ 170 171 172.record Test3 {} 173 174.function i32 Test3.foo1(Test3 a0) { 175 ldai 0 176 return 177} 178 179.function i32 foo_inf_loop(i32 a0) { 180 lda a0 181 jeqz exit 182loop: 183 addi 1 184 sta a0 185 jmp loop 186exit: 187 return 188} 189 190.function i32 Test3.main() { 191 newobj v0, Test3 192 call.virt Test3.foo1, v0 193 jeqz exit 194 sta v1 195 call.short foo_inf_loop, v1 196 ldai 0 197exit: 198 return 199} 200 201#! CHECKER Inline external files in AOT mode 202#! RUN_PAOC options: "--panda-files=../../inline_external.checked/test.abc --compiler-regex=Test4.*" 203#! METHOD "Test4::func_A_getConst_static__noinline__" 204#! PASS_AFTER "IrBuilder" 205#! INST /CallStatic.*A::getConst/ 206#! INST_NOT "Constant" 207#! PASS_AFTER "Inline" 208#! INST_NOT /CallStatic.*A::getConst/ 209#! INST "Constant" 210#! METHOD "Test4::func_A_getConst_virtual__noinline__" 211#! PASS_AFTER "IrBuilder" 212#! INST /CallVirtual.*A::getConst/ 213#! INST_NOT "Constant" 214#! PASS_AFTER "Inline" 215#! INST_NOT /CallVirtual.*A::getConst/ 216#! INST "Constant" 217#! METHOD "Test4::func_A_getParam_static__noinline__" 218#! PASS_AFTER "IrBuilder" 219#! INST /CallStatic.*A::getParam/ 220#! PASS_AFTER "Inline" 221#! INST_NOT /CallStatic.*A::getParam/ 222#! METHOD "Test4::func_A_getParam_virtual__noinline__" 223#! PASS_AFTER "IrBuilder" 224#! INST /CallVirtual.*A::getParam/ 225#! PASS_AFTER "Inline" 226#! INST_NOT /CallVirtual.*A::getParam/ 227#! METHOD "Test4::func_A_getVoid_static__noinline__" 228#! PASS_AFTER "IrBuilder" 229#! INST /CallStatic.*A::getVoid/ 230#! PASS_AFTER "Inline" 231#! INST_NOT /CallStatic.*A::getVoid/ 232#! METHOD "Test4::func_A_getVoid_virtual__noinline__" 233#! PASS_AFTER "IrBuilder" 234#! INST /CallVirtual.*A::getVoid/ 235#! PASS_AFTER "Inline" 236#! INST_NOT /CallVirtual.*A::getVoid/ 237#! METHOD "Test4::func_A_getObj_static__noinline__" 238#! PASS_AFTER "IrBuilder" 239#! INST /CallStatic.*A::getObj/ 240#! INST_NOT "LoadObject" 241#! PASS_AFTER "Inline" 242#! INST_NOT /CallStatic.*A::getObj/ 243#! INST "LoadObject" 244#! METHOD "Test4::func_A_getObj_virtual__noinline__" 245#! PASS_AFTER "IrBuilder" 246#! INST /CallVirtual.*A::getObj/ 247#! INST_NOT "LoadObject" 248#! PASS_AFTER "Inline" 249#! INST_NOT /CallVirtual.*A::getObj/ 250#! INST "LoadObject" 251#! METHOD "Test4::func_A_setObj_static__noinline__" 252#! PASS_AFTER "IrBuilder" 253#! INST /CallStatic.*A::setObj/ 254#! INST_NOT "StoreObject" 255#! PASS_AFTER "Inline" 256#! INST_NOT /CallStatic.*A::setObj/ 257#! INST "StoreObject" 258#! METHOD "Test4::func_A_setObj_virtual__noinline__" 259#! PASS_AFTER "IrBuilder" 260#! INST /CallVirtual.*A::setObj/ 261#! INST_NOT "StoreObject" 262#! PASS_AFTER "Inline" 263#! INST_NOT /CallVirtual.*A::setObj/ 264#! INST "StoreObject" 265#! METHOD "Test4::func_A_getObj_wrong_virtual__noinline__" 266#! PASS_AFTER "IrBuilder" 267#! INST /CallVirtual.*A::getObj/ 268#! INST_NOT "LoadObject" 269#! PASS_AFTER "Inline" 270#! INST_NOT /CallVirtual.*A::getObj/ 271#! INST "LoadObject" 272#! METHOD "Test4::func_A_setObj_wrong_virtual__noinline__" 273#! PASS_AFTER "IrBuilder" 274#! INST /CallVirtual.*A::setObj/ 275#! INST_NOT "StoreObject" 276#! PASS_AFTER "Inline" 277#! INST_NOT /CallVirtual.*A::setObj/ 278#! INST "StoreObject" 279#! METHOD "Test4::func_A_setObj_multiple__noinline__" 280#! PASS_AFTER "IrBuilder" 281#! INST /CallStatic.*A::setObj_multiple/ 282#! PASS_AFTER "Inline" 283#! INST_NOT /CallStatic.*A::setObj_multiple/ 284#! METHOD "Test4::func_A_complexMethod__noinline__" 285#! PASS_AFTER "IrBuilder" 286#! INST /CallVirtual.*A::complexMethod/ 287#! PASS_AFTER "Inline" 288#! INST_NOT /CallVirtual.*A::complexMethod/ 289#! METHOD "Test4::func_A_setObj_unknown_target__noinline__" 290#! PASS_AFTER "IrBuilder" 291#! INST /CallStatic.*A::setObj/ 292#! PASS_AFTER "Inline" 293#! INST /CallStatic.*A::setObj/ 294#! RUN options: "--panda-files=../../inline_external.checked/test.abc", entry: "Test4::main" 295 296#! CHECKER Don't inline external files in AOT mode without cha 297#! RUN_PAOC options: "--panda-files=../../inline_external.checked/test.abc --paoc-use-cha=false --compiler-regex=Test4.*" 298#! METHOD "Test4::func_A_getConst_static__noinline__" 299#! PASS_AFTER "IrBuilder" 300#! INST /CallStatic.*A::getConst/ 301#! INST_NOT "Constant" 302#! PASS_AFTER "Inline" 303#! INST /CallStatic.*A::getConst/ 304#! INST_NOT "Constant" 305 306.record A { 307 i32 data <external> 308} 309.record A.data <external> 310.function i32 A.getConst() <external,static> 311.function i32 A.getConst_virt(A a0) <external> 312.function i32 A.getParam(i32 a0) <external,static> 313.function i32 A.getParam_virt(A a0, i32 a1) <external> 314.function void A.getVoid() <external,static> 315.function void A.getVoid_virt(A a0) <external> 316.function i32 A.getObj(A a0) <external,static> 317.function i32 A.getObj_virt(A a0) <external> 318.function void A.setObj(A a0, i32 a1) <external,static> 319.function void A.setObjConst_virt(A a0) <external> 320.function void A.setObj_virt(A a0, i32 a1) <external> 321.function i32 A.getObj_wrong_virt(A a0, A a1) <external> 322.function void A.setObj_wrong_virt(A a0, i32 a1, A a2) <external> 323.function void A.setObj_multiple(A a0, i32 a1, i32 a2) <external,static> 324.function i32 A.complexMethod(A a0) <external> 325 326.record Test4 {} 327 328.function i32 Test4.func_A_getConst_static__noinline__() <static> { 329 call A.getConst 330 return 331} 332 333.function i32 Test4.func_A_getConst_virtual__noinline__() <static> { 334 newobj v0, A 335 call.virt A.getConst_virt, v0 336 return 337} 338 339.function i32 Test4.func_A_getParam_static__noinline__(i32 a0) <static> { 340 call A.getParam, a0 341 return 342} 343 344.function i32 Test4.func_A_getParam_virtual__noinline__(i32 a0) <static> { 345 newobj v0, A 346 call.virt A.getParam_virt, v0, a0 347 return 348} 349 350.function void Test4.func_A_getVoid_static__noinline__() <static> { 351 call A.getVoid 352 return.void 353} 354 355.function void Test4.func_A_getVoid_virtual__noinline__() <static> { 356 newobj v0, A 357 call.virt A.getVoid_virt, v0 358 return.void 359} 360 361.function i32 Test4.func_A_getObj_static__noinline__() <static> { 362 newobj v0, A 363 ldai 0x5 364 stobj v0, A.data 365 call A.getObj, v0 366 return 367} 368 369.function i32 Test4.func_A_getObj_virtual__noinline__() <static> { 370 newobj v0, A 371 ldai 0x6 372 stobj v0, A.data 373 call.virt A.getObj_virt, v0 374 return 375} 376 377.function i32 Test4.func_A_setObj_static__noinline__() <static> { 378 newobj v0, A 379 movi v1, 0x7 380 call A.setObj, v0, v1 381 ldobj v0, A.data 382 return 383} 384 385.function i32 Test4.func_A_setObj_virtual__noinline__() <static> { 386 newobj v0, A 387 movi v1, 0x8 388 call.virt A.setObj_virt, v0, v1 389 ldobj v0, A.data 390 return 391} 392 393.function i32 Test4.func_A_getObj_wrong_virtual__noinline__() <static> { 394 newobj v0, A 395 newobj v1, A 396 ldai 0x9 397 stobj v0, A.data 398 ldai 0x10 399 stobj v1, A.data 400 call.virt A.getObj_wrong_virt, v0, v1 401 return 402} 403 404.function i32 Test4.func_A_setObj_wrong_virtual__noinline__() <static> { 405 newobj v0, A 406 newobj v2, A 407 movi v1, 0x11 408 call.virt A.setObj_wrong_virt, v0, v1, v2 409 ldobj v2, A.data 410 return 411} 412 413.function i32 Test4.func_A_setObjConst_virtual__noinline__() <static> { 414 newobj v0, A 415 call.virt A.setObjConst_virt, v0 416 ldobj v0, A.data 417 return 418} 419 420.function i32 Test4.func_A_setObj_multiple__noinline__() <static> { 421 newobj v0, A 422 movi v1, 42 423 movi v2, 0 424 call A.setObj_multiple, v0, v1, v2 425 ldobj v0, A.data 426 return 427} 428 429.function i32 Test4.func_A_complexMethod__noinline__() <static> { 430 newobj v0, A 431 call.virt A.complexMethod, v0 432 sta v0 433 ldai 42 434 jeq v0, success 435 ldai 1 436 return 437success: 438 ldai 0 439 return 440} 441 442.function i32 Test4.func_A_setObj_unknown_target__noinline__(A a0) <static> { 443 movi v0, 0 444 call A.setObj, a0, v0 445 ldobj a0, A.data 446 return 447} 448 449.function i32 Test4.func_A_setObj_unknown_target_wrapper__noinline__() <static> { 450 newobj v0, A 451 call Test4.func_A_setObj_unknown_target__noinline__, v0 452 return 453} 454 455.function i32 Test4.main() { 456 movi v0, 0x1 457 call Test4.func_A_getConst_static__noinline__ 458 jne v0, error_exit_1 459 movi v0, 0x2 460 call Test4.func_A_getConst_virtual__noinline__ 461 jne v0, error_exit_2 462 movi v0, 0x3 463 call Test4.func_A_getParam_static__noinline__, v0 464 jne v0, error_exit_3 465 movi v0, 0x4 466 call Test4.func_A_getParam_virtual__noinline__, v0 467 jne v0, error_exit_4 468 call Test4.func_A_getVoid_static__noinline__, v0 469 call Test4.func_A_getVoid_virtual__noinline__, v0 470 movi v0, 0x5 471 call Test4.func_A_getObj_static__noinline__ 472 jne v0, error_exit_5 473 movi v0, 0x6 474 call Test4.func_A_getObj_virtual__noinline__ 475 jne v0, error_exit_6 476 movi v0, 0x7 477 call Test4.func_A_setObj_static__noinline__ 478 jne v0, error_exit_7 479 movi v0, 0x8 480 call Test4.func_A_setObj_virtual__noinline__ 481 jne v0, error_exit_8 482 movi v0, 0x9 483 call Test4.func_A_setObjConst_virtual__noinline__ 484 jne v0, error_exit_9 485 movi v0, 0x10 486 call Test4.func_A_getObj_wrong_virtual__noinline__ 487 jne v0, error_exit_10 488 movi v0, 0x11 489 call Test4.func_A_setObj_wrong_virtual__noinline__ 490 jne v0, error_exit_11 491 call Test4.func_A_setObj_multiple__noinline__ 492 jnez error_exit_12 493 call Test4.func_A_complexMethod__noinline__ 494 jnez error_exit_13 495 call Test4.func_A_setObj_unknown_target_wrapper__noinline__ 496 jnez error_exit_14 497 ldai 0x0 498 return 499error_exit_1: 500 ldai 0x1 501 return 502error_exit_2: 503 ldai 0x2 504error_exit_3: 505 ldai 0x3 506 return 507error_exit_4: 508 ldai 0x4 509 return 510error_exit_5: 511 ldai 0x5 512 return 513error_exit_6: 514 ldai 0x6 515 return 516error_exit_7: 517 ldai 0x7 518 return 519error_exit_8: 520 ldai 0x8 521 return 522error_exit_9: 523 ldai 0x9 524 return 525error_exit_10: 526 ldai 0xa 527 return 528error_exit_11: 529 ldai 0xb 530 return 531error_exit_12: 532 ldai 0xc 533 return 534error_exit_13: 535 ldai 0xd 536 return 537error_exit_14: 538 ldai 0xe 539 return 540} 541 542#! CHECKER Inline nested calls in AOT mode 543#! RUN_PAOC options: "--panda-files=../../inline.checked/test.abc --compiler-regex=NestedCalls::main" 544#! EVENT /Inline,NestedCalls::outer,NestedCalls::inner,.*,VIRTUAL,SUCCESS/ 545#! EVENT /Inline,NestedCalls::main,NestedCalls::outer,.*,VIRTUAL,SUCCESS/ 546 547#! CHECKER Inline nested calls in JIT mode 548#! RUN force_jit: true, entry: "NestedCalls::main", options: "--compiler-regex=NestedCalls::main --compiler-no-cha-inlining" 549#! EVENT /Inline,NestedCalls::outer,NestedCalls::inner,.*,VIRTUAL,SUCCESS/ 550#! EVENT /Inline,NestedCalls::main,NestedCalls::outer,.*,VIRTUAL,SUCCESS/ 551.record NestedCalls {} 552.function i32 NestedCalls.outer(NestedCalls a0) { 553 call.virt NestedCalls.inner, a0 554 return 555} 556.function i32 NestedCalls.inner(NestedCalls a0) { 557 ldai 0 558 return 559} 560.function i32 NestedCalls.main() <static> { 561 newobj v0, NestedCalls 562 call.virt NestedCalls.outer, v0 563 return 564}