| -- Test cases for "flag elimination" optimization. Used to optimize away |
| -- registers that are always used immediately after assignment as branch conditions. |
| |
| [case testFlagEliminationSimple] |
| def c() -> bool: |
| return True |
| def d() -> bool: |
| return True |
| |
| def f(x: bool) -> int: |
| if x: |
| b = c() |
| else: |
| b = d() |
| if b: |
| return 1 |
| else: |
| return 2 |
| [out] |
| def c(): |
| L0: |
| return 1 |
| def d(): |
| L0: |
| return 1 |
| def f(x): |
| x, r0, r1 :: bool |
| L0: |
| if x goto L1 else goto L2 :: bool |
| L1: |
| r0 = c() |
| if r0 goto L3 else goto L4 :: bool |
| L2: |
| r1 = d() |
| if r1 goto L3 else goto L4 :: bool |
| L3: |
| return 2 |
| L4: |
| return 4 |
| |
| [case testFlagEliminationOneAssignment] |
| def c() -> bool: |
| return True |
| |
| def f(x: bool) -> int: |
| # Not applied here |
| b = c() |
| if b: |
| return 1 |
| else: |
| return 2 |
| [out] |
| def c(): |
| L0: |
| return 1 |
| def f(x): |
| x, r0, b :: bool |
| L0: |
| r0 = c() |
| b = r0 |
| if b goto L1 else goto L2 :: bool |
| L1: |
| return 2 |
| L2: |
| return 4 |
| |
| [case testFlagEliminationThreeCases] |
| def c(x: int) -> bool: |
| return True |
| |
| def f(x: bool, y: bool) -> int: |
| if x: |
| b = c(1) |
| elif y: |
| b = c(2) |
| else: |
| b = c(3) |
| if b: |
| return 1 |
| else: |
| return 2 |
| [out] |
| def c(x): |
| x :: int |
| L0: |
| return 1 |
| def f(x, y): |
| x, y, r0, r1, r2 :: bool |
| L0: |
| if x goto L1 else goto L2 :: bool |
| L1: |
| r0 = c(2) |
| if r0 goto L5 else goto L6 :: bool |
| L2: |
| if y goto L3 else goto L4 :: bool |
| L3: |
| r1 = c(4) |
| if r1 goto L5 else goto L6 :: bool |
| L4: |
| r2 = c(6) |
| if r2 goto L5 else goto L6 :: bool |
| L5: |
| return 2 |
| L6: |
| return 4 |
| |
| [case testFlagEliminationAssignmentNotLastOp] |
| def f(x: bool) -> int: |
| y = 0 |
| if x: |
| b = True |
| y = 1 |
| else: |
| b = False |
| if b: |
| return 1 |
| else: |
| return 2 |
| [out] |
| def f(x): |
| x :: bool |
| y :: int |
| b :: bool |
| L0: |
| y = 0 |
| if x goto L1 else goto L2 :: bool |
| L1: |
| b = 1 |
| y = 2 |
| goto L3 |
| L2: |
| b = 0 |
| L3: |
| if b goto L4 else goto L5 :: bool |
| L4: |
| return 2 |
| L5: |
| return 4 |
| |
| [case testFlagEliminationAssignmentNoDirectGoto] |
| def f(x: bool) -> int: |
| if x: |
| b = True |
| else: |
| b = False |
| if x: |
| if b: |
| return 1 |
| else: |
| return 2 |
| return 4 |
| [out] |
| def f(x): |
| x, b :: bool |
| L0: |
| if x goto L1 else goto L2 :: bool |
| L1: |
| b = 1 |
| goto L3 |
| L2: |
| b = 0 |
| L3: |
| if x goto L4 else goto L7 :: bool |
| L4: |
| if b goto L5 else goto L6 :: bool |
| L5: |
| return 2 |
| L6: |
| return 4 |
| L7: |
| return 8 |
| |
| [case testFlagEliminationBranchNotNextOpAfterGoto] |
| def f(x: bool) -> int: |
| if x: |
| b = True |
| else: |
| b = False |
| y = 1 # Prevents the optimization |
| if b: |
| return 1 |
| else: |
| return 2 |
| [out] |
| def f(x): |
| x, b :: bool |
| y :: int |
| L0: |
| if x goto L1 else goto L2 :: bool |
| L1: |
| b = 1 |
| goto L3 |
| L2: |
| b = 0 |
| L3: |
| y = 2 |
| if b goto L4 else goto L5 :: bool |
| L4: |
| return 2 |
| L5: |
| return 4 |
| |
| [case testFlagEliminationFlagReadTwice] |
| def f(x: bool) -> bool: |
| if x: |
| b = True |
| else: |
| b = False |
| if b: |
| return b # Prevents the optimization |
| else: |
| return False |
| [out] |
| def f(x): |
| x, b :: bool |
| L0: |
| if x goto L1 else goto L2 :: bool |
| L1: |
| b = 1 |
| goto L3 |
| L2: |
| b = 0 |
| L3: |
| if b goto L4 else goto L5 :: bool |
| L4: |
| return b |
| L5: |
| return 0 |
| |
| [case testFlagEliminationArgumentNotEligible] |
| def f(x: bool, b: bool) -> bool: |
| if x: |
| b = True |
| else: |
| b = False |
| if b: |
| return True |
| else: |
| return False |
| [out] |
| def f(x, b): |
| x, b :: bool |
| L0: |
| if x goto L1 else goto L2 :: bool |
| L1: |
| b = 1 |
| goto L3 |
| L2: |
| b = 0 |
| L3: |
| if b goto L4 else goto L5 :: bool |
| L4: |
| return 1 |
| L5: |
| return 0 |
| |
| [case testFlagEliminationFlagNotAlwaysDefined] |
| def f(x: bool, y: bool) -> bool: |
| if x: |
| b = True |
| elif y: |
| b = False |
| else: |
| bb = False # b not assigned here -> can't optimize |
| if b: |
| return True |
| else: |
| return False |
| [out] |
| def f(x, y): |
| x, y, r0, b, bb, r1 :: bool |
| L0: |
| r0 = <error> :: bool |
| b = r0 |
| if x goto L1 else goto L2 :: bool |
| L1: |
| b = 1 |
| goto L5 |
| L2: |
| if y goto L3 else goto L4 :: bool |
| L3: |
| b = 0 |
| goto L5 |
| L4: |
| bb = 0 |
| L5: |
| if is_error(b) goto L6 else goto L7 |
| L6: |
| r1 = raise UnboundLocalError('local variable "b" referenced before assignment') |
| unreachable |
| L7: |
| if b goto L8 else goto L9 :: bool |
| L8: |
| return 1 |
| L9: |
| return 0 |