|
2 | 2 |
|
3 | 3 | from tests.venom_utils import PrePostChecker
|
4 | 4 | from vyper.exceptions import StaticAssertionException
|
| 5 | +from vyper.venom.analysis.analysis import IRAnalysesCache |
5 | 6 | from vyper.venom.basicblock import IRVariable
|
| 7 | +from vyper.venom.parser import parse_venom |
6 | 8 | from vyper.venom.passes import SCCP
|
7 | 9 | from vyper.venom.passes.sccp.sccp import LatticeEnum
|
8 | 10 |
|
@@ -278,6 +280,75 @@ def test_cont_phi_const_case():
|
278 | 280 | assert sccp.lattice[IRVariable("%5:2")] == LatticeEnum.TOP
|
279 | 281 |
|
280 | 282 |
|
| 283 | +def test_sccp_phi_operand_top_no_branch(): |
| 284 | + """ |
| 285 | + control jumps directly to a join block where a phi depends on predecessors |
| 286 | + that haven't been executed yet. The phi is TOP at first, and hhe arithmetic |
| 287 | + using it must defer evaluation. |
| 288 | + """ |
| 289 | + # NOTE: `main` goes straight to `@join`, yet the phi still lists `@then` |
| 290 | + # and `@else` as inputs. This intentionally mimics malformed IR seen in |
| 291 | + # programs where the CFG includes those predecessors even though |
| 292 | + # execution never reaches them (and will be prunned by a later pass). |
| 293 | + # So here we show that can SCCP gracefully treat the phi inputs |
| 294 | + # as TOP until (and unless) those blocks are actually visited. Decoupling |
| 295 | + # essentially the CGF from the SCCP. |
| 296 | + pre = """ |
| 297 | + main: |
| 298 | + jmp @join |
| 299 | + then: |
| 300 | + %a_then = 2 |
| 301 | + jmp @join |
| 302 | + else: |
| 303 | + %a_else = 3 |
| 304 | + jmp @join |
| 305 | + join: |
| 306 | + %phi = phi @then, %a_then, @else, %a_else |
| 307 | + %out = sub 14, %phi |
| 308 | + sink %out |
| 309 | + """ |
| 310 | + |
| 311 | + _check_pre_post(pre, pre, hevm=False) |
| 312 | + |
| 313 | + |
| 314 | +def test_sccp_jnz_top_phi_text_ir(): |
| 315 | + """ |
| 316 | + Same as above but using the value to control a jnz. |
| 317 | + This used to assert in SCCP when the jnz condition was TOP. |
| 318 | + """ |
| 319 | + # NOTE: `main` goes straight to `@join`, yet the phi still lists `@then` |
| 320 | + # and `@else` as inputs. This intentionally mimics malformed IR seen in |
| 321 | + # programs where the CFG includes those predecessors even though |
| 322 | + # execution never reaches them (and will be prunned by a later pass). |
| 323 | + # So here we show that can SCCP gracefully treat the phi inputs |
| 324 | + # as TOP until (and unless) those blocks are actually visited. Decoupling |
| 325 | + # essentially the CGF from the SCCP. |
| 326 | + src = """ |
| 327 | + function main { |
| 328 | + main: |
| 329 | + jmp @join |
| 330 | + then: |
| 331 | + %a_then = 2 |
| 332 | + jmp @join |
| 333 | + else: |
| 334 | + %a_else = 3 |
| 335 | + jmp @join |
| 336 | + join: |
| 337 | + %phi = phi @then, %a_then, @else, %a_else |
| 338 | + jnz %phi, @true, @false |
| 339 | + true: |
| 340 | + sink 1 |
| 341 | + false: |
| 342 | + sink 2 |
| 343 | + } |
| 344 | + """ |
| 345 | + |
| 346 | + ctx = parse_venom(src) |
| 347 | + fn = ctx.get_function(next(iter(ctx.functions.keys()))) |
| 348 | + ac = IRAnalysesCache(fn) |
| 349 | + SCCP(ac, fn).run_pass() |
| 350 | + |
| 351 | + |
281 | 352 | def test_phi_reduction_without_basic_block_removal():
|
282 | 353 | """
|
283 | 354 | Test of phi reduction `if` end not `if-else`
|
@@ -307,3 +378,30 @@ def test_phi_reduction_without_basic_block_removal():
|
307 | 378 | """
|
308 | 379 |
|
309 | 380 | _check_pre_post(pre, post)
|
| 381 | + |
| 382 | + |
| 383 | +inst = ["mload", "sload", "dload", "iload", "calldataload", "param"] |
| 384 | + |
| 385 | + |
| 386 | +@pytest.mark.parametrize("inst", inst) |
| 387 | +def test_mload_schedules_uses(inst): |
| 388 | + pre = f""" |
| 389 | + main: |
| 390 | + %cond = param |
| 391 | + jnz %cond, @B, @A |
| 392 | + A: |
| 393 | + %m = {inst} 0 |
| 394 | + jmp @join |
| 395 | + B: |
| 396 | + %x = assign %m |
| 397 | + jmp @join |
| 398 | + join: |
| 399 | + sink %x |
| 400 | + """ |
| 401 | + |
| 402 | + passes = _check_pre_post(pre, pre, hevm=False) |
| 403 | + sccp = passes[0] |
| 404 | + assert isinstance(sccp, SCCP) |
| 405 | + |
| 406 | + assert sccp.lattice[IRVariable("%m")] == LatticeEnum.BOTTOM |
| 407 | + assert sccp.lattice[IRVariable("%x")] == LatticeEnum.BOTTOM |
0 commit comments